Repository: theCheeseboard/thedesk Branch: master Commit: 5c8c5d85e967 Files: 1428 Total size: 16.4 MB Directory structure: gitextract_ocparz4t/ ├── .gitignore ├── .parlance.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── desktop/ │ ├── CMakeLists.txt │ ├── acknowledgements.html │ ├── background/ │ │ ├── background.cpp │ │ ├── background.h │ │ └── background.ui │ ├── bar/ │ │ ├── barwindow.cpp │ │ ├── barwindow.h │ │ ├── barwindow.ui │ │ ├── chunkcontainer.cpp │ │ ├── chunkcontainer.h │ │ ├── chunkcontainer.ui │ │ ├── currentappwidget.cpp │ │ ├── currentappwidget.h │ │ ├── currentappwidget.ui │ │ ├── currentappwidgetmenu.cpp │ │ ├── currentappwidgetmenu.h │ │ ├── currentappwidgetmenu.ui │ │ ├── mainbarwidget.cpp │ │ ├── mainbarwidget.h │ │ ├── mainbarwidget.ui │ │ ├── taskbarapplicationwidget.cpp │ │ ├── taskbarapplicationwidget.h │ │ ├── taskbardesktopwidget.cpp │ │ ├── taskbardesktopwidget.h │ │ ├── taskbardesktopwidget.ui │ │ ├── taskbarwidget.cpp │ │ ├── taskbarwidget.h │ │ └── taskbarwidget.ui │ ├── cli/ │ │ ├── commandline.cpp │ │ └── commandline.h │ ├── common/ │ │ ├── common.cpp │ │ └── common.h │ ├── crash/ │ │ ├── crashhandling.cpp │ │ └── crashhandling.h │ ├── desktop.pro │ ├── gateway/ │ │ ├── appsearchprovider.cpp │ │ ├── appsearchprovider.h │ │ ├── appselectionmodel.cpp │ │ ├── appselectionmodel.h │ │ ├── appselectionmodellistdelegate.cpp │ │ ├── appselectionmodellistdelegate.h │ │ ├── gateway.cpp │ │ ├── gateway.h │ │ ├── gateway.ui │ │ ├── gatewaysearchmodel.cpp │ │ ├── gatewaysearchmodel.h │ │ ├── gatewaysearchmodeldelegate.cpp │ │ ├── gatewaysearchmodeldelegate.h │ │ ├── maingatewaywidget.cpp │ │ ├── maingatewaywidget.h │ │ ├── maingatewaywidget.ui │ │ ├── searchresultswidget.cpp │ │ ├── searchresultswidget.h │ │ └── searchresultswidget.ui │ ├── main.cpp │ ├── media/ │ │ ├── intro.ogg │ │ ├── loop.ogg │ │ ├── welcome1.webm │ │ ├── welcome2.webm │ │ └── welcome3.webm │ ├── resources.qrc │ ├── run/ │ │ ├── rundialog.cpp │ │ ├── rundialog.h │ │ └── rundialog.ui │ ├── session/ │ │ ├── endsession.cpp │ │ ├── endsession.h │ │ ├── endsession.ui │ │ ├── endsessionbutton.cpp │ │ └── endsessionbutton.h │ ├── statuscenter/ │ │ ├── leftpanedelegate.cpp │ │ ├── leftpanedelegate.h │ │ ├── statuscenter.cpp │ │ ├── statuscenter.h │ │ ├── statuscenter.ui │ │ ├── statuscenterleftpane.cpp │ │ ├── statuscenterleftpane.h │ │ ├── statuscenterleftpane.ui │ │ ├── statuscenterquickswitch.cpp │ │ ├── statuscenterquickswitch.h │ │ └── statuscenterquickswitch.ui │ ├── systemsettings/ │ │ ├── about/ │ │ │ ├── about.cpp │ │ │ ├── about.h │ │ │ ├── about.ui │ │ │ ├── acknowledgements.cpp │ │ │ ├── acknowledgements.h │ │ │ ├── acknowledgements.ui │ │ │ ├── changehostnamepopover.cpp │ │ │ ├── changehostnamepopover.h │ │ │ └── changehostnamepopover.ui │ │ ├── pluginmanagement/ │ │ │ ├── managepluginpopover.cpp │ │ │ ├── managepluginpopover.h │ │ │ ├── managepluginpopover.ui │ │ │ ├── pluginitemdelegate.cpp │ │ │ ├── pluginitemdelegate.h │ │ │ ├── pluginmanagement.cpp │ │ │ ├── pluginmanagement.h │ │ │ ├── pluginmanagement.ui │ │ │ ├── pluginmodel.cpp │ │ │ └── pluginmodel.h │ │ ├── recovery/ │ │ │ ├── recovery.cpp │ │ │ ├── recovery.h │ │ │ └── recovery.ui │ │ ├── systemsettings.cpp │ │ ├── systemsettings.h │ │ ├── systemsettings.ui │ │ ├── systemsettingsleftpane.cpp │ │ ├── systemsettingsleftpane.h │ │ └── systemsettingsleftpane.ui │ ├── thedesk.conf │ └── translations/ │ ├── ar_SA.ts │ ├── au_AU.qm │ ├── au_AU.ts │ ├── cy.qm │ ├── cy.ts │ ├── da.qm │ ├── da.ts │ ├── de.qm │ ├── de.ts │ ├── en_AU.qm │ ├── en_AU.ts │ ├── en_CA.qm │ ├── en_CA.ts │ ├── en_GB.qm │ ├── en_GB.ts │ ├── en_NZ.qm │ ├── en_NZ.ts │ ├── en_US.qm │ ├── en_US.ts │ ├── es.ts │ ├── es_VE.ts │ ├── fr_FR.qm │ ├── fr_FR.ts │ ├── id_ID.qm │ ├── id_ID.ts │ ├── ja.qm │ ├── ja.ts │ ├── nl.qm │ ├── nl.ts │ ├── pl_PL.qm │ ├── pl_PL.ts │ ├── pt_BR.qm │ ├── pt_BR.ts │ ├── ro_RO.qm │ ├── ro_RO.ts │ ├── sv.qm │ ├── sv.ts │ ├── tr_TR.qm │ ├── tr_TR.ts │ ├── vi_VN.qm │ ├── vi_VN.ts │ ├── zh_CN.qm │ └── zh_CN.ts ├── desktop-portal/ │ ├── CMakeLists.txt │ ├── backend/ │ │ ├── abstractportalbackend.cpp │ │ ├── abstractportalbackend.h │ │ ├── private/ │ │ │ ├── waylandportalscreencopyframe.cpp │ │ │ └── waylandportalscreencopyframe.h │ │ ├── waylandportalbackend.cpp │ │ ├── waylandportalbackend.h │ │ ├── wlr-screencopy-unstable-v1.xml │ │ ├── x11portalbackend.cpp │ │ └── x11portalbackend.h │ ├── desktop-portal.pro │ ├── dialogs/ │ │ ├── accessdialog.cpp │ │ ├── accessdialog.h │ │ ├── accessdialog.ui │ │ ├── accountdialog.cpp │ │ ├── accountdialog.h │ │ ├── accountdialog.ui │ │ ├── filedialog.cpp │ │ ├── filedialog.h │ │ ├── filedialog.ui │ │ ├── penbutton.cpp │ │ ├── penbutton.h │ │ ├── screenshotwindow.cpp │ │ ├── screenshotwindow.h │ │ └── screenshotwindow.ui │ ├── interfaces/ │ │ ├── accessinterface.cpp │ │ ├── accessinterface.h │ │ ├── accountinterface.cpp │ │ ├── accountinterface.h │ │ ├── filechooserinterface.cpp │ │ ├── filechooserinterface.h │ │ ├── notificationinterface.cpp │ │ ├── notificationinterface.h │ │ ├── screenshotinterface.cpp │ │ ├── screenshotinterface.h │ │ ├── settingsinterface.cpp │ │ └── settingsinterface.h │ ├── main.cpp │ ├── org.freedesktop.impl.portal.desktop.thedesk.service.in │ ├── portalcommon.cpp │ ├── portalcommon.h │ ├── portalhandle.cpp │ ├── portalhandle.h │ ├── screenshot_resources.qrc │ ├── screenshotmanager.cpp │ ├── screenshotmanager.h │ ├── thedesk-portals.conf │ ├── thedesk.portal │ ├── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── vi.qm │ │ └── vi.ts │ └── xdg-desktop-portal-thedesk.service.in ├── dist/ │ ├── thedesk-blueprint.spec │ └── thedesk.spec ├── libthedesk/ │ ├── CMakeLists.txt │ ├── actionquickwidget.cpp │ ├── actionquickwidget.h │ ├── actionquickwidget.ui │ ├── barmanager.cpp │ ├── barmanager.h │ ├── chunk.cpp │ ├── chunk.h │ ├── common.cpp │ ├── common.h │ ├── gatewaymanager.cpp │ ├── gatewaymanager.h │ ├── gatewaysearchprovider.cpp │ ├── gatewaysearchprovider.h │ ├── hudmanager.cpp │ ├── hudmanager.h │ ├── icontextchunk.cpp │ ├── icontextchunk.h │ ├── icontextchunk.ui │ ├── keygrab.cpp │ ├── keygrab.h │ ├── libthedesk.pro │ ├── libthedeskConfig.cmake.in │ ├── libthedesk_global.h │ ├── libthedesk_resources.qrc │ ├── localemanager.cpp │ ├── localemanager.h │ ├── onboarding/ │ │ ├── OnboardingVideoForm.qml │ │ ├── onboarding.cpp │ │ ├── onboarding.h │ │ ├── onboarding.ui │ │ ├── onboardingbar.cpp │ │ ├── onboardingbar.h │ │ ├── onboardingbar.ui │ │ ├── onboardingbetathankyou.cpp │ │ ├── onboardingbetathankyou.h │ │ ├── onboardingbetathankyou.ui │ │ ├── onboardingcontroller.cpp │ │ ├── onboardingcontroller.h │ │ ├── onboardingfinal.cpp │ │ ├── onboardingfinal.h │ │ ├── onboardingfinal.ui │ │ ├── onboardingstepper.cpp │ │ ├── onboardingstepper.h │ │ ├── onboardingvideo.cpp │ │ ├── onboardingvideo.h │ │ ├── onboardingvideo.ui │ │ ├── onboardingwelcome.cpp │ │ ├── onboardingwelcome.h │ │ └── onboardingwelcome.ui │ ├── onboardingmanager.cpp │ ├── onboardingmanager.h │ ├── onboardingpage.cpp │ ├── onboardingpage.h │ ├── plugins/ │ │ ├── plugininterface.h │ │ ├── pluginmanager.cpp │ │ └── pluginmanager.h │ ├── powermanager.cpp │ ├── powermanager.h │ ├── private/ │ │ ├── keyboardlayoutmodel.cpp │ │ ├── keyboardlayoutmodel.h │ │ ├── keyboardlayoutselector.cpp │ │ ├── keyboardlayoutselector.h │ │ ├── keyboardlayoutselector.ui │ │ ├── localeselector.cpp │ │ ├── localeselector.h │ │ ├── localeselector.ui │ │ ├── onboardingmanager_p.h │ │ ├── quickwidgetcontainer.cpp │ │ ├── quickwidgetcontainer.h │ │ └── quickwidgetcontainer.ui │ ├── quickswitch.cpp │ ├── quickswitch.h │ ├── quietmodemanager.cpp │ ├── quietmodemanager.h │ ├── server/ │ │ ├── sessionserver.cpp │ │ └── sessionserver.h │ ├── statemanager.cpp │ ├── statemanager.h │ ├── statuscentermanager.cpp │ ├── statuscentermanager.h │ ├── statuscenterpane.cpp │ ├── statuscenterpane.h │ ├── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cs_CZ.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pl_PL.qm │ │ ├── pl_PL.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sl_SI.qm │ │ ├── sl_SI.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ └── zh_CN.ts │ ├── transparentdialog.cpp │ ├── transparentdialog.h │ └── transparentdialog.ui ├── locker/ │ ├── CMakeLists.txt │ ├── locker-checker/ │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── locker-common/ │ │ ├── CMakeLists.txt │ │ ├── lockergrabs.cpp │ │ └── lockergrabs.h │ └── locker-ui/ │ ├── CMakeLists.txt │ ├── lockmanager.cpp │ ├── lockmanager.h │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── translations/ │ │ └── en_US.ts │ ├── underlineanimation.cpp │ └── underlineanimation.h ├── platform/ │ ├── CMakeLists.txt │ ├── cursorhandler.cpp │ ├── cursorhandler.h │ ├── fontformat.cpp │ ├── fontformat.h │ ├── iconloaderengine.cpp │ ├── iconloaderengine.h │ ├── messagedialog/ │ │ ├── messagedialog.cpp │ │ ├── messagedialog.h │ │ ├── messagedialog.ui │ │ ├── messagedialogcontroller.cpp │ │ ├── messagedialogcontroller.h │ │ ├── messagedialoghelper.cpp │ │ └── messagedialoghelper.h │ ├── paletteformat.cpp │ ├── paletteformat.h │ ├── palettes.json │ ├── platform.pro │ ├── platformtheme.cpp │ ├── platformtheme.h │ ├── plugin.cpp │ ├── plugin.h │ ├── plugin.json │ ├── psAMLQ.json │ ├── thedesk-platform-resources.qrc │ ├── thedesk-platform.conf │ └── translations/ │ ├── ar_SA.ts │ ├── au_AU.qm │ ├── au_AU.ts │ ├── cy.qm │ ├── cy.ts │ ├── da.qm │ ├── da.ts │ ├── de.qm │ ├── de.ts │ ├── en_GB.qm │ ├── en_GB.ts │ ├── en_US.qm │ ├── en_US.ts │ ├── es.ts │ ├── es_VE.ts │ ├── id.ts │ ├── nl.qm │ ├── nl.ts │ ├── pt_BR.qm │ ├── pt_BR.ts │ ├── ro_RO.qm │ ├── ro_RO.ts │ ├── sv.qm │ ├── sv.ts │ ├── tr_TR.qm │ ├── tr_TR.ts │ ├── vi.qm │ ├── vi.ts │ └── vi_VN.ts ├── plugins/ │ ├── AccessibilityPlugin/ │ │ ├── AccessibilityPlugin.pro │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── accessibilitydaemon.cpp │ │ ├── accessibilitydaemon.h │ │ ├── chunks/ │ │ │ ├── stickykeyschunk.cpp │ │ │ └── stickykeyschunk.h │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── settings/ │ │ │ ├── accessibilitysettingspane.cpp │ │ │ ├── accessibilitysettingspane.h │ │ │ └── accessibilitysettingspane.ui │ │ ├── thedesk-accessibility.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── ja.qm │ │ ├── ja.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro.qm │ │ ├── ro.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr.qm │ │ ├── tr.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ └── vi_VN.ts │ ├── AudioPlugin/ │ │ ├── AudioPlugin.pro │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── audiochunk.cpp │ │ ├── audiochunk.h │ │ ├── audioquickwidget.cpp │ │ ├── audioquickwidget.h │ │ ├── audioquickwidget.ui │ │ ├── common.cpp │ │ ├── common.h │ │ ├── eventhandler.cpp │ │ ├── eventhandler.h │ │ ├── micchunk.cpp │ │ ├── micchunk.h │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── quickwidgetsink.cpp │ │ ├── quickwidgetsink.h │ │ ├── quickwidgetsink.ui │ │ ├── quickwidgetsinkinput.cpp │ │ ├── quickwidgetsinkinput.h │ │ ├── quickwidgetsinkinput.ui │ │ ├── thedesk-audio.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── ja.qm │ │ ├── ja.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ ├── zh_CN.ts │ │ ├── zu_ZA.qm │ │ └── zu_ZA.ts │ ├── BluetoothPlugin/ │ │ ├── BluetoothPlugin.pro │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── bluetoothplugincommon.cpp │ │ ├── bluetoothplugincommon.h │ │ ├── btagent.cpp │ │ ├── btagent.h │ │ ├── btobex.cpp │ │ ├── btobex.h │ │ ├── chunk/ │ │ │ ├── bluetoothchunk.cpp │ │ │ └── bluetoothchunk.h │ │ ├── defaults.json │ │ ├── devicedelegate.cpp │ │ ├── devicedelegate.h │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── settings/ │ │ │ ├── bluetoothsettingspane.cpp │ │ │ ├── bluetoothsettingspane.h │ │ │ ├── bluetoothsettingspane.ui │ │ │ ├── devicepopover.cpp │ │ │ ├── devicepopover.h │ │ │ ├── devicepopover.ui │ │ │ ├── pairpopover.cpp │ │ │ ├── pairpopover.h │ │ │ └── pairpopover.ui │ │ ├── thedesk-bluetooth.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro.qm │ │ ├── ro.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr.qm │ │ ├── tr.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ └── vi_VN.ts │ ├── BrightnessPlugin/ │ │ ├── BrightnessPlugin.pro │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── screenbrightnesschunk.cpp │ │ ├── screenbrightnesschunk.h │ │ ├── screenbrightnesschunk.ui │ │ ├── thedesk-brightness.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id_ID.qm │ │ ├── id_ID.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pl_PL.qm │ │ ├── pl_PL.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sk_SK.qm │ │ ├── sk_SK.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ ├── zh_CN.ts │ │ ├── zh_SG.qm │ │ ├── zh_SG.ts │ │ ├── zu_ZA.qm │ │ └── zu_ZA.ts │ ├── CMakeLists.txt │ ├── DefaultsPlugin/ │ │ ├── CMakeLists.txt │ │ ├── DefaultsPlugin.pro │ │ ├── Plugin.json │ │ ├── defaultspane.cpp │ │ ├── defaultspane.h │ │ ├── defaultspane.ui │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── thedesk-defaults.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro.qm │ │ ├── ro.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr.qm │ │ ├── tr.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ └── vi_VN.ts │ ├── DisplayPlugin/ │ │ ├── CMakeLists.txt │ │ ├── DisplayPlugin.pro │ │ ├── Plugin.json │ │ ├── arrange/ │ │ │ ├── arrangecontroller.cpp │ │ │ ├── arrangecontroller.h │ │ │ ├── arrangewidget.cpp │ │ │ ├── arrangewidget.h │ │ │ ├── arrangewidget.ui │ │ │ ├── overlaywindow.cpp │ │ │ ├── overlaywindow.h │ │ │ ├── overlaywindow.ui │ │ │ ├── screenarranger.cpp │ │ │ └── screenarranger.h │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── redshift/ │ │ │ ├── colorramp.cpp │ │ │ ├── colorramp.h │ │ │ ├── redshiftdaemon.cpp │ │ │ └── redshiftdaemon.h │ │ ├── settings/ │ │ │ ├── displaysettings.cpp │ │ │ ├── displaysettings.h │ │ │ └── displaysettings.ui │ │ ├── thedesk-display.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ └── zh_CN.ts │ ├── InputPlugin/ │ │ ├── CMakeLists.txt │ │ ├── InputPlugin.pro │ │ ├── Plugin.json │ │ ├── backends/ │ │ │ ├── settingsbackend.cpp │ │ │ ├── settingsbackend.h │ │ │ ├── xinputbackend.cpp │ │ │ └── xinputbackend.h │ │ ├── chunks/ │ │ │ ├── keyboardlayoutchunk.cpp │ │ │ ├── keyboardlayoutchunk.h │ │ │ └── keyboardlayoutchunk.ui │ │ ├── daemons/ │ │ │ ├── keyboarddaemon.cpp │ │ │ └── keyboarddaemon.h │ │ ├── models/ │ │ │ ├── selectedkeyboardlayoutsmodel.cpp │ │ │ └── selectedkeyboardlayoutsmodel.h │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── settings/ │ │ │ ├── inputsettingsleftpane.cpp │ │ │ ├── inputsettingsleftpane.h │ │ │ ├── inputsettingsleftpane.ui │ │ │ ├── inputsettingspane.cpp │ │ │ ├── inputsettingspane.h │ │ │ ├── inputsettingspane.ui │ │ │ ├── keyboardsettings.cpp │ │ │ ├── keyboardsettings.h │ │ │ ├── keyboardsettings.ui │ │ │ ├── mousesettings.cpp │ │ │ ├── mousesettings.h │ │ │ └── mousesettings.ui │ │ ├── thedesk-input.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro.qm │ │ ├── ro.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr.qm │ │ ├── tr.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ └── vi_VN.ts │ ├── LocalePlugin/ │ │ ├── CMakeLists.txt │ │ ├── LocalePlugin.pro │ │ ├── Plugin.json │ │ ├── localeplugincommon.cpp │ │ ├── localeplugincommon.h │ │ ├── onboarding/ │ │ │ ├── onboardingregion.cpp │ │ │ ├── onboardingregion.h │ │ │ └── onboardingregion.ui │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── settings/ │ │ │ ├── localesettingspane.cpp │ │ │ ├── localesettingspane.h │ │ │ └── localesettingspane.ui │ │ ├── thedesk-locale.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ ├── zh_CN.ts │ │ ├── zu_ZA.qm │ │ └── zu_ZA.ts │ ├── NetworkPlugin/ │ │ ├── CMakeLists.txt │ │ ├── NetworkPlugin.pro │ │ ├── Plugin.json │ │ ├── chunk/ │ │ │ ├── chunkupdater.cpp │ │ │ ├── chunkupdater.h │ │ │ ├── genericchunkupdater.cpp │ │ │ ├── genericchunkupdater.h │ │ │ ├── networkchunk.cpp │ │ │ ├── networkchunk.h │ │ │ ├── wiredchunkupdater.cpp │ │ │ ├── wiredchunkupdater.h │ │ │ ├── wirelesschunkupdater.cpp │ │ │ └── wirelesschunkupdater.h │ │ ├── models/ │ │ │ ├── deviceconnectionlistmodel.cpp │ │ │ ├── deviceconnectionlistmodel.h │ │ │ ├── wirelessaccesspointsmodel.cpp │ │ │ ├── wirelessaccesspointsmodel.h │ │ │ ├── wirelessconnectionlistmodel.cpp │ │ │ ├── wirelessconnectionlistmodel.h │ │ │ ├── wirelessnetworklistdelegate.cpp │ │ │ └── wirelessnetworklistdelegate.h │ │ ├── networkplugincommon.cpp │ │ ├── networkplugincommon.h │ │ ├── onboarding/ │ │ │ ├── onboardingnetwork.cpp │ │ │ ├── onboardingnetwork.h │ │ │ ├── onboardingnetwork.ui │ │ │ ├── wiredonboardingsetup.cpp │ │ │ ├── wiredonboardingsetup.h │ │ │ ├── wiredonboardingsetup.ui │ │ │ ├── wirelessonboardingsetup.cpp │ │ │ ├── wirelessonboardingsetup.h │ │ │ └── wirelessonboardingsetup.ui │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── statusCenter/ │ │ │ ├── connectionEditor/ │ │ │ │ ├── connectioneditorpane.cpp │ │ │ │ ├── connectioneditorpane.h │ │ │ │ ├── ipv4connectioneditorpane.cpp │ │ │ │ ├── ipv4connectioneditorpane.h │ │ │ │ ├── ipv4connectioneditorpane.ui │ │ │ │ ├── networkconnectioneditor.cpp │ │ │ │ ├── networkconnectioneditor.h │ │ │ │ ├── networkconnectioneditor.ui │ │ │ │ ├── wificonnectioneditorpane.cpp │ │ │ │ ├── wificonnectioneditorpane.h │ │ │ │ └── wificonnectioneditorpane.ui │ │ │ ├── devicePanes/ │ │ │ │ ├── abstractdevicepane.cpp │ │ │ │ ├── abstractdevicepane.h │ │ │ │ ├── cellularpane.cpp │ │ │ │ ├── cellularpane.h │ │ │ │ ├── cellularpane.ui │ │ │ │ ├── devicepane.cpp │ │ │ │ ├── devicepane.h │ │ │ │ ├── devicepane.ui │ │ │ │ ├── wifidevicepane.cpp │ │ │ │ ├── wifidevicepane.h │ │ │ │ ├── wifidevicepane.ui │ │ │ │ ├── wireddevicepane.cpp │ │ │ │ ├── wireddevicepane.h │ │ │ │ └── wireddevicepane.ui │ │ │ ├── eap/ │ │ │ │ ├── securityeap.cpp │ │ │ │ ├── securityeap.h │ │ │ │ ├── securityeappeap.cpp │ │ │ │ ├── securityeappeap.h │ │ │ │ ├── securityeappeap.ui │ │ │ │ ├── securityeapunsupported.cpp │ │ │ │ ├── securityeapunsupported.h │ │ │ │ └── securityeapunsupported.ui │ │ │ ├── networkstatuscenterleftpane.cpp │ │ │ ├── networkstatuscenterleftpane.h │ │ │ ├── networkstatuscenterleftpane.ui │ │ │ ├── networkstatuscenterpane.cpp │ │ │ ├── networkstatuscenterpane.h │ │ │ ├── networkstatuscenterpane.ui │ │ │ └── popovers/ │ │ │ ├── connectionselectionpopover.cpp │ │ │ ├── connectionselectionpopover.h │ │ │ ├── connectionselectionpopover.ui │ │ │ ├── simsettingspopover.cpp │ │ │ ├── simsettingspopover.h │ │ │ ├── simsettingspopover.ui │ │ │ ├── tetheringsettingspopover.cpp │ │ │ ├── tetheringsettingspopover.h │ │ │ ├── tetheringsettingspopover.ui │ │ │ ├── unlockmodempopover.cpp │ │ │ ├── unlockmodempopover.h │ │ │ ├── unlockmodempopover.ui │ │ │ ├── wirelessnetworkselectionpopover.cpp │ │ │ ├── wirelessnetworkselectionpopover.h │ │ │ └── wirelessnetworkselectionpopover.ui │ │ ├── switchmanager.cpp │ │ ├── switchmanager.h │ │ ├── thedesk-network.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro.qm │ │ ├── ro.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ └── zh_CN.ts │ ├── NotificationsPlugin/ │ │ ├── CMakeLists.txt │ │ ├── NotificationsPlugin.pro │ │ ├── Plugin.json │ │ ├── chunks/ │ │ │ ├── mprischunk.cpp │ │ │ ├── mprischunk.h │ │ │ └── mprischunk.ui │ │ ├── dbus/ │ │ │ ├── notifications_adaptor.cpp │ │ │ ├── notifications_adaptor.h │ │ │ ├── notificationsinterface.cpp │ │ │ ├── notificationsinterface.h │ │ │ └── org.freedesktop.Notifications.xml │ │ ├── drawer/ │ │ │ ├── hudwidget.cpp │ │ │ ├── hudwidget.h │ │ │ ├── hudwidget.ui │ │ │ ├── notificationsdrawer.cpp │ │ │ ├── notificationsdrawer.h │ │ │ ├── notificationsdrawer.ui │ │ │ ├── notificationsdrawerwidget.cpp │ │ │ ├── notificationsdrawerwidget.h │ │ │ └── notificationsdrawerwidget.ui │ │ ├── notification.cpp │ │ ├── notification.h │ │ ├── notificationtracker.cpp │ │ ├── notificationtracker.h │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── statuscenter/ │ │ │ ├── jobwidget.cpp │ │ │ ├── jobwidget.h │ │ │ ├── jobwidget.ui │ │ │ ├── notificationappgroup.cpp │ │ │ ├── notificationappgroup.h │ │ │ ├── notificationappgroup.ui │ │ │ ├── notificationsstatuscenterpane.cpp │ │ │ ├── notificationsstatuscenterpane.h │ │ │ ├── notificationsstatuscenterpane.ui │ │ │ ├── notificationwidget.cpp │ │ │ ├── notificationwidget.h │ │ │ └── notificationwidget.ui │ │ ├── thedesk-notifications.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ └── zh_CN.ts │ ├── OverviewPlugin/ │ │ ├── CMakeLists.txt │ │ ├── OverviewPane/ │ │ │ ├── overviewpane.cpp │ │ │ ├── overviewpane.h │ │ │ ├── overviewpane.ui │ │ │ ├── worldclock.cpp │ │ │ ├── worldclock.h │ │ │ └── worldclock.ui │ │ ├── OverviewPlugin.pro │ │ ├── Plugin.json │ │ ├── clockchunk.cpp │ │ ├── clockchunk.h │ │ ├── clockchunk.ui │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sk_SK.qm │ │ ├── sk_SK.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ ├── zh_CN.ts │ │ ├── zu_ZA.qm │ │ └── zu_ZA.ts │ ├── PowerPlugin/ │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── PowerPlugin.pro │ │ ├── eventhandler.cpp │ │ ├── eventhandler.h │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── settings/ │ │ │ ├── powersettings.cpp │ │ │ ├── powersettings.h │ │ │ └── powersettings.ui │ │ ├── sleepmonitor.cpp │ │ ├── sleepmonitor.h │ │ ├── thedesk-power.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id_ID.qm │ │ ├── id_ID.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ └── zh_CN.ts │ ├── ScreenshotPlugin/ │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── ScreenshotPlugin.pro │ │ ├── eventhandler.cpp │ │ ├── eventhandler.h │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── thedesk-screenshot.conf │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ └── zh_CN.ts │ ├── ThemePlugin/ │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── ThemePlugin.pro │ │ ├── onboarding/ │ │ │ ├── onboardingtheme.cpp │ │ │ ├── onboardingtheme.h │ │ │ └── onboardingtheme.ui │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── settings/ │ │ │ ├── accentcolourpicker.cpp │ │ │ ├── accentcolourpicker.h │ │ │ ├── themesettingspane.cpp │ │ │ ├── themesettingspane.h │ │ │ └── themesettingspane.ui │ │ ├── thedesk-theme.conf │ │ ├── thedesk-themeplugin-resources.qrc │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id_ID.qm │ │ ├── id_ID.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro.qm │ │ ├── ro.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ └── zh_CN.ts │ ├── TimeDatePlugin/ │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── TimeDatePlugin.pro │ │ ├── onboarding/ │ │ │ ├── onboardingtimezone.cpp │ │ │ ├── onboardingtimezone.h │ │ │ └── onboardingtimezone.ui │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── popovers/ │ │ │ ├── settimedatepopover.cpp │ │ │ ├── settimedatepopover.h │ │ │ ├── settimedatepopover.ui │ │ │ ├── settimezonepopover.cpp │ │ │ ├── settimezonepopover.h │ │ │ └── settimezonepopover.ui │ │ ├── settings/ │ │ │ ├── datetimepane.cpp │ │ │ ├── datetimepane.h │ │ │ └── datetimepane.ui │ │ ├── thedesk-timedate.conf │ │ ├── timezonesmodel.cpp │ │ ├── timezonesmodel.h │ │ └── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro.qm │ │ ├── ro.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr.qm │ │ ├── tr.ts │ │ ├── vi.qm │ │ ├── vi.ts │ │ └── vi_VN.ts │ ├── UsersPlugin/ │ │ ├── CMakeLists.txt │ │ ├── Plugin.json │ │ ├── UsersPlugin.pro │ │ ├── onboarding/ │ │ │ ├── onboardingusers.cpp │ │ │ ├── onboardingusers.h │ │ │ └── onboardingusers.ui │ │ ├── plugin.cpp │ │ ├── plugin.h │ │ ├── settings/ │ │ │ ├── adduserdialog.cpp │ │ │ ├── adduserdialog.h │ │ │ ├── adduserdialog.ui │ │ │ ├── changepassworddialog.cpp │ │ │ ├── changepassworddialog.h │ │ │ ├── changepassworddialog.ui │ │ │ ├── changerealnamedialog.cpp │ │ │ ├── changerealnamedialog.h │ │ │ ├── changerealnamedialog.ui │ │ │ ├── deleteuserdialog.cpp │ │ │ ├── deleteuserdialog.h │ │ │ ├── deleteuserdialog.ui │ │ │ ├── lockuserdialog.cpp │ │ │ ├── lockuserdialog.h │ │ │ ├── lockuserdialog.ui │ │ │ ├── user.cpp │ │ │ ├── user.h │ │ │ ├── usersmodel.cpp │ │ │ ├── usersmodel.h │ │ │ ├── userspane.cpp │ │ │ ├── userspane.h │ │ │ ├── userspane.ui │ │ │ ├── usertypedialog.cpp │ │ │ ├── usertypedialog.h │ │ │ └── usertypedialog.ui │ │ ├── thedesk-users.conf │ │ └── translations/ │ │ ├── ar_SA.qm │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id_ID.qm │ │ ├── id_ID.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro.qm │ │ ├── ro.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ └── zh_CN.ts │ ├── plugins.pri │ └── plugins.pro ├── polkitagent/ │ ├── CMakeLists.txt │ ├── authwindow.cpp │ ├── authwindow.h │ ├── authwindow.ui │ ├── common.cpp │ ├── common.h │ ├── identitypopover.cpp │ ├── identitypopover.h │ ├── identitypopover.ui │ ├── main.cpp │ ├── polkitagent.pro │ ├── polkitinterface.cpp │ ├── polkitinterface.h │ └── translations/ │ ├── ar_SA.ts │ ├── au_AU.qm │ ├── au_AU.ts │ ├── cy.qm │ ├── cy.ts │ ├── da.qm │ ├── da.ts │ ├── de.qm │ ├── de.ts │ ├── en_GB.qm │ ├── en_GB.ts │ ├── en_US.qm │ ├── en_US.ts │ ├── es.ts │ ├── es_VE.ts │ ├── id.ts │ ├── nl.qm │ ├── nl.ts │ ├── pt_BR.qm │ ├── pt_BR.ts │ ├── ro_RO.qm │ ├── ro_RO.ts │ ├── sv.qm │ ├── sv.ts │ ├── tr_TR.qm │ ├── tr_TR.ts │ ├── vi_VN.qm │ ├── vi_VN.ts │ ├── zh_CN.qm │ ├── zh_CN.ts │ ├── zu_ZA.qm │ └── zu_ZA.ts ├── startdesk/ │ ├── CMakeLists.txt │ ├── crash/ │ │ ├── backtracedialog.cpp │ │ ├── backtracedialog.h │ │ ├── backtracedialog.ui │ │ ├── backtracepopover.cpp │ │ ├── backtracepopover.h │ │ ├── backtracepopover.ui │ │ ├── backtracewidget.cpp │ │ ├── backtracewidget.h │ │ ├── backtracewidget.ui │ │ ├── crashwidget.cpp │ │ ├── crashwidget.h │ │ └── crashwidget.ui │ ├── main.cpp │ ├── resources.qrc │ ├── splash/ │ │ ├── splashcontroller.cpp │ │ ├── splashcontroller.h │ │ ├── splashwidget.cpp │ │ ├── splashwidget.h │ │ └── splashwidget.ui │ ├── splashwindow.cpp │ ├── splashwindow.h │ ├── splashwindow.ui │ ├── start-thedesk-wayland.in │ ├── startdesk.pro │ ├── thedesk-wayland.desktop.in │ ├── thedesk.desktop.in │ ├── translations/ │ │ ├── ar_SA.ts │ │ ├── au_AU.qm │ │ ├── au_AU.ts │ │ ├── cy.qm │ │ ├── cy.ts │ │ ├── da.qm │ │ ├── da.ts │ │ ├── de.qm │ │ ├── de.ts │ │ ├── en_GB.qm │ │ ├── en_GB.ts │ │ ├── en_US.qm │ │ ├── en_US.ts │ │ ├── es.ts │ │ ├── es_VE.ts │ │ ├── id.ts │ │ ├── nl.qm │ │ ├── nl.ts │ │ ├── pl_PL.qm │ │ ├── pl_PL.ts │ │ ├── pt_BR.qm │ │ ├── pt_BR.ts │ │ ├── ro_RO.qm │ │ ├── ro_RO.ts │ │ ├── sv.qm │ │ ├── sv.ts │ │ ├── tr_TR.qm │ │ ├── tr_TR.ts │ │ ├── vi_VN.qm │ │ ├── vi_VN.ts │ │ ├── zh_CN.qm │ │ ├── zh_CN.ts │ │ ├── zu_ZA.qm │ │ └── zu_ZA.ts │ └── wayfire-thedesk-config.conf ├── theDesk.pro └── wayfire-plugins/ ├── CMakeLists.txt ├── a11y-plugin/ │ ├── CMakeLists.txt │ ├── a11yplugin.cpp │ ├── a11yplugin.h │ ├── abstracta11ycontroller.cpp │ ├── abstracta11ycontroller.h │ ├── mousekeys.cpp │ ├── mousekeys.h │ ├── stickykeys.cpp │ └── stickykeys.h ├── keygrab-plugin/ │ ├── CMakeLists.txt │ ├── keygrab-plugin.pro │ ├── keygrab-plugin_global.h │ ├── keygrabplugin.cpp │ └── keygrabplugin.h ├── plugins.pri ├── startdesk-plugin/ │ ├── CMakeLists.txt │ ├── startdesk-plugin.pro │ ├── startdeskplugin.cpp │ └── startdeskplugin.h └── wayfire-plugins.pro ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ theDesk.pro.user ================================================ FILE: .parlance.json ================================================ { "name": "theDesk", "subprojects": [ { "name": "libthedesk", "type": "qt", "path": "/libthedesk/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Desktop", "type": "qt", "path": "/desktop/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Platform", "type": "qt", "path": "/platform/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Session Manager", "type": "qt", "path": "/startdesk/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Polkit", "type": "qt", "path": "/polkitagent/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Accessibility", "type": "qt", "path": "/plugins/AccessibilityPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Audio", "type": "qt", "path": "/plugins/AudioPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Bluetooth", "type": "qt", "path": "/plugins/BluetoothPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Brightness", "type": "qt", "path": "/plugins/BrightnessPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Defaults", "type": "qt", "path": "/plugins/DefaultsPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Display", "type": "qt", "path": "/plugins/DisplayPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Input", "type": "qt", "path": "/plugins/InputPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Locale", "type": "qt", "path": "/plugins/LocalePlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Network", "type": "qt", "path": "/plugins/NetworkPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Notifications", "type": "qt", "path": "/plugins/NotificationsPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Overview", "type": "qt", "path": "/plugins/OverviewPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Power", "type": "qt", "path": "/plugins/PowerPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Screenshots", "type": "qt", "path": "/plugins/ScreenshotPlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Theme", "type": "qt", "path": "/plugins/ThemePlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Time and Date", "type": "qt", "path": "/plugins/TimeDatePlugin/translations/{lang}.ts", "baseLang": "en_US" }, { "name": "theDesk Users", "type": "qt", "path": "/plugins/UsersPlugin/translations/{lang}.ts", "baseLang": "en_US" } ] } ================================================ FILE: CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15) project(thedesk VERSION 1.0.0 LANGUAGES CXX) IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") link_directories(/usr/local/lib) ENDIF() find_package(QT REQUIRED NAMES Qt6) set(KF_VERSION_MAJOR ${QT_VERSION_MAJOR} CACHE STRING "Major version of KDE Frameworks to link to") add_subdirectory(libthedesk) add_subdirectory(startdesk) add_subdirectory(desktop) add_subdirectory(platform) add_subdirectory(plugins) add_subdirectory(polkitagent) add_subdirectory(locker) add_subdirectory(desktop-portal) add_subdirectory(wayfire-plugins) ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: README.md ================================================ ---

theDesk is a desktop environment built on Qt libraries. ---



# Dependencies - Qt 5 - Qt Core - Qt GUI - Qt Widgets - Qt SVG - [the-libs](https://github.com/vicr123/the-libs) - [libtdesktopenvironment](https://github.com/vicr123/libtdesktopenvironment) - Xlib - xorg-libinput - NetworkManager-Qt ## Recommended Dependencies - [contemporary-widgets](https://github.com/vicr123/contemporary-widgets) - the default widget theme - [contemporary-icons](https://github.com/vicr123/contemporary-icons) - the default icon theme ## Build Run the following commands in your terminal. ``` mkdir build qmake ../theDesk.pro make ``` ## Install On Linux, run the following command in your terminal (with superuser permissions) ``` make install ``` --- > © Victor Tran, 2021. This project is licensed under the GNU General Public License, version 3, or at your option, any later version. > > Check the [LICENSE](LICENSE) file for more information. ================================================ FILE: desktop/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) project(thedesk VERSION 1.0.0 LANGUAGES CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network DBus Multimedia QuickWidgets) find_package(libcontemporary REQUIRED) find_package(libtdesktopenvironment REQUIRED) set(SOURCES background/background.cpp bar/barwindow.cpp bar/chunkcontainer.cpp bar/currentappwidget.cpp bar/currentappwidgetmenu.cpp bar/mainbarwidget.cpp bar/taskbarapplicationwidget.cpp bar/taskbardesktopwidget.cpp bar/taskbarwidget.cpp cli/commandline.cpp crash/crashhandling.cpp gateway/appsearchprovider.cpp gateway/appselectionmodel.cpp gateway/appselectionmodellistdelegate.cpp gateway/gateway.cpp gateway/gatewaysearchmodel.cpp gateway/gatewaysearchmodeldelegate.cpp gateway/maingatewaywidget.cpp gateway/searchresultswidget.cpp main.cpp run/rundialog.cpp session/endsession.cpp session/endsessionbutton.cpp statuscenter/leftpanedelegate.cpp statuscenter/statuscenter.cpp statuscenter/statuscenterleftpane.cpp statuscenter/statuscenterquickswitch.cpp systemsettings/about/about.cpp systemsettings/about/acknowledgements.cpp systemsettings/about/changehostnamepopover.cpp systemsettings/pluginmanagement/managepluginpopover.cpp systemsettings/pluginmanagement/pluginitemdelegate.cpp systemsettings/pluginmanagement/pluginmanagement.cpp systemsettings/pluginmanagement/pluginmodel.cpp systemsettings/recovery/recovery.cpp systemsettings/systemsettings.cpp systemsettings/systemsettingsleftpane.cpp background/background.ui bar/barwindow.ui bar/chunkcontainer.ui bar/currentappwidget.ui bar/currentappwidgetmenu.ui bar/mainbarwidget.ui bar/taskbardesktopwidget.ui bar/taskbarwidget.ui gateway/gateway.ui gateway/maingatewaywidget.ui gateway/searchresultswidget.ui run/rundialog.ui session/endsession.ui statuscenter/statuscenter.ui statuscenter/statuscenterleftpane.ui statuscenter/statuscenterquickswitch.ui systemsettings/about/about.ui systemsettings/about/acknowledgements.ui systemsettings/about/changehostnamepopover.ui systemsettings/pluginmanagement/managepluginpopover.ui systemsettings/pluginmanagement/pluginmanagement.ui systemsettings/recovery/recovery.ui systemsettings/systemsettings.ui systemsettings/systemsettingsleftpane.ui resources.qrc ) set(HEADERS background/background.h bar/barwindow.h bar/chunkcontainer.h bar/currentappwidget.h bar/currentappwidgetmenu.h bar/mainbarwidget.h bar/taskbarapplicationwidget.h bar/taskbardesktopwidget.h bar/taskbarwidget.h cli/commandline.h crash/crashhandling.h gateway/appsearchprovider.h gateway/appselectionmodel.h gateway/appselectionmodellistdelegate.h gateway/gateway.h gateway/gatewaysearchmodel.h gateway/gatewaysearchmodeldelegate.h gateway/maingatewaywidget.h gateway/searchresultswidget.h run/rundialog.h session/endsession.h session/endsessionbutton.h statuscenter/leftpanedelegate.h statuscenter/statuscenter.h statuscenter/statuscenterleftpane.h statuscenter/statuscenterquickswitch.h systemsettings/about/about.h systemsettings/about/acknowledgements.h systemsettings/about/changehostnamepopover.h systemsettings/pluginmanagement/managepluginpopover.h systemsettings/pluginmanagement/pluginitemdelegate.h systemsettings/pluginmanagement/pluginmanagement.h systemsettings/pluginmanagement/pluginmodel.h systemsettings/recovery/recovery.h systemsettings/systemsettings.h systemsettings/systemsettingsleftpane.h ) add_executable(thedesk ${SOURCES} ${HEADERS}) set_target_properties(thedesk PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_GUI_IDENTIFIER com.vicr123.thedesk WIN32_EXECUTABLE TRUE CNTP_DATA_SUBDIR thedesk) cntp_init(thedesk 20) cntp_translate(thedesk) cntp_target_name(thedesk "thedesk") cntp_defaults_file(thedesk DEFAULTS_FILE thedesk.conf) target_link_libraries(thedesk Qt::Widgets Qt::Network Qt::DBus Qt::Multimedia Qt::QuickWidgets libcontemporary libtdesktopenvironment libthedesk) target_include_directories(thedesk PUBLIC ../libthedesk/) install(TARGETS thedesk RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} BUNDLE DESTINATION /Applications) # TODO: Port install rules over from qmake install(DIRECTORY media DESTINATION ${CMAKE_INSTALL_DATADIR}/thedesk ) ================================================ FILE: desktop/acknowledgements.html ================================================

Thanks to the following people who contributed to the development of theDesk in some way:

ZoomTen for testing and contributing resorces and ideas, such as window borders
GitHub

The Pixel Polygon for the welcome cutscene
YouTube

All the people who contributed translations to theDesk
Translation Website

All the people that sponsor me (or have ever done so) on GitHub Sponsors:

  • techli0n
  • Neptunium Fluoride
  • JPlexer
  • Tomas
  • Alee14
  • Kommult
GitHub Sponsors

================================================ FILE: desktop/background/background.cpp ================================================ /**************************************** * * theShell - Desktop Environment * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "background.h" #include "ui_background.h" #include #include #include #include #include #include #include #include struct BackgroundPrivate { static BackgroundController* bg; static QList backgrounds; SystemScreen* oldScreen = nullptr; QMetaObject::Connection screenGeometryChangedConnection; QSettings settings; bool retrieving = false; bool retrieveAgain = false; BackgroundController::BackgroundData background; bool isChangeBackgroundVisible = false; bool communityBackgroundSettingsShown = true; }; BackgroundController* BackgroundPrivate::bg = nullptr; QList BackgroundPrivate::backgrounds = QList(); Background::Background() : QDialog(nullptr), ui(new Ui::Background) { ui->setupUi(this); d = new BackgroundPrivate(); if (!d->bg) { d->bg = new BackgroundController(BackgroundController::Desktop); connect(qApp, &QApplication::screenAdded, &Background::reconfigureBackgrounds); connect(qApp, &QApplication::screenRemoved, &Background::reconfigureBackgrounds); connect(ScreenDaemon::instance(), &ScreenDaemon::screensUpdated, &Background::reconfigureBackgrounds); } connect(d->bg, &BackgroundController::currentBackgroundChanged, this, [this](BackgroundController::BackgroundType type) { if (type == BackgroundController::Desktop) this->changeBackground(); this->showCommunityBackgroundSettings(d->bg->currentBackgroundName(BackgroundController::Desktop) == "community" || d->bg->currentBackgroundName(BackgroundController::LockScreen) == "community"); }); connect(d->bg, &BackgroundController::shouldShowCommunityLabelsChanged, this, [this] { if (d->bg->currentBackgroundName(BackgroundController::Desktop) == "community") this->changeBackground(); }); connect(d->bg, &BackgroundController::stretchTypeChanged, this, [this](BackgroundController::StretchType stretchType) { switch (stretchType) { case BackgroundController::StretchFit: ui->stretchFitButton->setChecked(true); break; case BackgroundController::ZoomCrop: ui->zoomCropButton->setChecked(true); break; case BackgroundController::Center: ui->centerButton->setChecked(true); break; case BackgroundController::Tile: ui->tileButton->setChecked(true); break; case BackgroundController::ZoomFit: ui->zoomFitButton->setChecked(true); break; } this->changeBackground(); }); this->showCommunityBackgroundSettings(d->bg->currentBackgroundName(BackgroundController::Desktop) == "community" || d->bg->currentBackgroundName(BackgroundController::LockScreen) == "community"); switch (d->bg->stretchType()) { case BackgroundController::StretchFit: ui->stretchFitButton->setChecked(true); break; case BackgroundController::ZoomCrop: ui->zoomCropButton->setChecked(true); break; case BackgroundController::Center: ui->centerButton->setChecked(true); break; case BackgroundController::Tile: ui->tileButton->setChecked(true); break; case BackgroundController::ZoomFit: ui->zoomFitButton->setChecked(true); break; } ui->showImageInformationBox->setChecked(d->bg->shouldShowCommunityLabels()); ui->stackedWidget->setCurrentWidget(ui->backgroundPage); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->backgroundPage->installEventFilter(this); ui->backgroundSelectionWidget->setFixedHeight(0); ui->backgroundList->setModel(new BackgroundSelectionModel()); ui->backgroundList->setItemDelegate(new BackgroundSelectionDelegate()); ui->backgroundList->setIconSize(QSize(213, 120)); ui->backgroundList->setFixedHeight(120); this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnBottomHint); this->setAttribute(Qt::WA_ShowWithoutActivating, true); changeBackground(); } Background::~Background() { delete d; delete ui; } QCoro::Task<> Background::changeBackground() { if (d->retrieving) { d->retrieveAgain = true; co_return; } d->retrieving = true; ui->stackedWidget->setCurrentWidget(ui->loadingBackgroundPage); try { auto data = co_await d->bg->getCurrentBackground(this->size()); // TODO: what if the backgrounds change? d->background = data; if (d->background.extendedInfoAvailable) { QPainter painter(&data.px); if (d->settings.value("desktop/showLabels", true).toBool()) { QLinearGradient darkener; darkener.setColorAt(0, QColor::fromRgb(0, 0, 0, 0)); darkener.setColorAt(1, QColor::fromRgb(0, 0, 0, 200)); if (d->settings.value("bar/onTop", true).toBool()) { darkener.setStart(0, 0); darkener.setFinalStop(0, data.px.height()); } else { darkener.setStart(0, data.px.height()); darkener.setFinalStop(0, 0); } painter.setBrush(darkener); painter.drawRect(0, 0, data.px.width(), data.px.height()); painter.setPen(Qt::white); int currentX = 30; int baselineY; if (d->settings.value("bar/onTop", true).toBool()) { baselineY = data.px.height() - 30; } else { baselineY = 30 + QFontMetrics(QFont(this->font().family(), 20)).ascent(); } if (!data.name.isEmpty()) { painter.setFont(QFont(this->font().family(), 20)); int width = painter.fontMetrics().horizontalAdvance(data.name); painter.drawText(currentX, baselineY, data.name); currentX += width + 9; } if (!data.location.isEmpty()) { painter.setFont(QFont(this->font().family(), 10)); QIcon locationIcon = QIcon::fromTheme("gps"); int height = painter.fontMetrics().height(); int width = painter.fontMetrics().horizontalAdvance(data.location) + height; painter.drawPixmap(currentX, baselineY - height, locationIcon.pixmap(QSize(16, 16))); painter.drawText(currentX + height + 6, baselineY - painter.fontMetrics().descent(), data.location); currentX += width + 20; } if (!data.author.isEmpty()) { painter.setFont(QFont(this->font().family(), 10)); QString author = tr("by %1").arg(data.author); int width = painter.fontMetrics().horizontalAdvance(author); painter.drawText(data.px.width() - width - 30, baselineY, author); } } } QTimer::singleShot(1000, this, [this, data] { d->background = data; this->update(); d->retrieving = false; if (d->retrieveAgain) { d->retrieveAgain = false; this->changeBackground(); } else { ui->stackedWidget->setCurrentWidget(ui->backgroundPage); } }); } catch (BackgroundException ex) { d->retrieving = false; if (d->retrieveAgain) { d->retrieveAgain = false; this->changeBackground(); } else { ui->stackedWidget->setCurrentWidget(ui->backgroundErrorPage); } } } void Background::toggleChangeBackground() { d->isChangeBackgroundVisible = !d->isChangeBackgroundVisible; tVariantAnimation* anim = new tVariantAnimation(); anim->setStartValue(ui->backgroundSelectionWidget->height()); if (d->isChangeBackgroundVisible) { anim->setEndValue(ui->backgroundSelectionWidget->sizeHint().height()); // TODO: Hide the bar // MainWindow::instance()->forceHide(); } else { // TODO: Show the bar anim->setEndValue(0); // MainWindow::instance()->unforceHide(); } anim->setDuration(500); anim->setEasingCurve(QEasingCurve::OutCubic); connect(anim, &tVariantAnimation::valueChanged, this, [this](QVariant value) { ui->backgroundSelectionWidget->setFixedHeight(value.toInt()); }); connect(anim, &tVariantAnimation::finished, this, [this] { if (d->isChangeBackgroundVisible) { ui->backgroundSelectionWidget->setFixedHeight(QWIDGETSIZE_MAX); } }); anim->start(); DesktopWm::setShowDesktop(d->isChangeBackgroundVisible); } void Background::showCommunityBackgroundSettings(bool shown) { if (shown == d->communityBackgroundSettingsShown) return; d->communityBackgroundSettingsShown = shown; ui->communityBackgroundSettings->setVisible(shown); } void Background::show() { DesktopWm::setSystemWindow(this, DesktopWm::SystemWindowTypeDesktop); QDialog::show(); } void Background::on_actionChange_Background_triggered() { this->toggleChangeBackground(); } void Background::reject() { } bool Background::eventFilter(QObject* watched, QEvent* event) { if (watched == ui->backgroundPage) { if (event->type() == QEvent::Paint) { QPainter p(ui->backgroundPage); if (d->retrieving) { p.setPen(Qt::transparent); p.setBrush(Qt::black); p.drawRect(0, 0, this->width(), this->height()); } else { p.drawPixmap(0, -ui->backgroundSelectionWidget->height(), d->background.px); } } else if (event->type() == QEvent::MouseButtonPress) { if (d->isChangeBackgroundVisible) toggleChangeBackground(); } } return false; } void Background::on_Background_customContextMenuRequested(const QPoint& pos) { if (d->isChangeBackgroundVisible) return; QMenu* menu = new QMenu(this); menu->addSection(tr("For desktop")); menu->addAction(ui->actionChange_Background); connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); menu->popup(this->mapToGlobal(pos)); } void Background::paintEvent(QPaintEvent* event) { } void Background::resizeEvent(QResizeEvent* event) { this->changeBackground(); } void Background::resizeToScreen(int screen) { auto s = ScreenDaemon::instance()->screens().at(screen); if (s != d->oldScreen) { if (s != nullptr) disconnect(d->screenGeometryChangedConnection); connect(s, &SystemScreen::geometryChanged, this, [this, s] { this->setGeometry(s->geometry()); }); this->setGeometry(s->geometry()); this->show(); d->oldScreen = s; } } void Background::changeBackground(QString background, QList types) { if (background == "custom") { // Ask the user to select a background background = QFileDialog::getOpenFileName(this, tr("Select Background"), "", "Images (*.png *.jpg *.jpeg *.bmp *.gif)"); if (background.isEmpty()) return; } for (auto type : types) { d->bg->setBackground(background, type); } } void Background::reconfigureBackgrounds() { if (BackgroundPrivate::backgrounds.count() > ScreenDaemon::instance()->screens().count()) { // Remove backgrounds until the correct number of backgrounds have been created int difference = BackgroundPrivate::backgrounds.count() - ScreenDaemon::instance()->screens().count(); for (int i = 0; i < difference; i++) { BackgroundPrivate::backgrounds.takeLast()->deleteLater(); } } if (BackgroundPrivate::backgrounds.count() < ScreenDaemon::instance()->screens().count()) { // Add new backgrounds until the correct number of backgrounds have been created int difference = ScreenDaemon::instance()->screens().count() - BackgroundPrivate::backgrounds.count(); for (int i = 0; i < difference; i++) { Background* w = new Background(); BackgroundPrivate::backgrounds.append(w); } } for (int i = 0; i < ScreenDaemon::instance()->screens().count(); i++) { BackgroundPrivate::backgrounds.at(i)->resizeToScreen(i); } } void Background::on_tryReloadBackgroundButton_clicked() { this->changeBackground(); } void Background::on_backgroundList_clicked(const QModelIndex& index) { QString background = index.data(Qt::UserRole).toString(); QMenu* menu = new QMenu(this); menu->addSection(tr("Set Background")); menu->addAction(tr("Set as Desktop Background"), this, [this, background] { changeBackground(background, {BackgroundController::Desktop}); }); menu->addAction(tr("Set as Lock Screen Background"), this, [this, background] { changeBackground(background, {BackgroundController::LockScreen}); }); menu->addSeparator(); menu->addAction(tr("Set for both"), this, [this, background] { changeBackground(background, {BackgroundController::Desktop, BackgroundController::LockScreen}); }); connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); menu->popup(QCursor::pos()); } void Background::on_backButton_clicked() { this->toggleChangeBackground(); } void Background::on_showImageInformationBox_toggled(bool checked) { d->bg->setShouldShowCommunityLabels(checked); } void Background::on_stretchFitButton_toggled(bool checked) { if (checked) { d->bg->setStretchType(BackgroundController::StretchFit); } } void Background::on_zoomCropButton_toggled(bool checked) { if (checked) { d->bg->setStretchType(BackgroundController::ZoomCrop); } } void Background::on_centerButton_toggled(bool checked) { if (checked) { d->bg->setStretchType(BackgroundController::Center); } } void Background::on_tileButton_toggled(bool checked) { if (checked) { d->bg->setStretchType(BackgroundController::Tile); } } void Background::on_zoomFitButton_toggled(bool checked) { if (checked) { d->bg->setStretchType(BackgroundController::ZoomFit); } } void Background::on_actionEndSession_triggered() { } ================================================ FILE: desktop/background/background.h ================================================ /**************************************** * * theShell - Desktop Environment * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BACKGROUND_H #define BACKGROUND_H #include #include #include class ChooseBackground; namespace Ui { class Background; } struct BackgroundPrivate; class Background : public QDialog { Q_OBJECT public: explicit Background(); ~Background(); void show(); static void reconfigureBackgrounds(); public slots: QCoro::Task<> changeBackground(); void toggleChangeBackground(); void showCommunityBackgroundSettings(bool shown); signals: void setAllBackgrounds(QString background); void reloadBackground(); private slots: void on_actionChange_Background_triggered(); void on_Background_customContextMenuRequested(const QPoint& pos); void on_tryReloadBackgroundButton_clicked(); void on_backgroundList_clicked(const QModelIndex& index); void on_backButton_clicked(); void on_showImageInformationBox_toggled(bool checked); void on_stretchFitButton_toggled(bool checked); void on_zoomCropButton_toggled(bool checked); void on_centerButton_toggled(bool checked); void on_tileButton_toggled(bool checked); void on_zoomFitButton_toggled(bool checked); void on_actionEndSession_triggered(); private: Ui::Background* ui; BackgroundPrivate* d; void reject(); bool eventFilter(QObject* watched, QEvent* event); void paintEvent(QPaintEvent* event); void resizeEvent(QResizeEvent* event); void resizeToScreen(int screen); void changeBackground(QString background, QList types); }; #endif // BACKGROUND_H ================================================ FILE: desktop/background/background.ui ================================================ Background 0 0 751 517 Qt::CustomContextMenu theShell Background :/icons/icon.svg:/icons/icon.svg 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 true Qt::Vertical 20 37 Qt::Horizontal 114 20 Sorry, there was a problem displaying the background. Qt::Horizontal 40 20 Try Again Qt::Horizontal 40 20 Qt::Horizontal 113 20 Qt::Vertical 20 38 Qt::Vertical 20 58 Qt::Horizontal 275 20 Qt::Horizontal 274 20 Qt::Vertical 20 57 0 0 0 0 0 16777215 1 Qt::Horizontal 0 0 0 ../statuscenter/PulseaudioPane../statuscenter/PulseaudioPane true 0 0 15 Background 9 16777215 1 Qt::Horizontal 6 9 9 9 9 75 true IMAGE Select an image to display on your background and lock screen 0 0 QFrame::NoFrame QListView::Static false QListView::Adjust QListView::IconMode 0 0 0 0 0 16777215 1 Qt::Horizontal 6 9 9 9 9 75 true COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information 16777215 1 Qt::Horizontal 6 9 9 9 9 75 true STRETCH Select how you'd like the background image to be sized 0 Stretch To Fit .. 64 64 true true Qt::ToolButtonTextUnderIcon Zoom and Crop .. 64 64 true true Qt::ToolButtonTextUnderIcon Center .. 64 64 true true Qt::ToolButtonTextUnderIcon Tile .. 64 64 true true Qt::ToolButtonTextUnderIcon Zoom To Fit .. 64 64 true true Qt::ToolButtonTextUnderIcon Qt::Horizontal 40 20 .. Change Background End Session tCircularSpinner QWidget
tcircularspinner.h
1
tStackedWidget QStackedWidget
tstackedwidget.h
1
================================================ FILE: desktop/bar/barwindow.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "barwindow.h" #include "ui_barwindow.h" #include #include #include #include #include #include #include "mainbarwidget.h" #include "statuscenter/statuscenter.h" #include #include #include #include #include #include #include #include #include #include #include "gateway/gateway.h" #include struct BarWindowPrivate { MainBarWidget* mainBarWidget; StatusCenter* statusCenterWidget; tVariantAnimation* heightAnim; tVariantAnimation* barStatusCenterTransitionAnim; QGraphicsOpacityEffect* mainBarOpacity; QGraphicsOpacityEffect* statusCenterOpacity; SystemScreen* oldPrimaryScreen = nullptr; QList maximisedWindows; bool barExpanding = true; bool statusCenterShown = false; bool barPendingShow = false; GestureInteractionPtr lastGesture; tSettings settings; }; BarWindow::BarWindow(QWidget* parent) : QWidget(parent), ui(new Ui::BarWindow) { ui->setupUi(this); d = new BarWindowPrivate(); this->setAttribute(Qt::WA_TranslucentBackground); this->setMouseTracking(true); d->mainBarWidget = new MainBarWidget(this); connect(d->mainBarWidget, &MainBarWidget::expandedHeightChanged, this, &BarWindow::barHeightChanged); connect(d->mainBarWidget, &MainBarWidget::statusBarHeightChanged, this, &BarWindow::barHeightChanged); d->statusCenterWidget = new StatusCenter(this); d->mainBarOpacity = new QGraphicsOpacityEffect(d->mainBarWidget); d->mainBarOpacity->setEnabled(false); d->mainBarWidget->setGraphicsEffect(d->mainBarOpacity); d->statusCenterOpacity = new QGraphicsOpacityEffect(d->statusCenterWidget); d->statusCenterOpacity->setEnabled(false); d->statusCenterWidget->setGraphicsEffect(d->statusCenterOpacity); d->statusCenterWidget->setVisible(false); d->heightAnim = new tVariantAnimation(this); d->heightAnim->setDuration(500); connect(d->heightAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { this->setFixedHeight(value.toInt() + 1); }); connect(GestureDaemon::instance(), &GestureDaemon::gestureBegin, this, [=](GestureInteractionPtr gesture) { if (gesture->isValidInteraction(GestureTypes::Swipe, GestureTypes::Down, 3)) { if (d->barExpanding) { trackStatusCenterPullDownGesture(gesture); } else { trackBarPullDownGesture(gesture); } } else if (gesture->isValidInteraction(GestureTypes::Swipe, GestureTypes::Up, 3)) { if (d->statusCenterShown) { trackStatusCenterPullUpGesture(gesture); } } }); d->barStatusCenterTransitionAnim = new tVariantAnimation(); d->barStatusCenterTransitionAnim->setStartValue(0.0); d->barStatusCenterTransitionAnim->setEndValue(1.0); d->barStatusCenterTransitionAnim->setDuration(250); d->barStatusCenterTransitionAnim->setEasingCurve(QEasingCurve::InOutCubic); connect(d->barStatusCenterTransitionAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { double percentage = value.toDouble(); if (qFuzzyIsNull(percentage)) { // Fully show bar view d->statusCenterWidget->setVisible(false); d->mainBarWidget->setVisible(true); d->statusCenterOpacity->setEnabled(false); d->mainBarOpacity->setEnabled(false); this->setFixedHeight(d->mainBarWidget->expandedHeight()); ui->line->setVisible(true); } else if (qFuzzyCompare(percentage, 1)) { // Fully show Status Center view d->statusCenterWidget->setVisible(true); d->mainBarWidget->setVisible(false); d->statusCenterOpacity->setEnabled(false); d->mainBarOpacity->setEnabled(false); this->setFixedHeight(d->statusCenterWidget->height()); ui->line->setVisible(false); } else { if (percentage < 0.5) { // Animate the bar d->mainBarOpacity->setOpacity(1 - (percentage * 2)); d->mainBarOpacity->setEnabled(true); d->mainBarWidget->setVisible(true); d->statusCenterWidget->setVisible(false); d->statusCenterOpacity->setEnabled(false); } else { // Animate the Status Center d->statusCenterOpacity->setOpacity(percentage * 2 - 1); d->statusCenterOpacity->setEnabled(true); d->statusCenterWidget->setVisible(true); d->mainBarWidget->setVisible(false); d->mainBarOpacity->setEnabled(false); } this->setFixedHeight((d->statusCenterWidget->height() - d->mainBarWidget->expandedHeight()) * percentage + d->mainBarWidget->expandedHeight()); ui->line->setVisible(true); } }); // Tell the window manager that this is a "taskbar" type window this->setWindowFlag(Qt::FramelessWindowHint); DesktopWm::instance()->setSystemWindow(this, DesktopWm::SystemWindowTypeTaskbar); DesktopWm::instance()->blurWindow(this); this->barHeightChanged(); connect(qApp, &QApplication::primaryScreenChanged, this, &BarWindow::updatePrimaryScreen); updatePrimaryScreen(); connect(StateManager::statusCenterManager(), &StatusCenterManager::showStatusCenter, this, &BarWindow::showStatusCenter); connect(StateManager::statusCenterManager(), &StatusCenterManager::hideStatusCenter, this, &BarWindow::hideStatusCenter); connect(StateManager::barManager(), &BarManager::barLockedChanged, this, [=](bool isBarLocked) { if (!isBarLocked) { // showBar(); // } else { if (!this->geometry().contains(QCursor::pos())) hideBar(); } }); connect(&d->settings, &tSettings::settingChanged, this, [=](QString key, QVariant value) { if (key == "Appearance/translucent") { this->update(); } }); connect(DesktopWm::instance(), &DesktopWm::windowAdded, this, &BarWindow::trackWindow); connect(DesktopWm::instance(), &DesktopWm::windowRemoved, this, [=](DesktopWmWindowPtr window) { if (d->maximisedWindows.contains(window)) { d->maximisedWindows.removeAll(window); this->update(); } }); for (const DesktopWmWindowPtr& window : DesktopWm::openWindows()) { trackWindow(window); } KeyGrab* statusCenterGrab = new KeyGrab(QKeySequence(Qt::MetaModifier | Qt::Key_Tab)); connect(statusCenterGrab, &KeyGrab::activated, this, [=] { StateManager::statusCenterManager()->show(); }); ui->line->raise(); // Initialise the Gateway Gateway::instance(); } BarWindow::~BarWindow() { delete ui; delete d; } void BarWindow::setFixedHeight(int height) { QWidget::setFixedHeight(height); // Work around a Qt bug that causes the native window not to be updated on Wayland for some reason this->windowHandle()->setGeometry(this->geometry()); } void BarWindow::setFixedWidth(int width) { QWidget::setFixedWidth(width); // Work around a Qt bug that causes the native window not to be updated on Wayland for some reason this->windowHandle()->setGeometry(this->geometry()); } void BarWindow::resizeEvent(QResizeEvent* event) { ui->line->setGeometry(0, this->height() - 1, this->width(), this->height()); d->mainBarWidget->setFixedWidth(this->width()); d->mainBarWidget->barHeightChanged(this->height() - 1); d->statusCenterWidget->setFixedWidth(this->width()); StateManager::barManager()->setBarHeight(this->height()); } void BarWindow::enterEvent(QEnterEvent* event) { if (d->lastGesture && d->lastGesture->isActive()) return; d->barPendingShow = true; if ((this->layoutDirection() == Qt::RightToLeft && mapFromGlobal(QCursor::pos()).x() > d->mainBarWidget->currentAppWidgetX()) || (this->layoutDirection() == Qt::LeftToRight && mapFromGlobal(QCursor::pos()).x() < d->mainBarWidget->currentAppWidgetX())) showBar(); } void BarWindow::leaveEvent(QEvent* event) { if (d->lastGesture && d->lastGesture->isActive()) return; hideBar(); } void BarWindow::paintEvent(QPaintEvent* event) { QColor bgCol = this->palette().color(QPalette::Window); if (d->settings.value("Appearance/translucent").toBool() && d->maximisedWindows.count() == 0) bgCol.setAlpha(150); QPainter painter(this); painter.setPen(Qt::transparent); painter.setBrush(bgCol); painter.drawRect(0, 0, this->width(), this->height()); } void BarWindow::trackWindow(DesktopWmWindowPtr window) { window->disconnect(this); DesktopWm::instance()->disconnect(window); connect(window, &DesktopWmWindow::geometryChanged, this, [=] { trackWindow(window); }); connect(window, &DesktopWmWindow::windowStateChanged, this, [=] { trackWindow(window); }); connect(DesktopWm::instance(), &DesktopWm::currentDesktopChanged, window, [=] { trackWindow(window); }); QRect screenGeometry = QApplication::primaryScreen()->geometry(); if (window->isMaximised() && !window->isMinimized() && screenGeometry.contains(window->geometry()) && window->isOnCurrentDesktop()) { if (d->maximisedWindows.contains(window)) return; d->maximisedWindows.append(window); this->update(); } else if (!window->isMaximised() || window->isMinimized() || !window->isOnCurrentDesktop()) { if (!d->maximisedWindows.contains(window)) return; d->maximisedWindows.removeAll(window); this->update(); } } void BarWindow::updatePrimaryScreen() { if (d->oldPrimaryScreen) { disconnect(d->oldPrimaryScreen, &SystemScreen::geometryChanged, this, &BarWindow::updatePrimaryScreen); disconnect(d->oldPrimaryScreen, &SystemScreen::rotationChanged, this, &BarWindow::updatePrimaryScreen); } auto* primaryScreen = ScreenDaemon::instance()->primayScreen(); connect(primaryScreen, &SystemScreen::geometryChanged, this, &BarWindow::updatePrimaryScreen); connect(primaryScreen, &SystemScreen::rotationChanged, this, &BarWindow::updatePrimaryScreen); d->oldPrimaryScreen = primaryScreen; if (primaryScreen) { // Qt adjusts the size of the window for us, so we'll need to adjust for that auto primaryGeometry = primaryScreen->geometry(); primaryGeometry.setSize(primaryGeometry.size() / primaryScreen->qtScreen()->devicePixelRatio()); this->setFixedWidth(primaryGeometry.width()); this->move(primaryGeometry.topLeft()); d->statusCenterWidget->setFixedHeight(primaryGeometry.height()); } // Refresh the state of all the windows for (const DesktopWmWindowPtr& window : DesktopWm::openWindows()) { trackWindow(window); } barHeightChanged(); } void BarWindow::barHeightChanged() { DesktopWm::setScreenMarginForWindow(this, qApp->primaryScreen(), Qt::TopEdge, d->mainBarWidget->statusBarHeight() * (ScreenDaemon::instance()->primayScreen() ? ScreenDaemon::instance()->primayScreen()->qtScreen()->devicePixelRatio() : 1)); d->mainBarWidget->setFixedHeight(d->mainBarWidget->expandedHeight()); if (!d->statusCenterShown) { QSignalBlocker blocker(d->heightAnim); d->heightAnim->setStartValue(this->height() - 1); d->heightAnim->setEndValue(d->barExpanding ? d->mainBarWidget->expandedHeight() : d->mainBarWidget->statusBarHeight()); d->heightAnim->setEasingCurve(QEasingCurve::OutCubic); d->heightAnim->stop(); d->heightAnim->start(); } } void BarWindow::showStatusCenter() { QSignalBlocker blocker(d->heightAnim); d->heightAnim->stop(); StateManager::statusCenterManager()->setIsShowingStatusCenter(true); int time = d->barStatusCenterTransitionAnim->currentTime(); d->barStatusCenterTransitionAnim->setDirection(tVariantAnimation::Forward); d->barStatusCenterTransitionAnim->start(); d->barStatusCenterTransitionAnim->setCurrentTime(time); // Tell the window manager that this is now a standard system window DesktopWm::instance()->setSystemWindow(this); d->statusCenterWidget->setFocus(); d->statusCenterShown = true; } void BarWindow::hideStatusCenter() { StateManager::statusCenterManager()->setIsShowingStatusCenter(false); int time = d->barStatusCenterTransitionAnim->currentTime(); d->barStatusCenterTransitionAnim->setDirection(tVariantAnimation::Backward); d->barStatusCenterTransitionAnim->start(); d->barStatusCenterTransitionAnim->setCurrentTime(time); // Tell the window manager that this is now a "taskbar" type window DesktopWm::instance()->setSystemWindow(this, DesktopWm::SystemWindowTypeTaskbar); d->mainBarWidget->setFocus(); d->statusCenterShown = false; } void BarWindow::showBar() { d->barPendingShow = false; // If we're showing the status bar, don't touch the height if (!StateManager::statusCenterManager()->isShowingStatusCenter()) { QSignalBlocker blocker(d->heightAnim); d->heightAnim->setStartValue(this->height() - 1); d->heightAnim->setEndValue(d->mainBarWidget->expandedHeight()); d->heightAnim->setEasingCurve(QEasingCurve::OutCubic); d->heightAnim->stop(); d->heightAnim->start(); d->barExpanding = true; } } void BarWindow::hideBar() { // If we're showing the status bar, don't touch the height if (!StateManager::statusCenterManager()->isShowingStatusCenter() && !StateManager::barManager()->isBarLocked()) { QSignalBlocker blocker(d->heightAnim); d->heightAnim->setStartValue(this->height() - 1); d->heightAnim->setEndValue(d->mainBarWidget->statusBarHeight()); d->heightAnim->setEasingCurve(QEasingCurve::OutCubic); d->heightAnim->stop(); d->heightAnim->start(); d->barExpanding = false; } } void BarWindow::trackBarPullDownGesture(GestureInteractionPtr gesture) { if (d->statusCenterShown || d->barExpanding) return; // Capture this gesture! d->lastGesture = gesture; QSignalBlocker blocker(d->heightAnim); d->heightAnim->setStartValue(this->height() - 1); d->heightAnim->setEndValue(d->mainBarWidget->expandedHeight()); d->heightAnim->setEasingCurve(QEasingCurve::Linear); d->heightAnim->stop(); d->barExpanding = true; connect(gesture.data(), &GestureInteraction::interactionUpdated, this, [=] { d->heightAnim->setCurrentTime(d->heightAnim->totalDuration() * gesture->percentage()); d->heightAnim->valueChanged(d->heightAnim->currentValue()); }); connect(gesture.data(), &GestureInteraction::interactionEnded, this, [=] { if (gesture->extrapolatePercentage(100) > 0.7) { showBar(); QTimer::singleShot(3000, this, [=] { if (gesture == d->lastGesture && !this->underMouse()) hideBar(); }); } else { hideBar(); } }); } void BarWindow::trackStatusCenterPullDownGesture(GestureInteractionPtr gesture) { if (d->statusCenterShown) return; // Capture this gesture! d->lastGesture = gesture; d->barStatusCenterTransitionAnim->setDirection(tVariantAnimation::Forward); d->barStatusCenterTransitionAnim->setCurrentTime(0); connect(gesture.data(), &GestureInteraction::interactionUpdated, this, [=] { d->barStatusCenterTransitionAnim->setCurrentTime(d->barStatusCenterTransitionAnim->totalDuration() * gesture->percentage()); d->barStatusCenterTransitionAnim->valueChanged(d->barStatusCenterTransitionAnim->currentValue()); }); connect(gesture.data(), &GestureInteraction::interactionEnded, this, [=] { if (gesture->extrapolatePercentage(100) > 0.7) { showStatusCenter(); } else { hideStatusCenter(); } }); } void BarWindow::trackStatusCenterPullUpGesture(GestureInteractionPtr gesture) { if (!d->statusCenterShown) return; // Only accept this gesture if there is not currently a popover active QList childWidgets; childWidgets.append(this); while (!childWidgets.isEmpty()) { QWidget* w = childWidgets.takeFirst(); if (tPopover::popoverForPopoverWidget(w)) return; for (QObject* o : w->children()) { if (qobject_cast(o)) childWidgets.append(qobject_cast(o)); } } // Capture this gesture! d->lastGesture = gesture; d->barStatusCenterTransitionAnim->setDirection(tVariantAnimation::Forward); d->barStatusCenterTransitionAnim->setCurrentTime(d->barStatusCenterTransitionAnim->duration()); connect(gesture.data(), &GestureInteraction::interactionUpdated, this, [=] { d->barStatusCenterTransitionAnim->setCurrentTime(d->barStatusCenterTransitionAnim->totalDuration() - d->barStatusCenterTransitionAnim->totalDuration() * gesture->percentage()); d->barStatusCenterTransitionAnim->valueChanged(d->barStatusCenterTransitionAnim->currentValue()); }); connect(gesture.data(), &GestureInteraction::interactionEnded, this, [=] { if (gesture->extrapolatePercentage(100) > 0.3) { hideStatusCenter(); } else { showStatusCenter(); } }); } void BarWindow::mouseMoveEvent(QMouseEvent* event) { if (event->pos().x() < d->mainBarWidget->currentAppWidgetX() && d->barPendingShow) showBar(); } ================================================ FILE: desktop/bar/barwindow.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BARWINDOW_H #define BARWINDOW_H #include #include #include namespace Ui { class BarWindow; } struct BarWindowPrivate; class BarWindow : public QWidget { Q_OBJECT public: explicit BarWindow(QWidget* parent = nullptr); ~BarWindow(); void setFixedHeight(int height); void setFixedWidth(int width); private: Ui::BarWindow* ui; BarWindowPrivate* d; void resizeEvent(QResizeEvent* event); void enterEvent(QEnterEvent* event); void leaveEvent(QEvent* event); void paintEvent(QPaintEvent* event); void mouseMoveEvent(QMouseEvent* event); void trackWindow(DesktopWmWindowPtr window); void updatePrimaryScreen(); void barHeightChanged(); void showStatusCenter(); void hideStatusCenter(); void showBar(); void hideBar(); void trackBarPullDownGesture(GestureInteractionPtr gesture); void trackStatusCenterPullDownGesture(GestureInteractionPtr gesture); void trackStatusCenterPullUpGesture(GestureInteractionPtr gesture); }; #endif // BARWINDOW_H ================================================ FILE: desktop/bar/barwindow.ui ================================================ BarWindow 0 0 636 300 Form 130 250 118 1 16777215 1 Qt::Horizontal ================================================ FILE: desktop/bar/chunkcontainer.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "chunkcontainer.h" #include "ui_chunkcontainer.h" #include "common/common.h" #include #include #include #include #include #include #include struct ChunkContainerPrivate { BarManager* barManager; QList> loadedChunks; QStringList preferredChunkOrder = { "OverviewClock", "Power", "PowerStretch", "flight-mode", "network-cellular", "Network", "network-tethering", "bluetooth", "audio", "audio-mic", "redshift", "keyboardlayout", "caffeinate", "Accessibility-StickyKeys", "mpris"}; QMap chunkWidgets; qreal currentAnimProgress = 1; }; ChunkContainer::ChunkContainer(QWidget* parent) : QWidget(parent), ui(new Ui::ChunkContainer) { ui->setupUi(this); d = new ChunkContainerPrivate(); d->barManager = StateManager::barManager(); ui->statusCenterButtonLine->setVisible(false); connect(d->barManager, &BarManager::chunkAdded, this, &ChunkContainer::chunkAdded); connect(d->barManager, &BarManager::chunkRemoved, this, &ChunkContainer::chunkRemoved); for (Chunk* chunk : d->barManager->chunks()) { this->chunkAdded(chunk); } connect(StateManager::barManager(), &BarManager::barHeightTransitioning, this, [=](qreal percentage) { int spacing = 3 + 3 * percentage; ui->chunkLayout->setSpacing(spacing); }); connect(ui->scrollArea->horizontalScrollBar(), &QScrollBar::valueChanged, this, [=](int value) { ui->statusCenterButtonLine->setVisible(value != 0); }); QPalette pal; pal.setBrush(QPalette::Window, Qt::transparent); ui->scrollArea->setPalette(pal); ui->scrollAreaWidgetContents->setPalette(pal); } ChunkContainer::~ChunkContainer() { delete d; delete ui; ui = nullptr; } int ChunkContainer::statusBarHeight() { int maxHeight = 0; for (Chunk* chunk : d->barManager->chunks()) { maxHeight = qMax(chunk->statusBarHeight(), maxHeight); } return maxHeight; } int ChunkContainer::expandedHeight() { int maxHeight = 0; for (Chunk* chunk : d->barManager->chunks()) { maxHeight = qMax(chunk->expandedHeight(), maxHeight); } return maxHeight; } int ChunkContainer::currentAppWidgetX() { return this->layoutDirection() == Qt::RightToLeft ? ui->currentAppWidget->width() : ui->currentAppWidget->x(); } void ChunkContainer::barHeightChanged(int height) { // if (height >= statusBarHeight() && height <= expandedHeight()) { // this->setFixedHeight(height); // } int boundHeight = qBound(statusBarHeight(), height, expandedHeight()); this->setFixedHeight(boundHeight); ui->chunkWidget->setFixedHeight(boundHeight); qreal percentageAnim = static_cast((height - statusBarHeight())) / (expandedHeight() - statusBarHeight()); if (percentageAnim < 0) percentageAnim = 0; if (percentageAnim > 1) percentageAnim = 1; d->barManager->barHeightTransitioning(percentageAnim); ui->currentAppWidget->barHeightChanging(percentageAnim); d->currentAnimProgress = percentageAnim; } void ChunkContainer::paintEvent(QPaintEvent* event) { } void ChunkContainer::chunkAdded(Chunk* chunk) { // Create a chunk widget QWidget* chunkWidget = new QWidget(this); QBoxLayout* chunkWidgetLayout = new QBoxLayout(QBoxLayout::LeftToRight, chunkWidget); QFrame* line = new QFrame(chunkWidget); line->setFrameShape(QFrame::VLine); line->setFixedWidth(1); chunkWidgetLayout->addWidget(line); chunkWidgetLayout->addWidget(chunk); chunkWidgetLayout->setSpacing(0); chunkWidgetLayout->setContentsMargins(0, 0, 0, 0); chunkWidget->setLayout(chunkWidgetLayout); d->chunkWidgets.insert(chunk, chunkWidget); QGraphicsOpacityEffect* lineOpacity = new QGraphicsOpacityEffect(line); lineOpacity->setOpacity(d->currentAnimProgress); line->setGraphicsEffect(lineOpacity); QStringList currentItems; for (QPair item : d->loadedChunks) { currentItems.append(item.first); } int index = Common::getInsertionIndex(d->preferredChunkOrder, currentItems, chunk->name()); if (index == -1) { // Add it at the end ui->chunkLayout->addWidget(chunkWidget); d->loadedChunks.append({chunk->name(), chunk}); } else { // Add this chunk at the beginning ui->chunkLayout->insertWidget(index, chunkWidget); d->loadedChunks.insert(index, {chunk->name(), chunk}); } connect(this, &ChunkContainer::chunksChanged, chunkWidget, [=] { // Make sure the line is not visible and set the margins appropriately for (int i = 0; i < d->loadedChunks.count(); i++) { QPair chunkDescriptor = d->loadedChunks.at(i); if (chunkDescriptor.second == chunk) { line->setVisible(i != 0); return; } } }); connect(StateManager::barManager(), &BarManager::barHeightTransitioning, lineOpacity, &QGraphicsOpacityEffect::setOpacity); emit statusBarHeightChanged(); emit expandedHeightChanged(); emit chunksChanged(); } void ChunkContainer::chunkRemoved(Chunk* chunk) { if (!ui) return; for (int i = 0; i < d->loadedChunks.count(); i++) { if (d->loadedChunks.at(i).second == chunk) { QWidget* chunkWidget = d->chunkWidgets.take(chunk); ui->chunkLayout->removeWidget(chunkWidget); d->loadedChunks.removeAt(i); chunk->setParent(nullptr); chunkWidget->deleteLater(); emit statusBarHeightChanged(); emit expandedHeightChanged(); return; } } } void ChunkContainer::on_statusCenterButton_clicked() { StateManager::statusCenterManager()->showStatusCenter(); } ================================================ FILE: desktop/bar/chunkcontainer.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CHUNKCONTAINER_H #define CHUNKCONTAINER_H #include namespace Ui { class ChunkContainer; } class Chunk; struct ChunkContainerPrivate; class ChunkContainer : public QWidget { Q_OBJECT public: explicit ChunkContainer(QWidget* parent = nullptr); ~ChunkContainer(); int statusBarHeight(); int expandedHeight(); int currentAppWidgetX(); void barHeightChanged(int height); signals: void statusBarHeightChanged(); void expandedHeightChanged(); void chunksChanged(); private slots: void on_statusCenterButton_clicked(); private: Ui::ChunkContainer* ui; ChunkContainerPrivate* d; void paintEvent(QPaintEvent* event); void chunkAdded(Chunk* chunk); void chunkRemoved(Chunk* chunk); }; #endif // CHUNKCONTAINER_H ================================================ FILE: desktop/bar/chunkcontainer.ui ================================================ ChunkContainer 0 0 400 23 Form 0 0 0 0 0 0 0 Open Status Center .. 1 16777215 Qt::Vertical 0 0 QFrame::NoFrame Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff QAbstractScrollArea::AdjustToContents true 0 0 365 23 0 0 0 0 0 0 0 0 9 0 9 0 Qt::Horizontal 0 20 CurrentAppWidget QWidget
bar/currentappwidget.h
1
================================================ FILE: desktop/bar/currentappwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "currentappwidget.h" #include "ui_currentappwidget.h" #include #include #include #include #include #include #include #include "currentappwidgetmenu.h" struct CurrentAppWidgetPrivate { QPalette pal; QGraphicsOpacityEffect* opacity; tVariantAnimation* anim; QuickWidgetContainer* menuContainer; CurrentAppWidgetMenu* menu; KeyGrab* forceStopGrab; }; CurrentAppWidget::CurrentAppWidget(QWidget* parent) : QWidget(parent), ui(new Ui::CurrentAppWidget) { ui->setupUi(this); d = new CurrentAppWidgetPrivate(); d->pal = this->palette(); d->pal.setColor(QPalette::Window, QColor(0, 0, 0, 0)); this->setPalette(d->pal); d->opacity = new QGraphicsOpacityEffect(this); d->opacity->setOpacity(1); this->setGraphicsEffect(d->opacity); d->anim = new tVariantAnimation(this); d->anim->setStartValue(0.0); d->anim->setEndValue(1.0); d->anim->setDuration(200); connect(d->anim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { d->opacity->setOpacity(value.toReal()); }); d->menu = new CurrentAppWidgetMenu(); d->menuContainer = new QuickWidgetContainer(this); d->menuContainer->setQuickWidget(d->menu); connect(d->menuContainer, &QuickWidgetContainer::hiding, this, &CurrentAppWidget::activeWindowChanged); connect(d->menu, &CurrentAppWidgetMenu::done, d->menuContainer, &QuickWidgetContainer::hideContainer); connect(DesktopWm::instance(), &DesktopWm::activeWindowChanged, this, &CurrentAppWidget::activeWindowChanged); activeWindowChanged(); d->forceStopGrab = new KeyGrab(QKeySequence(Qt::ControlModifier | Qt::AltModifier | Qt::Key_Escape), "force-stop"); connect(d->forceStopGrab, &KeyGrab::activated, this, [ = ] { DesktopWmWindowPtr active = DesktopWm::activeWindow(); if (!active->application()) return; d->menu->setWindow(active); d->menu->showForceStopScreen(); if (!d->menuContainer->isShowing()) d->menuContainer->showContainer(); }); } CurrentAppWidget::~CurrentAppWidget() { delete d; delete ui; } void CurrentAppWidget::barHeightChanging(float barTransitionPercentage) { if (qFuzzyIsNull(barTransitionPercentage)) { this->setFixedWidth(QWIDGETSIZE_MAX); this->setVisible(true); } else if (qFuzzyCompare(barTransitionPercentage, 1)) { this->setVisible(false); } else { this->setFixedWidth(this->sizeHint().width() * (1 - barTransitionPercentage)); this->setVisible(true); } } void CurrentAppWidget::activeWindowChanged() { if (d->menuContainer->isShowing()) return; DesktopWmWindowPtr active = DesktopWm::activeWindow(); if (active) { ApplicationPointer app = active->application(); if (app) { ui->iconLabel->setPixmap(QIcon::fromTheme(app->getProperty("Icon").toString()).pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->currentAppLabel->setText(app->getProperty("Name").toString()); if (d->anim->direction() == tVariantAnimation::Backward) { d->anim->setDirection(tVariantAnimation::Forward); d->anim->start(); } } else { if (d->anim->direction() == tVariantAnimation::Forward) { d->anim->setDirection(tVariantAnimation::Backward); d->anim->start(); } } } else { ui->iconLabel->setPixmap(QIcon(":/thedesk/desktop/thedesk.svg").pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->currentAppLabel->setText(QStringLiteral("theDesk")); if (d->anim->direction() == tVariantAnimation::Backward) { d->anim->setDirection(tVariantAnimation::Forward); d->anim->start(); } } } void CurrentAppWidget::enterEvent(QEvent* event) { QPalette pal = d->pal; pal.setColor(QPalette::Window, QColor(255, 255, 255, 100)); this->setPalette(pal); } void CurrentAppWidget::leaveEvent(QEvent* event) { this->setPalette(d->pal); } void CurrentAppWidget::mousePressEvent(QMouseEvent* event) { QPalette pal = d->pal; pal.setColor(QPalette::Window, QColor(0, 0, 0, 100)); this->setPalette(pal); } void CurrentAppWidget::mouseReleaseEvent(QMouseEvent* event) { QPalette pal = d->pal; pal.setColor(QPalette::Window, QColor(255, 255, 255, 100)); this->setPalette(pal); if (this->underMouse()) { //Click! DesktopWmWindowPtr active = DesktopWm::activeWindow(); if (!active || !active->application()) return; d->menu->setWindow(active); if (!d->menuContainer->isShowing()) d->menuContainer->showContainer(); } } ================================================ FILE: desktop/bar/currentappwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CURRENTAPPWIDGET_H #define CURRENTAPPWIDGET_H #include namespace Ui { class CurrentAppWidget; } struct CurrentAppWidgetPrivate; class CurrentAppWidget : public QWidget { Q_OBJECT public: explicit CurrentAppWidget(QWidget* parent = nullptr); ~CurrentAppWidget(); void barHeightChanging(float barTransitionPercentage); private: Ui::CurrentAppWidget* ui; CurrentAppWidgetPrivate* d; void activeWindowChanged(); // QWidget interface protected: void enterEvent(QEvent* event); void leaveEvent(QEvent* event); void mousePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); }; #endif // CURRENTAPPWIDGET_H ================================================ FILE: desktop/bar/currentappwidget.ui ================================================ CurrentAppWidget 0 0 90 35 Form true 0 0 0 0 0 1 16777215 Qt::Vertical 6 3 3 3 3 Icon Current App ================================================ FILE: desktop/bar/currentappwidgetmenu.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "currentappwidgetmenu.h" #include "ui_currentappwidgetmenu.h" #include struct CurrentAppWidgetMenuPrivate { DesktopWmWindowPtr window; QList actionButtons; }; CurrentAppWidgetMenu::CurrentAppWidgetMenu(QWidget* parent) : QWidget(parent), ui(new Ui::CurrentAppWidgetMenu) { ui->setupUi(this); d = new CurrentAppWidgetMenuPrivate(); ui->quitImmediateButton->setProperty("type", "destructive"); ui->doQuitImmediateButton->setProperty("type", "destructive"); updateModifiers(); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); } CurrentAppWidgetMenu::~CurrentAppWidgetMenu() { delete d; delete ui; } QSize CurrentAppWidgetMenu::sizeHint() const { return this->size(); } void CurrentAppWidgetMenu::setWindow(DesktopWmWindowPtr window) { for (QPushButton* button : d->actionButtons) { ui->actionsLayout->removeWidget(button); button->setVisible(false); button->deleteLater(); } d->actionButtons.clear(); d->window = window; QString applicationName = window->application()->getProperty("Name").toString(); ui->quitImmediateButton->setText(tr("Force Stop")); ui->quitImmediateTitle->setText(tr("Force Stop %1").arg(applicationName).toUpper()); ui->quitImmediateDescription->setText(tr("%1 will be forced to exit and won't have a chance to save any unsaved data.").arg(applicationName)); ui->doQuitImmediateButton->setText(tr("Force Stop %1").arg(applicationName)); ui->cancelImmediateQuitButton->setVisible(true); QStringList actions = window->application()->getStringList("Actions"); for (const QString& action : qAsConst(actions)) { QPushButton* button = new QPushButton(); button->setText(window->application()->getActionProperty(action, "Name").toString()); connect(button, &QPushButton::clicked, this, [ = ] { window->application()->launchAction(action); emit done(); }); ui->actionsLayout->addWidget(button); d->actionButtons.append(button); } ui->actionsWidget->setVisible(!actions.isEmpty()); ui->stackedWidget->setCurrentWidget(ui->initialPage, false); updateModifiers(); } void CurrentAppWidgetMenu::showForceStopScreen() { ui->cancelImmediateQuitButton->setVisible(false); ui->stackedWidget->setCurrentWidget(ui->quitImmediatelyPage, false); this->setFixedSize(ui->stackedWidget->currentWidget()->sizeHint()); } void CurrentAppWidgetMenu::updateModifiers() { bool showExtraOptions = qApp->queryKeyboardModifiers() & Qt::ShiftModifier; ui->quitImmediateButton->setVisible(showExtraOptions); on_stackedWidget_switchingFrame(ui->stackedWidget->currentIndex()); } void CurrentAppWidgetMenu::on_closeWindowButton_clicked() { d->window->close(); emit done(); } void CurrentAppWidgetMenu::keyPressEvent(QKeyEvent* event) { updateModifiers(); } void CurrentAppWidgetMenu::keyReleaseEvent(QKeyEvent* event) { updateModifiers(); } void CurrentAppWidgetMenu::on_doQuitImmediateButton_clicked() { d->window->kill(); emit done(); } void CurrentAppWidgetMenu::on_cancelImmediateQuitButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->initialPage); } void CurrentAppWidgetMenu::on_quitImmediateButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->quitImmediatelyPage); } void CurrentAppWidgetMenu::on_stackedWidget_switchingFrame(int frame) { QTimer::singleShot(0, [ = ] { tVariantAnimation::singleShot(this, this->size(), ui->stackedWidget->widget(frame)->sizeHint(), 250, [ = ](QVariant value) { this->setFixedSize(value.toSize()); }); }); } ================================================ FILE: desktop/bar/currentappwidgetmenu.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CURRENTAPPWIDGETMENU_H #define CURRENTAPPWIDGETMENU_H #include #include namespace Ui { class CurrentAppWidgetMenu; } struct CurrentAppWidgetMenuPrivate; class CurrentAppWidgetMenu : public QWidget { Q_OBJECT public: explicit CurrentAppWidgetMenu(QWidget* parent = nullptr); ~CurrentAppWidgetMenu(); QSize sizeHint() const; void setWindow(DesktopWmWindowPtr window); void showForceStopScreen(); void updateModifiers(); private slots: void on_closeWindowButton_clicked(); void on_doQuitImmediateButton_clicked(); void on_cancelImmediateQuitButton_clicked(); void on_quitImmediateButton_clicked(); void on_stackedWidget_switchingFrame(int frame); signals: void done(); private: Ui::CurrentAppWidgetMenu* ui; CurrentAppWidgetMenuPrivate* d; // QWidget interface protected: void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); }; #endif // CURRENTAPPWIDGETMENU_H ================================================ FILE: desktop/bar/currentappwidgetmenu.ui ================================================ CurrentAppWidgetMenu 0 0 400 105 Form 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Close Window .. 0 0 0 0 0 16777215 1 Qt::Horizontal 16777215 1 Qt::Horizontal Quit Immediately .. 0 0 0 0 0 9 9 9 6 true QUIT IMMEDIATELY TextLabel Cancel .. Quit Immediately .. tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
================================================ FILE: desktop/bar/mainbarwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "mainbarwidget.h" #include "ui_mainbarwidget.h" #include "gateway/gateway.h" #include #include #include #include #include #include #include MainBarWidget::MainBarWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainBarWidget) { ui->setupUi(this); ui->gatewayButton->setIconSize(SC_DPI_T(QSize(32, 32), QSize)); connect(ui->chunkContainer, &ChunkContainer::expandedHeightChanged, this, &MainBarWidget::expandedHeightChanged); connect(ui->chunkContainer, &ChunkContainer::statusBarHeightChanged, this, &MainBarWidget::statusBarHeightChanged); connect(new KeyGrab(QKeySequence(Qt::Key_Super_L), "gatewayOpen"), &KeyGrab::activated, this, [=] { Gateway::instance()->show(); }); } MainBarWidget::~MainBarWidget() { delete ui; } int MainBarWidget::statusBarHeight() { return ui->chunkContainer->statusBarHeight(); } int MainBarWidget::expandedHeight() { return ui->chunkContainer->expandedHeight() + ui->mainContentsWidget->sizeHint().height(); } int MainBarWidget::currentAppWidgetX() { return ui->chunkContainer->currentAppWidgetX(); } void MainBarWidget::barHeightChanged(int height) { ui->chunkContainer->barHeightChanged(height); } void MainBarWidget::on_gatewayButton_clicked() { Gateway::instance()->show(); } ================================================ FILE: desktop/bar/mainbarwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MAINBARWIDGET_H #define MAINBARWIDGET_H #include namespace Ui { class MainBarWidget; } class MainBarWidget : public QWidget { Q_OBJECT public: explicit MainBarWidget(QWidget* parent = nullptr); ~MainBarWidget(); int statusBarHeight(); int expandedHeight(); int currentAppWidgetX(); void barHeightChanged(int height); signals: void statusBarHeightChanged(); void expandedHeightChanged(); private slots: void on_gatewayButton_clicked(); private: Ui::MainBarWidget* ui; }; #endif // MAINBARWIDGET_H ================================================ FILE: desktop/bar/mainbarwidget.ui ================================================ MainBarWidget 0 0 724 195 Form 0 0 0 0 0 0 0 0 0 0 0 0 :/thedesk/desktop/icons/thedesk.svg:/thedesk/desktop/icons/thedesk.svg 32 32 true 0 0 Qt::Vertical 0 0 ChunkContainer QWidget
bar/chunkcontainer.h
1
TaskbarWidget QWidget
bar/taskbarwidget.h
1
================================================ FILE: desktop/bar/taskbarapplicationwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "taskbarapplicationwidget.h" #include #include #include #include #include #include #include #include #include #include #include struct TaskbarApplicationWidgetPrivate { ApplicationPointer app; uint desktop; ActionQuickWidget* windowListMenu; QuickWidgetContainer* windowListMenuContainer; QList trackedWindows; QMap actions; }; TaskbarApplicationWidget::TaskbarApplicationWidget(QString desktopEntry, uint desktop, QWidget* parent) : QPushButton(parent) { d = new TaskbarApplicationWidgetPrivate(); d->app = ApplicationPointer(new Application(desktopEntry)); d->desktop = desktop; this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); this->setCheckable(true); connect(DesktopWm::instance(), &DesktopWm::windowRemoved, this, [=](DesktopWmWindowPtr window) { removeTrackedWindow(window); }); connect(DesktopWm::instance(), &DesktopWm::activeWindowChanged, this, &TaskbarApplicationWidget::updateActive); connect(this, &TaskbarApplicationWidget::clicked, this, [=] { if (d->trackedWindows.count() == 1) { d->trackedWindows.first()->activate(); } else { if (!d->windowListMenuContainer->isShowing()) d->windowListMenuContainer->showContainer(); } updateActive(); }); this->setIconSize(SC_DPI_T(QSize(32, 32), QSize)); d->windowListMenuContainer = new QuickWidgetContainer(this); d->windowListMenu = new ActionQuickWidget(d->windowListMenuContainer); d->windowListMenuContainer->setQuickWidget(d->windowListMenu); // connect(d->windowListMenu, &ActionQuickWidget::done, d->menuContainer, &QuickWidgetContainer::hideContainer); updateIcon(); } TaskbarApplicationWidget::~TaskbarApplicationWidget() { delete d; } void TaskbarApplicationWidget::trackWindow(DesktopWmWindowPtr window) { if (d->trackedWindows.contains(window)) return; QAction* action = new QAction(this); action->setText(window->title()); connect(window, &DesktopWmWindow::titleChanged, action, [=] { action->setText(window->title()); }); connect(action, &QAction::triggered, window, [=] { window->activate(); }); d->actions.insert(window, action); d->windowListMenu->addAction(action); d->trackedWindows.append(window); updateIcon(); updateActive(); } void TaskbarApplicationWidget::removeTrackedWindow(DesktopWmWindowPtr window) { if (!d->trackedWindows.contains(window)) return; window->disconnect(this); d->trackedWindows.removeOne(window); QAction* action = d->actions.take(window); d->windowListMenu->removeAction(action); action->deleteLater(); updateIcon(); updateActive(); if (d->trackedWindows.isEmpty()) emit windowsRemoved(); } QList TaskbarApplicationWidget::trackedWindows() { return d->trackedWindows; } void TaskbarApplicationWidget::setColor(QColor color) { QPalette pal = this->palette(); pal.setColor(QPalette::Button, color); this->setPalette(pal); } void TaskbarApplicationWidget::resizeEvent(QResizeEvent* event) { this->setFixedWidth(this->height()); } void TaskbarApplicationWidget::updateIcon() { if (d->app->isValid()) { this->setIcon(d->app->icon()); } else if (!d->trackedWindows.isEmpty()) { this->setIcon(d->trackedWindows.first()->icon()); } else { this->setIcon(QIcon::fromTheme("generic-app")); } emit iconChanged(); } void TaskbarApplicationWidget::updateActive() { this->setChecked(d->trackedWindows.contains(DesktopWm::activeWindow())); } void TaskbarApplicationWidget::contextMenuEvent(QContextMenuEvent* event) { auto menu = new QMenu(this); if (d->trackedWindows.count() == 1) { auto win = d->trackedWindows.constFirst(); menu->addSection(tr("For %1").arg(QLocale().quoteString(win->title()))); QMenu* desktopsMenu = new QMenu(menu); desktopsMenu->setTitle(tr("Move to desktop")); auto desktopsGroup = new QActionGroup(desktopsMenu); desktopsGroup->setExclusive(true); auto allDesktopsAction = desktopsMenu->addAction(tr("All Desktops"), [win] { win->moveToDesktop(UINT_MAX); }); desktopsGroup->addAction(allDesktopsAction); allDesktopsAction->setCheckable(true); if (win->desktop() == UINT_MAX) allDesktopsAction->setChecked(true); desktopsMenu->addSeparator(); for (auto i = 0; i < DesktopWm::desktops().count() - 1; i++) { auto desktopName = DesktopWm::desktops().at(i); auto action = desktopsMenu->addAction(desktopName, [win, i] { win->moveToDesktop(i); }); desktopsGroup->addAction(action); action->setCheckable(true); if (i == win->desktop()) action->setChecked(true); } desktopsMenu->addSeparator(); desktopsMenu->addAction(QIcon::fromTheme("list-add"), tr("New Desktop"), [win] { win->moveToDesktop(DesktopWm::desktops().count() - 1); }); menu->addMenu(desktopsMenu); menu->addAction(QIcon::fromTheme("window-close"), tr("Close"), this, [win] { win->close(); }); } else { if (d->app->isValid()) { menu->addSection(tr("For %n %1 windows", nullptr, d->trackedWindows.count()).arg(QLocale().quoteString(d->app->getProperty("Name").toString()))); } else { menu->addSection(tr("For %n windows", nullptr, d->trackedWindows.count())); } menu->addAction(QIcon::fromTheme("application-exit"), tr("Close All"), this, [this] { for (auto win : d->trackedWindows) { win->close(); } }); } auto locker = StateManager::barManager()->acquireLock(); connect(menu, &QMenu::aboutToHide, this, [locker, menu] { locker->unlock(); menu->deleteLater(); }); menu->popup(event->globalPos()); } ================================================ FILE: desktop/bar/taskbarapplicationwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef TASKBARAPPLICATIONWIDGET_H #define TASKBARAPPLICATIONWIDGET_H #include class DesktopWmWindow; typedef QPointer DesktopWmWindowPtr; struct TaskbarApplicationWidgetPrivate; class TaskbarApplicationWidget : public QPushButton { Q_OBJECT public: explicit TaskbarApplicationWidget(QString desktopEntry, uint desktop, QWidget* parent = nullptr); ~TaskbarApplicationWidget(); void trackWindow(DesktopWmWindowPtr window); void removeTrackedWindow(DesktopWmWindowPtr window); QList trackedWindows(); void setColor(QColor color); signals: void iconChanged(); void windowsRemoved(); private: TaskbarApplicationWidgetPrivate* d; void resizeEvent(QResizeEvent* event); void updateIcon(); void updateActive(); // QWidget interface protected: void contextMenuEvent(QContextMenuEvent *event); }; #endif // TASKBARAPPLICATIONWIDGET_H ================================================ FILE: desktop/bar/taskbardesktopwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "taskbardesktopwidget.h" #include "ui_taskbardesktopwidget.h" #include "taskbarapplicationwidget.h" #include #include #include #include struct TaskbarDesktopWidgetPrivate { QMap applicationWidgets; QList applicationWidgetOrder; uint desktop; QColor color; tVariantAnimation* progressAnim; const QRgb colors[6] = { 0x0000c8, 0x006400, 0x640000, 0xff6400, 0x0064ff, 0x6400ff}; }; TaskbarDesktopWidget::TaskbarDesktopWidget(uint desktop, QWidget* parent) : QWidget(parent), ui(new Ui::TaskbarDesktopWidget) { ui->setupUi(this); d = new TaskbarDesktopWidgetPrivate(); d->desktop = desktop; d->color = QColor::fromRgb(d->colors[desktop % 6]); d->progressAnim = new tVariantAnimation(); d->progressAnim->setStartValue(0.0); d->progressAnim->setEndValue(1.0); d->progressAnim->setDuration(250); d->progressAnim->setEasingCurve(QEasingCurve::OutCubic); connect(d->progressAnim, &tVariantAnimation::valueChanged, this, &TaskbarDesktopWidget::updateAnimation); connect(d->progressAnim, &tVariantAnimation::finished, this, &TaskbarDesktopWidget::finishAnimation); if (DesktopWm::currentDesktop() == d->desktop) d->progressAnim->setCurrentTime(d->progressAnim->duration()); finishAnimation(); connect(DesktopWm::instance(), &DesktopWm::currentDesktopChanged, this, &TaskbarDesktopWidget::updateDesktop); connect(DesktopWm::instance(), &DesktopWm::windowAdded, this, &TaskbarDesktopWidget::windowAdded); connect(DesktopWm::instance(), &DesktopWm::windowRemoved, this, &TaskbarDesktopWidget::windowRemoved); for (DesktopWmWindowPtr window : DesktopWm::openWindows()) { this->windowAdded(window); } QPalette pal = ui->desktopOverviewButton->palette(); pal.setColor(QPalette::Button, d->color); ui->desktopOverviewButton->setPalette(pal); ui->desktopOverviewButton->setIconSize(SC_DPI_T(QSize(32, 32), QSize)); updateOverviewButtonIcon(); } TaskbarDesktopWidget::~TaskbarDesktopWidget() { delete d; delete ui; } void TaskbarDesktopWidget::moveDesktop(uint newDesktop) { d->desktop = newDesktop; QList windowsToMove; for (TaskbarApplicationWidget* widget : d->applicationWidgetOrder) { windowsToMove.append(widget->trackedWindows()); } for (DesktopWmWindowPtr window : windowsToMove) { window->moveToDesktop(newDesktop); } } void TaskbarDesktopWidget::windowAdded(DesktopWmWindowPtr window) { connect(window, &DesktopWmWindow::desktopChanged, this, [this, window] { if (window->isOnDesktop(d->desktop) && window->shouldShowInTaskbar()) { registerOnDesktop(window); } else { deregisterFromDesktop(window); } }); if (window->isOnDesktop(d->desktop) && window->shouldShowInTaskbar()) registerOnDesktop(window); } void TaskbarDesktopWidget::windowRemoved(DesktopWmWindowPtr window) { deregisterFromDesktop(window); } void TaskbarDesktopWidget::registerOnDesktop(DesktopWmWindowPtr window) { QString desktopEntry = QString::number(window->pid()); if (window->application()) desktopEntry = window->application()->desktopEntry(); TaskbarApplicationWidget* widget; if (d->applicationWidgets.contains(desktopEntry)) { widget = d->applicationWidgets.value(desktopEntry); } else { widget = new TaskbarApplicationWidget(desktopEntry, d->desktop, this); widget->setColor(d->color); connect(widget, &TaskbarApplicationWidget::iconChanged, this, &TaskbarDesktopWidget::updateOverviewButtonIcon); connect(widget, &TaskbarApplicationWidget::windowsRemoved, this, [=] { d->applicationWidgets.remove(desktopEntry); d->applicationWidgetOrder.removeOne(widget); ui->applicationsLayout->removeWidget(widget); widget->deleteLater(); updateOverviewButtonIcon(); }); ui->applicationsLayout->addWidget(widget); d->applicationWidgets.insert(desktopEntry, widget); d->applicationWidgetOrder.append(widget); } widget->trackWindow(window); updateOverviewButtonIcon(); } void TaskbarDesktopWidget::deregisterFromDesktop(DesktopWmWindowPtr window) { QString desktopEntry = QString::number(window->pid()); if (window->application()) desktopEntry = window->application()->desktopEntry(); if (d->applicationWidgets.contains(desktopEntry)) { TaskbarApplicationWidget* widget = d->applicationWidgets.value(desktopEntry); widget->removeTrackedWindow(window); } } void TaskbarDesktopWidget::updateOverviewButtonIcon() { QPixmap pixmap(SC_DPI_T(QSize(32, 32), QSize)); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); for (int i = 0; i < 4; i++) { if (d->applicationWidgetOrder.count() <= i) continue; QRect boxGeometry; boxGeometry.setSize(SC_DPI_T(QSize(16, 16), QSize)); boxGeometry.moveTopLeft(QPoint(SC_DPI(16) * (i % 2), SC_DPI(16) * (i / 2))); QRect geometry; geometry.setSize(SC_DPI_T(QSize(14, 14), QSize)); geometry.moveCenter(boxGeometry.center()); if (i == 3 && d->applicationWidgetOrder.count() > 4) { QFont font = this->font(); font.setPixelSize(geometry.height()); painter.setFont(font); painter.setPen(this->palette().color(QPalette::ButtonText)); painter.drawText(geometry, Qt::AlignCenter, QStringLiteral("%1%2").arg(QLocale().positiveSign()).arg(d->applicationWidgetOrder.count() - 3)); } else { QPixmap icon(d->applicationWidgetOrder.at(i)->icon().pixmap(geometry.size())); painter.drawPixmap(geometry, icon); } } ui->desktopOverviewButton->setIcon(QIcon(pixmap)); } void TaskbarDesktopWidget::updateDesktop() { if (DesktopWm::currentDesktop() == d->desktop && d->progressAnim->currentValue().toReal() < 0.5) { d->progressAnim->setDirection(tVariantAnimation::Forward); d->progressAnim->start(); } else if (DesktopWm::currentDesktop() != d->desktop && d->progressAnim->currentValue().toReal() > 0.5) { d->progressAnim->setDirection(tVariantAnimation::Backward); d->progressAnim->start(); } } void TaskbarDesktopWidget::updateAnimation() { ui->applicationsWidget->setFixedWidth(ui->applicationsWidget->sizeHint().width() * d->progressAnim->currentValue().toReal()); ui->desktopOverviewButton->setFixedWidth(this->height() * (1 - d->progressAnim->currentValue().toReal())); } void TaskbarDesktopWidget::finishAnimation() { if (d->progressAnim->currentValue().toReal() > 0.5) { ui->applicationsWidget->setFixedWidth(QWIDGETSIZE_MAX); ui->desktopOverviewButton->setFixedWidth(0); } else { ui->applicationsWidget->setFixedWidth(0); ui->desktopOverviewButton->setFixedWidth(this->height()); } } void TaskbarDesktopWidget::on_desktopOverviewButton_clicked() { DesktopWm::setCurrentDesktop(d->desktop); } void TaskbarDesktopWidget::resizeEvent(QResizeEvent* event) { if (d->progressAnim->state() == tVariantAnimation::Running) { updateAnimation(); } else { finishAnimation(); } } ================================================ FILE: desktop/bar/taskbardesktopwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef TASKBARDESKTOPWIDGET_H #define TASKBARDESKTOPWIDGET_H #include namespace Ui { class TaskbarDesktopWidget; } class DesktopWmWindow; typedef QPointer DesktopWmWindowPtr; struct TaskbarDesktopWidgetPrivate; class TaskbarDesktopWidget : public QWidget { Q_OBJECT public: explicit TaskbarDesktopWidget(uint desktop, QWidget* parent = nullptr); ~TaskbarDesktopWidget(); void moveDesktop(uint newDesktop); private slots: void on_desktopOverviewButton_clicked(); private: Ui::TaskbarDesktopWidget* ui; TaskbarDesktopWidgetPrivate* d; void resizeEvent(QResizeEvent* event); void windowAdded(DesktopWmWindowPtr window); void windowRemoved(DesktopWmWindowPtr window); void registerOnDesktop(DesktopWmWindowPtr window); void deregisterFromDesktop(DesktopWmWindowPtr window); void updateOverviewButtonIcon(); void updateDesktop(); void updateAnimation(); void finishAnimation(); }; #endif // TASKBARDESKTOPWIDGET_H ================================================ FILE: desktop/bar/taskbardesktopwidget.ui ================================================ TaskbarDesktopWidget 0 0 255 48 Form 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ================================================ FILE: desktop/bar/taskbarwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "taskbarwidget.h" #include "ui_taskbarwidget.h" #include "taskbardesktopwidget.h" #include #include #include #include #include #include struct TaskbarWidgetPrivate { QList desktopWidgets; }; TaskbarWidget::TaskbarWidget(QWidget* parent) : QWidget(parent), ui(new Ui::TaskbarWidget) { ui->setupUi(this); d = new TaskbarWidgetPrivate(); // connect(DesktopWm::instance(), &DesktopWm::windowAdded, this, &TaskbarWidget::addWindow); // connect(DesktopWm::instance(), &DesktopWm::windowRemoved, this, &TaskbarWidget::removeWindow); // connect(DesktopWm::instance(), &DesktopWm::activeWindowChanged, this, &TaskbarWidget::activeWindowChanged); // for (DesktopWmWindowPtr window : DesktopWm::openWindows()) { // this->addWindow(window); // } connect(DesktopWm::instance(), &DesktopWm::currentDesktopChanged, this, &TaskbarWidget::updateDesktop); connect(DesktopWm::instance(), &DesktopWm::desktopCountChanged, this, &TaskbarWidget::updateDesktop); connect(DesktopWm::instance(), &DesktopWm::currentDesktopChanged, this, &TaskbarWidget::normaliseDesktops); connect(DesktopWm::instance(), &DesktopWm::desktopCountChanged, this, &TaskbarWidget::normaliseDesktops); connect(DesktopWm::instance(), &DesktopWm::windowAdded, this, &TaskbarWidget::addWindow); connect(DesktopWm::instance(), &DesktopWm::windowRemoved, this, &TaskbarWidget::removeWindow); // TODO: Move to window manager connect(GestureDaemon::instance(), &GestureDaemon::gestureBegin, this, [=](GestureInteractionPtr gesture) { if (gesture->isValidInteraction(GestureTypes::Swipe, GestureTypes::Left, 4)) { connect(gesture.data(), &GestureInteraction::interactionEnded, this, [=] { if (gesture->extrapolatePercentage(100) > 0.7 && DesktopWm::currentDesktop() != DesktopWm::desktops().length() - 1) { DesktopWm::setCurrentDesktop(DesktopWm::currentDesktop() + 1); } }); } else if (gesture->isValidInteraction(GestureTypes::Swipe, GestureTypes::Right, 4)) { connect(gesture.data(), &GestureInteraction::interactionEnded, this, [=] { if (gesture->extrapolatePercentage(100) > 0.7 && DesktopWm::currentDesktop() != 0) { DesktopWm::setCurrentDesktop(DesktopWm::currentDesktop() - 1); } }); } }); ui->lastDesktopButton->setIconSize(SC_DPI_T(QSize(24, 24), QSize)); ui->lastDesktopButton->setVisible(DesktopWm::supportsSetNumDesktops()); normaliseDesktops(); updateDesktop(); } TaskbarWidget::~TaskbarWidget() { delete d; delete ui; d = nullptr; } void TaskbarWidget::addWindow(DesktopWmWindowPtr window) { connect(window, &DesktopWmWindow::desktopChanged, this, &TaskbarWidget::normaliseDesktops); // Race condition? QTimer::singleShot(500, this, [=] { normaliseDesktops(); }); } void TaskbarWidget::removeWindow(DesktopWmWindowPtr window) { // Race condition? QTimer::singleShot(500, this, [=] { normaliseDesktops(); }); } void TaskbarWidget::activeWindowChanged() { } void TaskbarWidget::normaliseDesktops() { // Ensure there is a taskbar desktop widget for every desktop - 1 for (int i = 0; i < DesktopWm::desktops().count() - 1; i++) { if (d->desktopWidgets.count() == i) { // Add another widget TaskbarDesktopWidget* widget = new TaskbarDesktopWidget(i); ui->desktopsLayout->addWidget(widget); d->desktopWidgets.append(widget); } } // Remove any extraenous desktop widgets while (d->desktopWidgets.count() > DesktopWm::desktops().count() - 1) { TaskbarDesktopWidget* widget = d->desktopWidgets.takeLast(); ui->desktopsLayout->removeWidget(widget); widget->deleteLater(); } // Go through each desktop to find any that need to be removed for (int i = 0; i < DesktopWm::desktops().count() - 1; i++) { if (DesktopWm::currentDesktop() == static_cast(i)) continue; bool haveWindows = false; for (auto window : DesktopWm::windowsOnDesktop(i)) { if (window->desktop() != UINT_MAX) haveWindows = true; } if (haveWindows) continue; // This desktop needs to be removed // Shuffle all of the windows from the desktops in front down for (int j = i + 1; j < DesktopWm::desktops().count() - 1; j++) { d->desktopWidgets.at(j)->moveDesktop(j - 1); } // Remove the last desktop DesktopWm::setNumDesktops(DesktopWm::desktops().count() - 1); // Normalise and check again normaliseDesktops(); return; } // Ensure that there is an empty desktop at the end bool haveWindows = false; for (auto window : DesktopWm::windowsOnDesktop(DesktopWm::desktops().count() - 1)) { if (window->desktop() != UINT_MAX) haveWindows = true; } if (haveWindows) { // Add an extra desktop DesktopWm::setNumDesktops(DesktopWm::desktops().count() + 1); // Normalise and check again normaliseDesktops(); return; } } void TaskbarWidget::updateDesktop() { // Race condition? QTimer::singleShot(500, this, [=] { ui->lastDesktopButton->setChecked(DesktopWm::currentDesktop() == DesktopWm::desktops().count() - 1); }); } void TaskbarWidget::on_lastDesktopButton_clicked() { DesktopWm::setCurrentDesktop(DesktopWm::desktops().count() - 1); } void TaskbarWidget::resizeEvent(QResizeEvent* event) { ui->lastDesktopButton->setFixedWidth(this->height()); } ================================================ FILE: desktop/bar/taskbarwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef TASKBARWIDGET_H #define TASKBARWIDGET_H #include namespace Ui { class TaskbarWidget; } class DesktopWmWindow; typedef QPointer DesktopWmWindowPtr; struct TaskbarWidgetPrivate; class TaskbarWidget : public QWidget { Q_OBJECT public: explicit TaskbarWidget(QWidget* parent = nullptr); ~TaskbarWidget(); private slots: void on_lastDesktopButton_clicked(); private: Ui::TaskbarWidget* ui; TaskbarWidgetPrivate* d; void resizeEvent(QResizeEvent* event); void addWindow(DesktopWmWindowPtr window); void removeWindow(DesktopWmWindowPtr window); void activeWindowChanged(); void normaliseDesktops(); void updateDesktop(); }; #endif // TASKBARWIDGET_H ================================================ FILE: desktop/bar/taskbarwidget.ui ================================================ TaskbarWidget 0 0 400 23 Form 0 0 0 0 0 0 0 0 true Qt::Horizontal 395 20 ================================================ FILE: desktop/cli/commandline.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "commandline.h" #include #include #include "plugins/pluginmanager.h" #include "server/sessionserver.h" CommandLine::CommandLine(QObject* parent) : QObject(parent) { } #include int CommandLine::parse(QStringList args) { QTextStream stream(stdout); QCommandLineParser parser; QCommandLineOption safeOption("safe", tr("Start theDesk in Safe Mode")); parser.addOption(safeOption); QCommandLineOption serverOption("sessionserver", tr("Internal use; the path to a local socket to communicate with the session manager"), tr("path")); parser.addOption(serverOption); QCommandLineOption helpOption = parser.addHelpOption(); QCommandLineOption versionOption = parser.addVersionOption(); if (!parser.parse(args)) { stream << parser.errorText() << "\n"; return 1; } if (parser.isSet(helpOption)) { stream << parser.helpText(); return 0; } if (parser.isSet(versionOption)) { parser.showVersion(); } if (parser.isSet(safeOption)) { PluginManager::instance()->setSafeMode(true); } if (!parser.value(serverOption).isEmpty()) { //Connect to the session server SessionServer::instance()->setServerPath(parser.value(serverOption)); } return -1; } ================================================ FILE: desktop/cli/commandline.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef COMMANDLINE_H #define COMMANDLINE_H #include class CommandLine : public QObject { Q_OBJECT public: explicit CommandLine(QObject* parent = nullptr); static int parse(QStringList args); signals: }; #endif // COMMANDLINE_H ================================================ FILE: desktop/common/common.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "common.h" int Common::getInsertionIndex(QStringList preferredOrder, QStringList currentItems, QString item) { //First, check to see if there is a preferred order for this item if (!preferredOrder.contains(item)) { //No preferred order so just add it at the end return -1; } //Find where this item is supposed to go int beforeIndex = preferredOrder.indexOf(item) - 1; if (beforeIndex == -1) { //Add this item at the beginning return 0; } //Iterate over the currently loaded items and insert the item at the correct place QStringList itemsBefore = preferredOrder.mid(0, beforeIndex + 1); for (int i = currentItems.count() - 1; i >= 0; i--) { if (itemsBefore.contains(currentItems.at(i))) { return i + 1; } } //None of the other items were found so just add it at the beginning return 0; } ================================================ FILE: desktop/common/common.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef COMMON_H #define COMMON_H #include namespace Common { /** * Given a list of items, find the correct index to insert this item into * * @param preferredOrder The preferred order of items * @param currentItems The items that are currently in the layout * @param item The name of the current item * @return An index, or -1 to add to the end of the layout */ int getInsertionIndex(QStringList preferredOrder, QStringList currentItems, QString item); } #endif // COMMON_H ================================================ FILE: desktop/crash/crashhandling.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "crashhandling.h" #include #include #include #include #include "plugins/pluginmanager.h" namespace CrashHandling { void catchSignal(int sig); } void CrashHandling::prepareCrashHandler() { signal(SIGSEGV, CrashHandling::catchSignal); signal(SIGBUS, CrashHandling::catchSignal); signal(SIGFPE, CrashHandling::catchSignal); } void CrashHandling::catchSignal(int sig) { const QMap signalNames = { {SIGSEGV, "SIGSEGV"}, {SIGBUS, "SIGBUS"}, {SIGFPE, "SIGFPE"} }; QTextStream output(stderr); output << "----- BEGIN CRASH HANDLER -----\n"; output << "THEDESK-TRAP: Fatal Signal: " << signalNames.value(sig) << "\n"; output << "THEDESK-TRAP: \n"; output << "THEDESK-TRAP: --- LOADED PLUGINS ---\n"; for (QUuid plugin : PluginManager::instance()->loadedPlugins()) { output << "THEDESK-TRAP: " << plugin.toString() << "\n"; } output << "THEDESK-TRAP: \n"; output << "THEDESK-TRAP: --- BACKTRACE ---\n"; QStringList backtrace = tApplication::exportBacktrace(); for (QString line : backtrace) { output << "THEDESK-TRAP: " << line << "\n"; } output.flush(); signal(sig, SIG_DFL); raise(sig); } ================================================ FILE: desktop/crash/crashhandling.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CRASHHANDLING_H #define CRASHHANDLING_H namespace CrashHandling { void prepareCrashHandler(); } #endif // CRASHHANDLING_H ================================================ FILE: desktop/desktop.pro ================================================ QT += core gui tdesktopenvironment network multimedia multimediawidgets quickwidgets greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = thedesk CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) QMAKE_POST_LINK += $$QMAKE_COPY_DIR $$quote($$PWD/translations) $$shell_quote($$OUT_PWD) && \ $$QMAKE_COPY $$quote($$PWD/defaults.conf) $$shell_quote($$OUT_PWD) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ background/background.cpp \ bar/barwindow.cpp \ bar/chunkcontainer.cpp \ bar/currentappwidget.cpp \ bar/currentappwidgetmenu.cpp \ bar/mainbarwidget.cpp \ bar/taskbarapplicationwidget.cpp \ bar/taskbardesktopwidget.cpp \ bar/taskbarwidget.cpp \ cli/commandline.cpp \ crash/crashhandling.cpp \ gateway/appsearchprovider.cpp \ gateway/appselectionmodel.cpp \ gateway/appselectionmodellistdelegate.cpp \ gateway/gateway.cpp \ gateway/gatewaysearchmodel.cpp \ gateway/gatewaysearchmodeldelegate.cpp \ gateway/maingatewaywidget.cpp \ gateway/searchresultswidget.cpp \ main.cpp \ run/rundialog.cpp \ session/endsession.cpp \ session/endsessionbutton.cpp \ statuscenter/leftpanedelegate.cpp \ statuscenter/statuscenter.cpp \ statuscenter/statuscenterleftpane.cpp \ statuscenter/statuscenterquickswitch.cpp \ systemsettings/about/about.cpp \ systemsettings/about/acknowledgements.cpp \ systemsettings/about/changehostnamepopover.cpp \ systemsettings/pluginmanagement/managepluginpopover.cpp \ systemsettings/pluginmanagement/pluginitemdelegate.cpp \ systemsettings/pluginmanagement/pluginmanagement.cpp \ systemsettings/pluginmanagement/pluginmodel.cpp \ systemsettings/recovery/recovery.cpp \ systemsettings/systemsettings.cpp \ systemsettings/systemsettingsleftpane.cpp HEADERS += \ background/background.h \ bar/barwindow.h \ bar/chunkcontainer.h \ bar/currentappwidget.h \ bar/currentappwidgetmenu.h \ bar/mainbarwidget.h \ bar/taskbarapplicationwidget.h \ bar/taskbardesktopwidget.h \ bar/taskbarwidget.h \ cli/commandline.h \ crash/crashhandling.h \ gateway/appsearchprovider.h \ gateway/appselectionmodel.h \ gateway/appselectionmodellistdelegate.h \ gateway/gateway.h \ gateway/gatewaysearchmodel.h \ gateway/gatewaysearchmodeldelegate.h \ gateway/maingatewaywidget.h \ gateway/searchresultswidget.h \ run/rundialog.h \ session/endsession.h \ session/endsessionbutton.h \ statuscenter/leftpanedelegate.h \ statuscenter/statuscenter.h \ statuscenter/statuscenterleftpane.h \ statuscenter/statuscenterquickswitch.h \ systemsettings/about/about.h \ systemsettings/about/acknowledgements.h \ systemsettings/about/changehostnamepopover.h \ systemsettings/pluginmanagement/managepluginpopover.h \ systemsettings/pluginmanagement/pluginitemdelegate.h \ systemsettings/pluginmanagement/pluginmanagement.h \ systemsettings/pluginmanagement/pluginmodel.h \ systemsettings/recovery/recovery.h \ systemsettings/systemsettings.h \ systemsettings/systemsettingsleftpane.h FORMS += \ background/background.ui \ bar/barwindow.ui \ bar/chunkcontainer.ui \ bar/currentappwidget.ui \ bar/currentappwidgetmenu.ui \ bar/mainbarwidget.ui \ bar/taskbardesktopwidget.ui \ bar/taskbarwidget.ui \ gateway/gateway.ui \ gateway/maingatewaywidget.ui \ gateway/searchresultswidget.ui \ run/rundialog.ui \ session/endsession.ui \ statuscenter/statuscenter.ui \ statuscenter/statuscenterleftpane.ui \ statuscenter/statuscenterquickswitch.ui \ systemsettings/about/about.ui \ systemsettings/about/acknowledgements.ui \ systemsettings/about/changehostnamepopover.ui \ systemsettings/pluginmanagement/managepluginpopover.ui \ systemsettings/pluginmanagement/pluginmanagement.ui \ systemsettings/recovery/recovery.ui \ systemsettings/systemsettings.ui \ systemsettings/systemsettingsleftpane.ui unix { target.path = /usr/bin/ translations.files = translations/*.qm translations.path = /usr/share/thedesk/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/ media.files = media/ media.path = /usr/share/thedesk/ acknowledgements.files = acknowledgements.html acknowledgements.path = /usr/share/thedesk INSTALLS += target translations defaults media acknowledgements } DEFINES += SYSTEM_LIBRARY_DIRECTORY=\\\"$$THELIBS_INSTALL_LIB\\\" unix:!macx: LIBS += -L$$OUT_PWD/../libthedesk/ -lthedesk INCLUDEPATH += $$PWD/../libthedesk DEPENDPATH += $$PWD/../libthedesk RESOURCES += \ resources.qrc DISTFILES += \ acknowledgements.html \ defaults.conf \ onboarding/OnboardingVideoForm.qml ================================================ FILE: desktop/gateway/appsearchprovider.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "appsearchprovider.h" #include #include #include struct AppSearchProviderPrivate { }; AppSearchProvider::AppSearchProvider(QObject* parent) : GatewaySearchProvider(parent) { d = new AppSearchProviderPrivate(); } AppSearchProvider::~AppSearchProvider() { delete d; } tPromise>* AppSearchProvider::searchResults(QString query) { return TPROMISE_CREATE_SAME_THREAD(QList, { Q_UNUSED(rej) QList results; for (const QString& desktopEntry : Application::allApplications()) { ApplicationPointer a(new Application(desktopEntry)); // Make sure this app is good to be shown if (a->getProperty("Type", "").toString() != "Application") continue; if (a->getProperty("NoDisplay", false).toBool()) continue; if (!a->getStringList("OnlyShowIn", {"thedesk"}).contains("thedesk")) continue; if (a->getStringList("NotShowIn").contains("thedesk")) continue; QStringList possibleWords; possibleWords.append(a->getProperty("Name").toString()); possibleWords.append(a->getProperty("GenericName").toString()); possibleWords.append(a->getStringList("Keywords")); for (const QString& s : possibleWords) { if (s.contains(query, Qt::CaseInsensitive)) { results.append({ {"application", a->desktopEntry() }, {"mainText", a->getProperty("Name").toString()}, {"priority", 0 }, {"drawArrows", false } }); for (QString action : a->getStringList("Actions")) { results.append({ {"application", a->desktopEntry() }, {"action", action }, {"mainText", a->getProperty("Name").toString()}, {"priority", 0 }, {"drawArrows", false } }); } break; } } } // if (theLibsGlobal::searchInPath(query.split(" ")[0]).count() > 0) { // d->appsShown.append(ApplicationPointer(new Application({ // {"Name", query}, // {"Exec", query}, // {"GenericName", tr("Run Command")}, // {"Icon", "system-run"} // }))); // } res(results); }); } void AppSearchProvider::launch(QVariantMap data) { Application app(data.value("application").toString()); if (data.contains("action")) { app.launchAction(data.value("action").toString()); } else { app.launch(); } } void AppSearchProvider::paint(QPainter* painter, const QStyleOptionViewItem& option, const QVariantMap data) const { tPaintCalculator calculator = this->calculator(painter, option, data); calculator.setPainter(painter); painter->setFont(option.font); calculator.performPaint(); } QSize AppSearchProvider::sizeHint(const QStyleOptionViewItem& option, const QVariantMap data) const { // Application app(data.value("application").toString()); // int fontHeight = option.fontMetrics.height() * 2 + SC_DPI(14); // int iconHeight = SC_DPI(46); // return QSize(option.fontMetrics.horizontalAdvance(app.getProperty("Name").toString()), qMax(fontHeight, iconHeight)); return calculator(nullptr, option, data).sizeWithMargins().toSize(); } tPaintCalculator AppSearchProvider::calculator(QPainter* painter, const QStyleOptionViewItem& option, const QVariantMap data) const { Application app(data.value("application").toString()); tPaintCalculator calculator; calculator.setDrawBounds(option.rect); calculator.setLayoutDirection(option.direction); QString name; QString genericName; QPixmap icon; QRect iconRect; QRect textRect; QRect descRect; if (data.contains("action")) { QString action = data.value("action").toString(); name = app.getActionProperty(action, "Name").toString(); icon = app.actionIcon(action, SC_DPI_T(QSize(16, 16), QSize)); iconRect.setLeft(option.rect.left() + SC_DPI(12)); iconRect.setTop(option.rect.top() + SC_DPI(6)); iconRect.setSize(icon.size()); textRect.setHeight(option.fontMetrics.height()); textRect.setWidth(option.fontMetrics.horizontalAdvance(name) + 1); textRect.moveCenter(iconRect.center()); textRect.moveLeft(iconRect.right() + SC_DPI(6)); } else { name = app.getProperty("Name").toString(); genericName = app.getProperty("GenericName", tr("Application")).toString(); icon = app.icon(SC_DPI_T(QSize(32, 32), QSize)); iconRect.setLeft(option.rect.left() + SC_DPI(6)); iconRect.setTop(option.rect.top() + SC_DPI(6)); iconRect.setSize(icon.size()); textRect.setLeft(iconRect.right() + SC_DPI(6)); textRect.setTop(option.rect.top() + SC_DPI(6)); textRect.setBottom(option.rect.top() + option.fontMetrics.height() + SC_DPI(6)); textRect.setRight(option.rect.right() - SC_DPI(6)); descRect.setLeft(iconRect.right() + SC_DPI(6)); descRect.setTop(option.rect.top() + option.fontMetrics.height() + SC_DPI(8)); descRect.setBottom(option.rect.top() + option.fontMetrics.height() * 2 + SC_DPI(6)); descRect.setRight(option.rect.right() - SC_DPI(6)); } if (option.state & QStyle::State_Selected) { calculator.addRect(option.rect, [=](QRectF drawBounds) { painter->setPen(Qt::transparent); painter->setBrush(option.palette.color(QPalette::Highlight)); painter->drawRect(drawBounds); }); calculator.addRect(textRect, [=](QRectF drawBounds) { painter->setBrush(Qt::transparent); painter->setPen(option.palette.color(QPalette::HighlightedText)); painter->drawText(drawBounds, Qt::AlignLeading, name); }); calculator.addRect(descRect, [=](QRectF drawBounds) { painter->drawText(drawBounds, Qt::AlignLeading, genericName); }); } else if (option.state & QStyle::State_MouseOver) { calculator.addRect(option.rect, [=](QRectF drawBounds) { QColor col = option.palette.color(QPalette::Highlight); col.setAlpha(127); painter->setBrush(col); painter->setPen(Qt::transparent); painter->drawRect(drawBounds); }); calculator.addRect(textRect, [=](QRectF drawBounds) { painter->setBrush(Qt::transparent); painter->setPen(option.palette.color(QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, name); }); calculator.addRect(descRect, [=](QRectF drawBounds) { painter->setPen(option.palette.color(QPalette::Disabled, QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, genericName); }); } else { calculator.addRect(textRect, [=](QRectF drawBounds) { painter->setPen(option.palette.color(QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, name); }); calculator.addRect(descRect, [=](QRectF drawBounds) { painter->setPen(option.palette.color(QPalette::Disabled, QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, genericName); }); } calculator.addRect(iconRect, [=](QRectF drawBounds) { painter->drawPixmap(drawBounds.toRect(), icon); }); if (data.value("drawArrows", true).toBool()) { if (app.getStringList("Actions").count() > 0) { // Actions included QRect actionsRect; actionsRect.setWidth(SC_DPI(16)); actionsRect.setHeight(SC_DPI(16)); actionsRect.moveCenter(iconRect.center()); actionsRect.moveRight(option.rect.right() - SC_DPI(9)); calculator.addRect(actionsRect, [=](QRectF drawBounds) { painter->drawPixmap(drawBounds.toRect(), QIcon::fromTheme("arrow-right").pixmap(SC_DPI_T(QSize(16, 16), QSize))); }); } } return calculator; } ================================================ FILE: desktop/gateway/appsearchprovider.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef APPSEARCHPROVIDER_H #define APPSEARCHPROVIDER_H #include class tPaintCalculator; struct AppSearchProviderPrivate; class AppSearchProvider : public GatewaySearchProvider { Q_OBJECT public: explicit AppSearchProvider(QObject* parent = nullptr); ~AppSearchProvider(); tPromise>* searchResults(QString query); void launch(QVariantMap data); void paint(QPainter* painter, const QStyleOptionViewItem& option, const QVariantMap data) const; QSize sizeHint(const QStyleOptionViewItem& option, const QVariantMap data) const; tPaintCalculator calculator(QPainter* painter, const QStyleOptionViewItem& option, const QVariantMap data) const; signals: private: AppSearchProviderPrivate* d; }; #endif // APPSEARCHPROVIDER_H ================================================ FILE: desktop/gateway/appselectionmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "appselectionmodel.h" #include #include #include struct AppSelectionModelPrivate { QString category; QList apps; QList appsShown; }; AppSelectionModel::AppSelectionModel(QObject* parent) : QAbstractListModel(parent) { d = new AppSelectionModelPrivate(); connect(ApplicationDaemon::instance(), &ApplicationDaemon::appsUpdateRequired, this, &AppSelectionModel::updateData); updateData(); } AppSelectionModel::~AppSelectionModel() { delete d; } int AppSelectionModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return d->appsShown.count(); } QVariant AppSelectionModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); ApplicationPointer a = d->appsShown.at(index.row()); if (d->appsShown.count() > index.row()) { if (role == Qt::DisplayRole) { return a->getProperty("Name", a->desktopEntry()); } else if (role == Qt::DecorationRole) { // Cache the icon for smooth scrolling return a->icon(SC_DPI_T(QSize(32, 32), QSize)); } else if (role == Qt::UserRole) { // Description return a->getProperty("GenericName", tr("Application")); } else if (role == Qt::UserRole + 1) { // Pinned // return d->pinnedAppsList.contains(a->desktopEntry()); return false; } else if (role == Qt::UserRole + 2) { // Desktop Entry return a->desktopEntry(); } else if (role == Qt::UserRole + 3) { // App return QVariant::fromValue(a); } } return QVariant(); } void AppSelectionModel::filterCategory(QString category) { d->category = category; d->appsShown.clear(); // If there is no current category, show all apps if (category == "") { d->appsShown.append(d->apps); emit dataChanged(index(0), index(rowCount())); return; } for (ApplicationPointer app : qAsConst(d->apps)) { QStringList categories = app->getStringList("Categories"); if (categories.contains(category, Qt::CaseSensitive)) d->appsShown.append(app); } emit dataChanged(index(0), index(rowCount())); } void AppSelectionModel::updateData() { emit loading(); d->apps.clear(); struct ApplicationListReturnValue { QList apps; QMap appIcons; }; (new tPromise>([=](QString& error) { QList apps; QList normalApps; for (QString desktopEntry : Application::allApplications()) { ApplicationPointer a(new Application(desktopEntry)); // Make sure this app is good to be shown if (a->getProperty("Type", "").toString() != "Application") continue; if (a->getProperty("NoDisplay", false).toBool()) continue; if (!a->getStringList("OnlyShowIn", {"thedesk"}).contains("thedesk")) continue; if (a->getStringList("NotShowIn").contains("thedesk")) continue; normalApps.append(a); } std::sort(normalApps.begin(), normalApps.end(), [](const ApplicationPointer& a, const ApplicationPointer& b) -> bool { if (a->getProperty("Name").toString().localeAwareCompare(b->getProperty("Name").toString()) < 0) { return true; } else { return false; } }); apps.append(normalApps); return apps; }))->then([=](QList apps) { d->apps = apps; // Perform a category search to initialize the list filterCategory(d->category); emit ready(); }); } ================================================ FILE: desktop/gateway/appselectionmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef APPSELECTIONMODEL_H #define APPSELECTIONMODEL_H #include struct AppSelectionModelPrivate; class AppSelectionModel : public QAbstractListModel { Q_OBJECT public: explicit AppSelectionModel(QObject* parent = nullptr); ~AppSelectionModel() override; // Basic functionality: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; void filterCategory(QString category); signals: void loading(); void ready(); private: AppSelectionModelPrivate* d; void updateData(); }; #endif // APPSELECTIONMODEL_H ================================================ FILE: desktop/gateway/appselectionmodellistdelegate.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "appselectionmodellistdelegate.h" #include "appsearchprovider.h" #include #include #include AppSelectionModelListDelegate::AppSelectionModelListDelegate(QWidget* parent, bool drawArrows) : QStyledItemDelegate(parent) { this->drawArrows = drawArrows; } void AppSelectionModelListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { AppSearchProvider provider; return provider.paint(painter, option, { {"application", index.data(Qt::UserRole + 2).toString()}, {"drawArrows", this->drawArrows } }); } QSize AppSelectionModelListDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { AppSearchProvider provider; return provider.sizeHint(option, { {"application", index.data(Qt::UserRole + 2).toString()} }); } ================================================ FILE: desktop/gateway/appselectionmodellistdelegate.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef APPSELECTIONMODELLISTDELEGATE_H #define APPSELECTIONMODELLISTDELEGATE_H #include class AppSelectionModelListDelegate : public QStyledItemDelegate { Q_OBJECT public: AppSelectionModelListDelegate(QWidget* parent = nullptr, bool drawArrows = true); void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; private: bool drawArrows; }; #endif // APPSELECTIONMODELLISTDELEGATE_H ================================================ FILE: desktop/gateway/gateway.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "gateway.h" #include "ui_gateway.h" #include #include #include #include #include #include #include #include #include #include #include struct GatewayPrivate { Gateway* instance = nullptr; tVariantAnimation* width; GestureInteractionPtr lastGesture; }; GatewayPrivate* Gateway::d = new GatewayPrivate(); Gateway::Gateway() : QDialog(nullptr), ui(new Ui::Gateway) { ui->setupUi(this); ui->gatewayContainer->move(0, 0); connect(ui->gatewayContainer, &MainGatewayWidget::closeGateway, this, [=] { this->close(); }); d->width = new tVariantAnimation(); d->width->setDuration(500); connect(d->width, &tVariantAnimation::valueChanged, this, [=](QVariant value) { this->setFixedWidth(value.toInt()); auto* screen = ScreenDaemon::instance()->primayScreen(); QRect geometry; geometry.setHeight(this->height()); geometry.setWidth(value.toInt()); if (this->layoutDirection() == Qt::RightToLeft) { geometry.moveTopRight(screen->geometry().topRight()); } else { geometry.moveTopLeft(screen->geometry().topLeft()); } this->setGeometry(geometry); }); connect(d->width, &tVariantAnimation::finished, this, [=] { if (d->lastGesture && d->lastGesture->isActive()) return; if (this->geometry().width() == 0) { QDialog::hide(); ui->gatewayContainer->clearState(); } }); this->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); DesktopWm::setSystemWindow(this, DesktopWm::SystemWindowTypeMenu); this->setFixedWidth(0); connect(GestureDaemon::instance(), &GestureDaemon::gestureBegin, this, [=](GestureInteractionPtr interaction) { if (interaction->isValidInteraction(GestureTypes::Swipe, this->layoutDirection() == Qt::RightToLeft ? GestureTypes::Left : GestureTypes::Right, 3)) { trackGatewayOpenGesture(interaction); } else if (interaction->isValidInteraction(GestureTypes::Swipe, this->layoutDirection() == Qt::RightToLeft ? GestureTypes::Right : GestureTypes::Left, 3)) { trackGatewayCloseGesture(interaction); } }); ui->line->raise(); } void Gateway::resizeEvent(QResizeEvent* event) { ui->gatewayContainer->setFixedSize(ui->gatewayContainer->sizeHint().width(), this->height()); if (this->layoutDirection() == Qt::RightToLeft) { ui->gatewayContainer->move(1, 0); ui->line->setGeometry(0, 0, 1, this->height()); } else { ui->gatewayContainer->move(this->geometry().width() - ui->gatewayContainer->width() - 1, 0); ui->line->setGeometry(this->geometry().width() - 1, 0, 1, this->height()); } StateManager::gatewayManager()->setGatewayWidth(this->geometry().width()); } void Gateway::changeEvent(QEvent* event) { QDialog::changeEvent(event); switch (event->type()) { case QEvent::ActivationChange: if (!this->isActiveWindow()) this->close(); break; default:; } } void Gateway::trackGatewayOpenGesture(GestureInteractionPtr gesture) { if (this->isVisible()) return; // Capture this gesture! d->lastGesture = gesture; auto* screen = ScreenDaemon::instance()->primayScreen(); this->setFixedHeight(screen->geometry().height()); d->width->setEasingCurve(QEasingCurve::Linear); d->width->setCurrentTime(0); d->width->setStartValue(0); d->width->setEndValue(ui->gatewayContainer->sizeHint().width() + 1); connect(gesture.data(), &GestureInteraction::interactionUpdated, this, [=] { d->width->setCurrentTime(d->width->totalDuration() * gesture->percentage()); d->width->valueChanged(d->width->currentValue()); }); connect(gesture.data(), &GestureInteraction::interactionEnded, this, [=] { if (gesture->extrapolatePercentage(100) > 0.3) { show(); } else { close(); } }); QDialog::show(); } void Gateway::trackGatewayCloseGesture(GestureInteractionPtr gesture) { if (!this->isVisible()) return; // Capture this gesture! d->lastGesture = gesture; auto* screen = ScreenDaemon::instance()->primayScreen(); this->setFixedHeight(screen->geometry().height()); d->width->setEasingCurve(QEasingCurve::Linear); d->width->setCurrentTime(0); d->width->setStartValue(ui->gatewayContainer->sizeHint().width() + 1); d->width->setEndValue(0); connect(gesture.data(), &GestureInteraction::interactionUpdated, this, [=] { d->width->setCurrentTime(d->width->totalDuration() * gesture->percentage()); d->width->valueChanged(d->width->currentValue()); }); connect(gesture.data(), &GestureInteraction::interactionEnded, this, [=] { if (gesture->extrapolatePercentage(100) > 0.3) { close(); } else { show(); } }); } Gateway::~Gateway() { delete ui; } Gateway* Gateway::instance() { if (!d->instance) d->instance = new Gateway(); return d->instance; } void Gateway::setFixedHeight(int height) { QWidget::setFixedHeight(height); // Work around a Qt bug that causes the native window not to be updated on Wayland for some reason this->windowHandle()->setGeometry(this->geometry()); } void Gateway::setFixedWidth(int width) { QWidget::setFixedWidth(width); // Work around a Qt bug that causes the native window not to be updated on Wayland for some reason this->windowHandle()->setGeometry(this->geometry()); } void Gateway::show() { auto* screen = ScreenDaemon::instance()->primayScreen(); this->setFixedHeight(screen->geometry().height()); d->width->setEasingCurve(QEasingCurve::OutCubic); d->width->setStartValue(this->geometry().width()); d->width->setEndValue(ui->gatewayContainer->sizeHint().width() + 1); d->width->stop(); d->width->start(); QDialog::show(); QDialog::activateWindow(); ui->gatewayContainer->setFocus(); DesktopWm::setSystemWindow(this, DesktopWm::SystemWindowTypeMenu); } void Gateway::close() { d->width->setEasingCurve(QEasingCurve::OutCubic); d->width->setStartValue(this->geometry().width()); d->width->setEndValue(0); d->width->stop(); d->width->start(); } ================================================ FILE: desktop/gateway/gateway.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef GATEWAY_H #define GATEWAY_H #include #include namespace Ui { class Gateway; } struct GatewayPrivate; class Gateway : public QDialog { Q_OBJECT public: ~Gateway(); static Gateway* instance(); void setFixedHeight(int height); void setFixedWidth(int width); void show(); void close(); private: explicit Gateway(); Ui::Gateway* ui; static GatewayPrivate* d; void resizeEvent(QResizeEvent* event); void changeEvent(QEvent* event); void trackGatewayOpenGesture(GestureInteractionPtr gesture); void trackGatewayCloseGesture(GestureInteractionPtr gesture); }; #endif // GATEWAY_H ================================================ FILE: desktop/gateway/gateway.ui ================================================ Gateway 0 0 400 300 Dialog 50 20 120 80 370 80 1 61 1 16777215 Qt::Vertical MainGatewayWidget QWidget
gateway/maingatewaywidget.h
1
================================================ FILE: desktop/gateway/gatewaysearchmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "gatewaysearchmodel.h" #include #include #include struct GatewaySearchModelPrivate { QString query; QList currentItems; }; GatewaySearchModel::GatewaySearchModel(QObject* parent) : QAbstractListModel(parent) { d = new GatewaySearchModelPrivate(); } GatewaySearchModel::~GatewaySearchModel() { delete d; } void GatewaySearchModel::search(QString query) { d->currentItems.clear(); d->query = query; for (GatewaySearchProvider* searchProvider : StateManager::gatewayManager()->searchProviders()) { searchProvider->searchResults(query)->then([ = ](QList results) { if (d->query != query) return; QList endResults; for (QVariantMap result : results) { endResults.append({ {"provider", QVariant::fromValue(searchProvider)}, {"data", result}, {"priority", result.value("priority", 1)}, {"mainText", result.value("mainText", "")} }); } d->currentItems.append(endResults); //Sort the items std::stable_sort(d->currentItems.begin(), d->currentItems.end(), [ = ](const QVariantMap first, const QVariantMap second) { if (first.value("priority") == second.value("priority")) { return first.value("mainText").toString().localeAwareCompare(second.value("mainText").toString()) < 0; } return first.value("priority").toInt() < second.value("priority").toInt(); }); emit dataChanged(index(0), index(rowCount())); }); } } int GatewaySearchModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return d->currentItems.count(); } QVariant GatewaySearchModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); if (d->currentItems.length() <= index.row()) return QVariant(); switch (role) { case Qt::UserRole: return d->currentItems.at(index.row()).value("data"); case Qt::UserRole + 1: return d->currentItems.at(index.row()).value("provider"); } return QVariant(); } void GatewaySearchModel::launch(const QModelIndex& index) const { GatewaySearchProvider* provider = index.data(Qt::UserRole + 1).value(); provider->launch(index.data(Qt::UserRole).toMap()); } ================================================ FILE: desktop/gateway/gatewaysearchmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef GATEWAYSEARCHMODEL_H #define GATEWAYSEARCHMODEL_H #include struct GatewaySearchModelPrivate; class GatewaySearchModel : public QAbstractListModel { Q_OBJECT public: explicit GatewaySearchModel(QObject* parent = nullptr); ~GatewaySearchModel(); void search(QString query); // Basic functionality: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; void launch(const QModelIndex& index) const; private: GatewaySearchModelPrivate* d; }; #endif // GATEWAYSEARCHMODEL_H ================================================ FILE: desktop/gateway/gatewaysearchmodeldelegate.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "gatewaysearchmodeldelegate.h" #include GatewaySearchModelDelegate::GatewaySearchModelDelegate(QObject* parent) : QStyledItemDelegate(parent) { } void GatewaySearchModelDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { GatewaySearchProvider* provider = index.data(Qt::UserRole + 1).value(); return provider->paint(painter, option, index.data(Qt::UserRole).toMap()); } QSize GatewaySearchModelDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { GatewaySearchProvider* provider = index.data(Qt::UserRole + 1).value(); return provider->sizeHint(option, index.data(Qt::UserRole).toMap()); } ================================================ FILE: desktop/gateway/gatewaysearchmodeldelegate.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef GATEWAYSEARCHMODELDELEGATE_H #define GATEWAYSEARCHMODELDELEGATE_H #include class GatewaySearchModelDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit GatewaySearchModelDelegate(QObject* parent = nullptr); signals: // QAbstractItemDelegate interface public: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; }; #endif // GATEWAYSEARCHMODELDELEGATE_H ================================================ FILE: desktop/gateway/maingatewaywidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "maingatewaywidget.h" #include "ui_maingatewaywidget.h" #include #include #include #include #include "appselectionmodel.h" #include "appselectionmodellistdelegate.h" #include "session/endsession.h" #include #include #include #include "searchresultswidget.h" #include #include #include struct MainGatewayWidgetPrivate { AppSelectionModel* model; SearchResultsWidget* searchWidget; }; MainGatewayWidget::MainGatewayWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainGatewayWidget) { ui->setupUi(this); d = new MainGatewayWidgetPrivate(); d->model = new AppSelectionModel(this); connect(d->model, &AppSelectionModel::loading, this, [ = ] { ui->gatewayTypeStack->setCurrentWidget(ui->gatewayLoading); }); connect(d->model, &AppSelectionModel::ready, this, [ = ] { QTimer::singleShot(500, [ = ] { ui->gatewayTypeStack->setCurrentWidget(ui->gatewayList); }); }); ui->gatewayTypeStack->setCurrentWidget(ui->gatewayLoading); ui->gatewayTypeStack->setCurrentAnimation(tStackedWidget::Fade); ui->titleLabel->setBackButtonShown(true); ui->leftPane->setFixedWidth(SC_DPI(200)); // ui->usernameLabel->setText(tr("Hey, %1!").arg(DesktopWm::userDisplayName())); ui->usernameLabel->setText(DesktopWm::userDisplayName()); ui->appsList->setModel(d->model); ui->appsList->setItemDelegate(new AppSelectionModelListDelegate(this, true)); ui->appsList->setFocusProxy(ui->searchBox); QScroller::grabGesture(ui->appsList->viewport(), QScroller::LeftMouseButtonGesture); this->setFocusProxy(ui->searchBox); ui->endSessionButton->setFocusProxy(ui->searchBox); d->searchWidget = new SearchResultsWidget(ui->searchResultsContainer); d->searchWidget->move(0, 0); d->searchWidget->hide(); connect(d->searchWidget, &SearchResultsWidget::closeGateway, this, &MainGatewayWidget::closeGateway); connect(tScrim::scrimForWidget(ui->appContentsWidget), &tScrim::scrimClicked, this, [ = ] { ui->searchBox->setText(""); tScrim::scrimForWidget(ui->appContentsWidget)->hide(); d->searchWidget->hide(); }); QList> categories = { {"AudioVideo", tr("A/V")}, {"Development", tr("Development")}, {"Education", tr("Education")}, {"Game", tr("Games")}, {"Graphics", tr("Graphics")}, {"Network", tr("Networking")}, {"Office", tr("Office")}, {"Science", tr("Science")}, {"Utility", tr("Utilities")} }; std::sort(categories.begin(), categories.end(), [ = ](const QPair& first, const QPair& second) { return first.second.localeAwareCompare(second.second) < 0; }); for (const QPair& category : categories) { QPushButton* button = new QPushButton(this); button->setAutoExclusive(true); button->setCheckable(true); button->setText(category.second); connect(button, &QPushButton::toggled, this, [ = ](bool checked) { if (checked) d->model->filterCategory(category.first); }); ui->categoriesLayout->addWidget(button); } ui->searchBox->installEventFilter(this); } MainGatewayWidget::~MainGatewayWidget() { delete d; delete ui; } QSize MainGatewayWidget::sizeHint() const { QSize sizeHint = QWidget::sizeHint(); sizeHint.setWidth(SC_DPI(400)); sizeHint.setWidth(SC_DPI(700)); return sizeHint; } void MainGatewayWidget::clearState() { ui->searchBox->setText(""); tScrim::scrimForWidget(ui->appContentsWidget)->hide(); d->searchWidget->hide(); ui->allAppsButton->setChecked(true); } void MainGatewayWidget::on_searchBox_textEdited(const QString& arg1) { if (arg1.isEmpty()) { tScrim::scrimForWidget(ui->appContentsWidget)->hide(); d->searchWidget->hide(); } else { tScrim::scrimForWidget(ui->appContentsWidget)->show(); d->searchWidget->show(); } d->searchWidget->search(arg1); } void MainGatewayWidget::on_appsList_clicked(const QModelIndex& index) { int x = ui->appsList->mapFromGlobal(QCursor::pos()).x(); if ((this->layoutDirection() == Qt::RightToLeft && x < SC_DPI(32)) || (this->layoutDirection() == Qt::LeftToRight && x > ui->appsList->width() - SC_DPI(32))) { if (showActionMenu(index)) return; } launch(index); } void MainGatewayWidget::on_searchBox_returnPressed() { if (!ui->searchBox->text().isEmpty()) d->searchWidget->launchSelected(); } void MainGatewayWidget::launch(QModelIndex applicationIndex) { applicationIndex.data(Qt::UserRole + 3).value()->launch(); emit closeGateway(); } bool MainGatewayWidget::showActionMenu(QModelIndex applicationIndex) { ApplicationPointer application = applicationIndex.data(Qt::UserRole + 3).value(); if (application->getStringList("Actions").isEmpty()) return false; QMenu* menu = new QMenu(); menu->addSection(tr("Actions for %1").arg(QLocale().quoteString(application->getProperty("Name").toString()))); for (const QString& action : application->getStringList("Actions")) { menu->addAction(application->actionIcon(action), application->getActionProperty(action, "Name").toString(), this, [ = ] { application->launchAction(action); emit closeGateway(); }); } connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); QRect rect = ui->appsList->visualRect(applicationIndex); if (layoutDirection() == Qt::RightToLeft) { menu->popup(ui->appsList->mapToGlobal(rect.topLeft())); } else { menu->popup(ui->appsList->mapToGlobal(rect.topRight())); } return true; } void MainGatewayWidget::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } void MainGatewayWidget::resizeEvent(QResizeEvent* event) { d->searchWidget->setFixedWidth(this->width()); } void MainGatewayWidget::on_endSessionButton_clicked() { StateManager::instance()->powerManager()->showPowerOffConfirmation(); } void MainGatewayWidget::on_allAppsButton_toggled(bool checked) { if (checked) d->model->filterCategory(""); } void MainGatewayWidget::on_titleLabel_backButtonClicked() { emit closeGateway(); } void MainGatewayWidget::on_statusCenterButton_clicked() { StateManager::statusCenterManager()->show(); emit closeGateway(); } void MainGatewayWidget::on_systemSettingsButton_clicked() { StateManager::statusCenterManager()->show(); StateManager::statusCenterManager()->setPane("SystemSettings"); emit closeGateway(); } bool MainGatewayWidget::eventFilter(QObject* watched, QEvent* event) { if (watched == ui->searchBox) { if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Down) { if (ui->searchBox->text().isEmpty()) { QItemSelectionModel* selectionModel = ui->appsList->selectionModel(); int selectionRow = 0; if (selectionModel->hasSelection()) { int row = selectionModel->selectedIndexes().first().row(); if (row != d->model->rowCount() - 1) selectionRow = row + 1; } selectionModel->select(d->model->index(selectionRow), QItemSelectionModel::ClearAndSelect); ui->appsList->scrollTo(d->model->index(selectionRow), QListView::PositionAtCenter); } else { d->searchWidget->moveSelectionDown(); } return true; } else if (keyEvent->key() == Qt::Key_Up) { if (ui->searchBox->text().isEmpty()) { QItemSelectionModel* selectionModel = ui->appsList->selectionModel(); int selectionRow = d->model->rowCount() - 1; if (selectionModel->hasSelection()) { int row = selectionModel->selectedIndexes().first().row(); if (row != 0) selectionRow = row - 1; } selectionModel->select(d->model->index(selectionRow), QItemSelectionModel::ClearAndSelect); ui->appsList->scrollTo(d->model->index(selectionRow), QListView::PositionAtCenter); } else { d->searchWidget->moveSelectionUp(); } return true; } else if ((layoutDirection() == Qt::LeftToRight && keyEvent->key() == Qt::Key_Right) || (layoutDirection() == Qt::RightToLeft && keyEvent->key() == Qt::Key_Left)) { if (ui->searchBox->text().isEmpty()) { QItemSelectionModel* selectionModel = ui->appsList->selectionModel(); if (selectionModel->hasSelection()) { showActionMenu(selectionModel->selectedIndexes().first()); } return true; } } } } return false; } ================================================ FILE: desktop/gateway/maingatewaywidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MAINGATEWAYWIDGET_H #define MAINGATEWAYWIDGET_H #include namespace Ui { class MainGatewayWidget; } struct MainGatewayWidgetPrivate; class MainGatewayWidget : public QWidget { Q_OBJECT public: explicit MainGatewayWidget(QWidget* parent = nullptr); ~MainGatewayWidget(); QSize sizeHint() const; void clearState(); private slots: void on_searchBox_textEdited(const QString& arg1); void on_appsList_clicked(const QModelIndex& index); void on_searchBox_returnPressed(); void on_endSessionButton_clicked(); void on_allAppsButton_toggled(bool checked); void on_titleLabel_backButtonClicked(); void on_statusCenterButton_clicked(); void on_systemSettingsButton_clicked(); signals: void closeGateway(); private: Ui::MainGatewayWidget* ui; MainGatewayWidgetPrivate* d; void launch(QModelIndex applicationIndex); bool showActionMenu(QModelIndex applicationIndex); void changeEvent(QEvent* event); void resizeEvent(QResizeEvent* event); // QObject interface public: bool eventFilter(QObject* watched, QEvent* event); }; #endif // MAINGATEWAYWIDGET_H ================================================ FILE: desktop/gateway/maingatewaywidget.ui ================================================ MainGatewayWidget 0 0 405 570 Form 0 0 0 0 0 0 0 0 0 0 0 Gateway false Type to search... true 16777215 1 Qt::Horizontal 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 true CATEGORIES 9 All Apps true true true 16777215 1 Qt::Horizontal Status Center Qt::Vertical 20 353 1 16777215 Qt::Vertical 0 0 0 0 0 QFrame::NoFrame Qt::Vertical 20 64 15 Preparing the Gateway... Qt::AlignCenter Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Vertical 20 63 16777215 1 Qt::Horizontal 0 0 20 TextLabel Qt::Horizontal 40 20 System Settings true Qt::NoFocus End Session .. true tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: desktop/gateway/searchresultswidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "searchresultswidget.h" #include "ui_searchresultswidget.h" #include #include "gatewaysearchmodel.h" #include "gatewaysearchmodeldelegate.h" struct SearchResultsWidgetPrivate { GatewaySearchModel* model; int maxHeight = 0; }; SearchResultsWidget::SearchResultsWidget(QWidget* parent) : QWidget(parent), ui(new Ui::SearchResultsWidget) { ui->setupUi(this); d = new SearchResultsWidgetPrivate(); d->model = new GatewaySearchModel(); ui->listView->setModel(d->model); ui->listView->setItemDelegate(new GatewaySearchModelDelegate(this)); connect(d->model, &GatewaySearchModel::dataChanged, this, [ = ] { int height = 1; for (int i = 0; i < d->model->rowCount(); i++) { height += ui->listView->sizeHintForRow(i); } if (height > this->parentWidget()->height()) height = this->parentWidget()->height();// + 1; this->setFixedHeight(height); }); QPalette pal = ui->listView->palette(); pal.setColor(QPalette::Base, Qt::transparent); ui->listView->setPalette(pal); ui->line->setVisible(false); } SearchResultsWidget::~SearchResultsWidget() { delete ui; delete d; } void SearchResultsWidget::search(QString query) { ui->listView->selectionModel()->clear(); d->model->search(query); } void SearchResultsWidget::moveSelectionUp() { QItemSelectionModel* selectionModel = ui->listView->selectionModel(); int selectionRow = d->model->rowCount() - 1; if (selectionModel->hasSelection()) { int row = selectionModel->selectedIndexes().first().row(); if (row != 0) selectionRow = row - 1; } selectionModel->select(d->model->index(selectionRow), QItemSelectionModel::ClearAndSelect); ui->listView->scrollTo(d->model->index(selectionRow), QListView::PositionAtCenter); } void SearchResultsWidget::moveSelectionDown() { QItemSelectionModel* selectionModel = ui->listView->selectionModel(); int selectionRow = 0; if (selectionModel->hasSelection()) { int row = selectionModel->selectedIndexes().first().row(); if (row != d->model->rowCount() - 1) selectionRow = row + 1; } selectionModel->select(d->model->index(selectionRow), QItemSelectionModel::ClearAndSelect); ui->listView->scrollTo(d->model->index(selectionRow), QListView::PositionAtCenter); } void SearchResultsWidget::launchSelected() { QModelIndexList indices = ui->listView->selectionModel()->selectedIndexes(); if (indices.isEmpty() || !indices.first().isValid()) { if (d->model->rowCount() > 0) launch(d->model->index(0)); } else { launch(indices.at(0)); } } void SearchResultsWidget::on_listView_clicked(const QModelIndex& index) { launch(index); } void SearchResultsWidget::launch(QModelIndex index) { d->model->launch(index); emit closeGateway(); } ================================================ FILE: desktop/gateway/searchresultswidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SEARCHRESULTSWIDGET_H #define SEARCHRESULTSWIDGET_H #include namespace Ui { class SearchResultsWidget; } struct SearchResultsWidgetPrivate; class SearchResultsWidget : public QWidget { Q_OBJECT public: explicit SearchResultsWidget(QWidget* parent = nullptr); ~SearchResultsWidget(); void search(QString query); void moveSelectionUp(); void moveSelectionDown(); void launchSelected(); private slots: void on_listView_clicked(const QModelIndex& index); signals: void closeGateway(); private: Ui::SearchResultsWidget* ui; SearchResultsWidgetPrivate* d; void launch(QModelIndex index); }; #endif // SEARCHRESULTSWIDGET_H ================================================ FILE: desktop/gateway/searchresultswidget.ui ================================================ SearchResultsWidget 0 0 400 300 Form 0 0 0 0 0 QFrame::NoFrame 16777215 1 Qt::Horizontal ================================================ FILE: desktop/main.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "background/background.h" #include "bar/barwindow.h" #include "cli/commandline.h" #include "crash/crashhandling.h" #include "plugins/pluginmanager.h" #include "run/rundialog.h" #include "server/sessionserver.h" #include "session/endsession.h" #include #include #include "gateway/appsearchprovider.h" int main(int argc, char* argv[]) { tApplication a(argc, argv); a.setOrganizationName("theSuite"); a.setOrganizationDomain("vicr123.com"); a.setApplicationName("theDesk"); a.setApplicationVersion("2.0"); a.setCopyrightYear("2024"); a.setApplicationShareDir("thedesk"); StateManager::instance(); StateManager::localeManager()->addTranslationSet({a.applicationDirPath() + "/translations", "/usr/share/thedesk/translations"}); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../desktop/thedesk.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk.conf"); CrashHandling::prepareCrashHandler(); // Parse command line arguments int parseResult = CommandLine::parse(a.arguments()); if (parseResult != -1) { // Stop running right here return parseResult; } if (a.queryKeyboardModifiers() & Qt::ControlModifier && !PluginManager::instance()->isSafeMode()) { tPromiseResults results = SessionServer::instance()->askQuestion(QApplication::translate("main", "Safe Mode"), QApplication::translate("main", "You're holding the CTRL key. Start theDesk in Safe Mode?"))->await(); if (results.result) PluginManager::instance()->setSafeMode(true); } DesktopWm::instance()->registerAsPrimaryProvider(); PluginManager::instance()->scanPlugins(); QObject::connect(StateManager::instance()->powerManager(), &PowerManager::powerOffConfirmationRequested, [=](PowerManager::PowerOperation operation, QString message, QStringList flags, tPromiseFunctions::SuccessFunction cb) { EndSession::showDialog(operation, message, flags)->then(cb); }); // Perform onboarding if required if (!OnboardingController::performOnboarding(false)) { // Exit now because onboarding failed (probably the user chose to log out) return 0; } // Prepare the run dialog RunDialog::initialise(); // Prepare the background Background::reconfigureBackgrounds(); StateManager::gatewayManager()->registerSearchProvider(new AppSearchProvider()); BarWindow w; w.show(); QTimer::singleShot(0, [=] { SessionServer::instance()->hideSplashes(); SessionServer::instance()->performAutostart(); }); return a.exec(); } ================================================ FILE: desktop/media/welcome1.webm ================================================ [File too large to display: 10.3 MB] ================================================ FILE: desktop/resources.qrc ================================================ icons/thedesk.svg icons/cactus.svg ================================================ FILE: desktop/run/rundialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "rundialog.h" #include "ui_rundialog.h" #include "transparentdialog.h" #include #include #include #include #include RunDialog::RunDialog(QWidget* parent) : QWidget(parent), ui(new Ui::RunDialog) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); ui->widget->setFixedWidth(SC_DPI(600)); this->setFocusProxy(ui->lineEdit); } RunDialog::~RunDialog() { delete ui; } void RunDialog::initialise() { KeyGrab* grab = new KeyGrab(QKeySequence(Qt::AltModifier | Qt::Key_F2), "run"); connect(grab, &KeyGrab::activated, [ = ] { TransparentDialog* dialog = new TransparentDialog(); dialog->setWindowFlag(Qt::FramelessWindowHint); dialog->setWindowFlag(Qt::WindowStaysOnTopHint); dialog->showFullScreen(); QTimer::singleShot(500, [ = ] { RunDialog* popoverContents = new RunDialog(); tPopover* popover = new tPopover(popoverContents); popover->setPopoverSide(tPopover::Bottom); popover->setPopoverWidth(popoverContents->sizeHint().height()); connect(popoverContents, &RunDialog::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popoverContents, &RunDialog::deleteLater); connect(popover, &tPopover::dismissed, [ = ] { popover->deleteLater(); dialog->deleteLater(); }); popover->show(dialog); popoverContents->setFocus(); }); }); } void RunDialog::on_titleLabel_backButtonClicked() { emit done(); } void RunDialog::on_runButton_clicked() { QStringList parts = ui->lineEdit->text().split(" "); QString executable = parts.takeFirst(); if (QProcess::startDetached(executable, parts)) { emit done(); } else { tErrorFlash::flashError(ui->lineEdit); } } ================================================ FILE: desktop/run/rundialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef RUNDIALOG_H #define RUNDIALOG_H #include namespace Ui { class RunDialog; } class RunDialog : public QWidget { Q_OBJECT public: explicit RunDialog(QWidget* parent = nullptr); ~RunDialog(); static void initialise(); private slots: void on_titleLabel_backButtonClicked(); void on_runButton_clicked(); signals: void done(); private: Ui::RunDialog* ui; }; #endif // RUNDIALOG_H ================================================ FILE: desktop/run/rundialog.ui ================================================ RunDialog 0 0 400 300 Form 0 0 0 0 0 Run 6 0 0 0 0 Enter a command to run. 9 Run this command tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
lineEdit returnPressed() runButton click() 198 254 198 278
================================================ FILE: desktop/session/endsession.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "endsession.h" #include "ui_endsession.h" #include "transparentdialog.h" #include #include #include #include #include #include #include #include #include #include #include struct EndSessionPrivate { tVariantAnimation* powerOffAnimation; EndSessionButton* timedButton; }; EndSession::EndSession(PowerManager::PowerOperation operation, QString message, QStringList flags, QWidget* parent) : QWidget(parent), ui(new Ui::EndSession) { ui->setupUi(this); d = new EndSessionPrivate(); if (message == "") { message = tr("Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything."); } ui->rebootInstallUpdatesButton->setVisible(false); if (operation != PowerManager::All) { ui->powerOffButton->setVisible(false); ui->rebootButton->setVisible(false); ui->logoutButton->setVisible(false); ui->suspendButton->setVisible(false); ui->lockButton->setVisible(false); ui->screenOffButton->setVisible(false); ui->switchUsersButton->setVisible(false); ui->hibernateButton->setVisible(false); } switch (operation) { case PowerManager::All: if (StateManager::onboardingManager()->isOnboardingRunning()) { ui->lockButton->setVisible(false); ui->screenOffButton->setVisible(false); } Q_FALLTHROUGH(); case PowerManager::PowerOff: d->timedButton = ui->powerOffButton; break; case PowerManager::Reboot: if (flags.contains("update")) { d->timedButton = ui->rebootInstallUpdatesButton; } else { d->timedButton = ui->rebootButton; } break; case PowerManager::LogOut: d->timedButton = ui->logoutButton; break; case PowerManager::Suspend: d->timedButton = ui->suspendButton; break; case PowerManager::Lock: d->timedButton = ui->lockButton; break; case PowerManager::TurnOffScreen: d->timedButton = ui->screenOffButton; break; case PowerManager::Hibernate: d->timedButton = ui->hibernateButton; break; } d->timedButton->setVisible(true); d->timedButton->setProperty("type", "destructive"); d->powerOffAnimation = new tVariantAnimation(); d->powerOffAnimation->setStartValue(60.0); d->powerOffAnimation->setEndValue(0.0); d->powerOffAnimation->setDuration(60000); d->powerOffAnimation->setForceAnimation(true); connect(d->powerOffAnimation, &tVariantAnimation::valueChanged, this, [=](QVariant value) { const QMap text = { {ui->powerOffButton, QT_TR_NOOP("power off the system") }, {ui->rebootButton, QT_TR_NOOP("reboot the system") }, {ui->rebootInstallUpdatesButton, QT_TR_NOOP("reboot the system and install any pending updates")}, {ui->logoutButton, QT_TR_NOOP("log you out") }, {ui->suspendButton, QT_TR_NOOP("suspend the system") }, {ui->lockButton, QT_TR_NOOP("lock the screen") }, {ui->screenOffButton, QT_TR_NOOP("turn off the screen") }, {ui->switchUsersButton, QT_TR_NOOP("switch users") }, {ui->hibernateButton, QT_TR_NOOP("hibernate the system") } }; ui->descriptionLabel->setText(tr(qPrintable(message), nullptr, value.toFloat() < 1 ? 1 : qRound(value.toDouble())) .arg(DesktopWm::userDisplayName()) .arg(tr(text.value(d->timedButton)))); d->timedButton->setTimeRemaining(value.toDouble()); }); connect(d->powerOffAnimation, &tVariantAnimation::finished, d->timedButton, &QCommandLinkButton::click); d->powerOffAnimation->start(); ui->centeredWidget->setFixedWidth(SC_DPI(600)); ui->centeredWidgetUpdates->setFixedWidth(SC_DPI(600)); ui->powerOffButton->setProperty("type", "destructive"); ui->rebootButton->setProperty("type", "destructive"); ui->titleLabel->setBackButtonShown(true); ui->updatesAvailableTitle->setBackButtonShown(true); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); } EndSession::~EndSession() { d->powerOffAnimation->stop(); delete d; delete ui; } tPromise* EndSession::showDialog(PowerManager::PowerOperation operation, QString message, QStringList flags) { return tPromise::runOnSameThread([=](tPromiseFunctions::SuccessFunction res, tPromiseFunctions::FailureFunction rej) { Q_UNUSED(rej) TransparentDialog* dialog = new TransparentDialog(); dialog->showFullScreen(); QTimer::singleShot(500, [=] { EndSession* popoverContents = new EndSession(operation, message, flags); tPopover* popover = new tPopover(popoverContents); popover->setPopoverSide(tPopover::Bottom); popover->setPopoverWidth(popoverContents->heightForWidth(dialog->width())); connect(popoverContents, &EndSession::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popoverContents, &EndSession::deleteLater); connect(popover, &tPopover::dismissed, [=] { popover->deleteLater(); dialog->deleteLater(); popoverContents->deleteLater(); res(); }); popover->show(dialog); }); }); } void EndSession::on_titleLabel_backButtonClicked() { d->powerOffAnimation->stop(); emit done(); } void EndSession::on_powerOffButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::PowerOff); emit done(); } void EndSession::on_rebootButton_clicked() { if (QFile("/var/lib/PackageKit/prepared-update").exists() && !QFile::exists("/system-update")) { // Ask the user to install updates ui->stackedWidget->setCurrentWidget(ui->updatesAvailablePage); } else { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::Reboot); emit done(); } } void EndSession::on_logoutButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::LogOut); emit done(); } void EndSession::on_suspendButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::Suspend); emit done(); } void EndSession::on_lockButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::Lock); emit done(); } void EndSession::on_screenOffButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::TurnOffScreen); emit done(); } void EndSession::on_switchUsersButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::SwitchUsers); emit done(); } void EndSession::on_hibernateButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::Hibernate); emit done(); } void EndSession::on_updatesAvailableTitle_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->mainPage); } void EndSession::on_rebootNoUpdateButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::Reboot); emit done(); } void EndSession::on_rebootUpdateButton_clicked() { // Reboot StateManager::instance()->powerManager()->performPowerOperation(PowerManager::Reboot, {"update"}); emit done(); } void EndSession::on_stackedWidget_switchingFrame(int frame) { if (frame == 0) { d->powerOffAnimation->start(); } else { d->powerOffAnimation->stop(); } } void EndSession::on_rebootInstallUpdatesButton_clicked() { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::Reboot, {"update"}); emit done(); } void EndSession::on_rebootButton_customContextMenuRequested(const QPoint& pos) { QMenu* menu = new QMenu(); menu->addSection(tr("Advanced Reboot")); menu->addAction(QIcon::fromTheme("system-reboot"), tr("Reboot"), [=] { // Just reboot ui->rebootButton->click(); }); QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "CanRebootToFirmwareSetup"); QDBusMessage msg = QDBusConnection::systemBus().call(message); if (msg.arguments().first().toString() == "yes") { menu->addAction(QIcon::fromTheme("system-reboot"), tr("Reboot into System UEFI Setup"), [=] { StateManager::instance()->powerManager()->performPowerOperation(PowerManager::Reboot, {"setup"}); emit done(); }); } menu->popup(ui->rebootButton->mapToGlobal(pos)); } ================================================ FILE: desktop/session/endsession.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ENDSESSION_H #define ENDSESSION_H #include #include #include namespace Ui { class EndSession; } struct EndSessionPrivate; class EndSession : public QWidget { Q_OBJECT public: ~EndSession(); static tPromise* showDialog(PowerManager::PowerOperation operation = PowerManager::All, QString message = "", QStringList flags = {}); signals: void done(); private slots: void on_titleLabel_backButtonClicked(); void on_powerOffButton_clicked(); void on_rebootButton_clicked(); void on_logoutButton_clicked(); void on_suspendButton_clicked(); void on_lockButton_clicked(); void on_screenOffButton_clicked(); void on_switchUsersButton_clicked(); void on_hibernateButton_clicked(); void on_updatesAvailableTitle_backButtonClicked(); void on_rebootNoUpdateButton_clicked(); void on_rebootUpdateButton_clicked(); void on_stackedWidget_switchingFrame(int frame); void on_rebootInstallUpdatesButton_clicked(); void on_rebootButton_customContextMenuRequested(const QPoint &pos); private: explicit EndSession(PowerManager::PowerOperation operation, QString message, QStringList flags, QWidget* parent = nullptr); Ui::EndSession* ui; EndSessionPrivate* d; }; #endif // ENDSESSION_H ================================================ FILE: desktop/session/endsession.ui ================================================ EndSession 0 0 799 515 Form 0 0 0 0 0 0 0 0 0 0 0 End Session 600 16777215 0 0 0 0 0 9 9 Ready to leave? true 9 Power Off .. Turns off your computer. Qt::CustomContextMenu Reboot .. Turns off your computer and turns it on again Reboot and install updates .. Turns off your computer, installs pending updates and turns it on again Log Out .. Ends your session but keeps your computer on for other people to use Suspend .. Puts your computer in a low power state so it reopens quickly Lock .. Locks your workspace with your password Turn Off Screen .. Turns off the screen, but keeps everything else running in the background Switch Users .. Switches to the logon screen, but keeps your session in the background Hibernate .. Powers off your computer, but restores the session when powered back on Qt::Vertical 0 20 0 0 0 0 0 Reboot 0 0 0 0 0 0 0 0 0 0 9 6 Updates are available. What do you want to do? 0 0 Reboot and update .. We'll perform system updates once this device has rebooted. 0 0 Reboot .. We'll reboot your device normally. Qt::Vertical 20 348 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
EndSessionButton QCommandLinkButton
session/endsessionbutton.h
================================================ FILE: desktop/session/endsessionbutton.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "endsessionbutton.h" #include #include struct EndSessionButtonPrivate { double timeRemaining = 0; }; EndSessionButton::EndSessionButton(QWidget* parent) : QCommandLinkButton(parent) { d = new EndSessionButtonPrivate(); } EndSessionButton::~EndSessionButton() { delete d; } void EndSessionButton::setTimeRemaining(double timeRemaining) { d->timeRemaining = timeRemaining; this->update(); } void EndSessionButton::paintEvent(QPaintEvent* event) { QCommandLinkButton::paintEvent(event); QPainter* painter = new QPainter(this); tPaintCalculator calculator; calculator.setDrawBounds(this->size()); calculator.setPainter(painter); calculator.setLayoutDirection(this->layoutDirection()); calculator.addRect(QRectF(0, 0, this->width() * d->timeRemaining / 60.0, this->height()), [ = ](QRectF drawBounds) { painter->setBrush(QColor(255, 255, 255, 50)); painter->setPen(Qt::transparent); painter->drawRect(drawBounds); }); calculator.performPaint(); delete painter; } ================================================ FILE: desktop/session/endsessionbutton.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ENDSESSIONBUTTON_H #define ENDSESSIONBUTTON_H #include struct EndSessionButtonPrivate; class EndSessionButton : public QCommandLinkButton { Q_OBJECT public: explicit EndSessionButton(QWidget* parent = nullptr); ~EndSessionButton(); void setTimeRemaining(double timeRemaining); signals: private: EndSessionButtonPrivate* d; void paintEvent(QPaintEvent* event); }; #endif // ENDSESSIONBUTTON_H ================================================ FILE: desktop/statuscenter/leftpanedelegate.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "leftpanedelegate.h" #include #include #include LeftPaneDelegate::LeftPaneDelegate(QObject* parent) : QStyledItemDelegate(parent) { } void LeftPaneDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { QStyledItemDelegate::paint(painter, option, index); if (index.data(Qt::UserRole).toBool()) { // Draw an indicator arrow tPaintCalculator calculator; calculator.setDrawBounds(option.rect); calculator.setLayoutDirection(option.direction); QRect iconRect; iconRect.setSize(SC_DPI_T(QSize(16, 16), QSize)); iconRect.moveCenter(option.rect.center()); iconRect.moveRight(option.rect.right() - SC_DPI(6)); calculator.addRect(iconRect, [=](QRectF drawBounds) { painter->drawPixmap(drawBounds.toRect(), QIcon::fromTheme("arrow-right").pixmap(iconRect.size())); }); calculator.performPaint(); } } ================================================ FILE: desktop/statuscenter/leftpanedelegate.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef LEFTPANEDELEGATE_H #define LEFTPANEDELEGATE_H #include class LeftPaneDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit LeftPaneDelegate(QObject* parent = nullptr); signals: // QAbstractItemDelegate interface public: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; #endif // LEFTPANEDELEGATE_H ================================================ FILE: desktop/statuscenter/statuscenter.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "statuscenter.h" #include "ui_statuscenter.h" #include #include #include #include #include #include #include #include #include "statuscenterleftpane.h" #include "common/common.h" #include "systemsettings/systemsettings.h" #include #include "statuscenterquickswitch.h" struct StatusCenterPrivate { StatusCenterLeftPane* leftPane; bool leftPaneAttached = false; QList> loadedPanes; QMap paneItems; QList> switchItems; QStringList preferredPaneOrder; QStringList preferredSwitchOrder; tSettings settings; }; StatusCenter::StatusCenter(QWidget* parent) : QWidget(parent), ui(new Ui::StatusCenter) { ui->setupUi(this); d = new StatusCenterPrivate(); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Lift); d->preferredPaneOrder = d->settings.delimitedList("StatusCenter/panesOrder"); d->preferredSwitchOrder = d->settings.delimitedList("StatusCenter/quickSwitchOrder"); d->preferredPaneOrder.removeAll("SystemSettings"); d->preferredPaneOrder.append("SystemSettings"); d->leftPane = new StatusCenterLeftPane(this); if (this->width() <= SC_DPI(1024)) { d->leftPaneAttached = true; detachLeftPane(); } else { d->leftPaneAttached = false; attachLeftPane(); } connect(StateManager::statusCenterManager(), &StatusCenterManager::paneAdded, this, [ = ](StatusCenterPane * pane, StatusCenterManager::PaneType type) { if (type == StatusCenterManager::Informational) { this->addPane(pane); } }); connect(StateManager::statusCenterManager(), &StatusCenterManager::paneRemoved, this, &StatusCenter::removePane); connect(StateManager::statusCenterManager(), &StatusCenterManager::showHamburgerMenu, this, &StatusCenter::showHamburgerMenu); connect(StateManager::statusCenterManager(), &StatusCenterManager::rootMenu, d->leftPane, &StatusCenterLeftPane::popMenu); connect(StateManager::statusCenterManager(), &StatusCenterManager::switchAdded, this, &StatusCenter::addSwitch); connect(StateManager::statusCenterManager(), &StatusCenterManager::switchRemoved, this, &StatusCenter::removeSwitch); for (StatusCenterPane* pane : StateManager::statusCenterManager()->panes()) { if (StateManager::statusCenterManager()->paneType(pane) == StatusCenterManager::Informational) this->addPane(pane); } for (QuickSwitch* sw : StateManager::statusCenterManager()->switches()) { this->addSwitch(sw); } connect(d->leftPane, &StatusCenterLeftPane::indexChanged, this, QOverload::of(&StatusCenter::selectPane)); connect(d->leftPane, &StatusCenterLeftPane::enterMenu, this, &StatusCenter::enterMenu); connect(StateManager::statusCenterManager(), QOverload::of(&StatusCenterManager::paneRequest), this, [ = ](QString paneName) { for (StatusCenterPane* pane : StateManager::statusCenterManager()->panes()) { if (pane->name() == paneName) { if (StateManager::statusCenterManager()->paneType(pane) == StatusCenterManager::Informational) { selectPane(pane); } else { selectPane("SystemSettings"); } } } }); connect(StateManager::statusCenterManager(), QOverload::of(&StatusCenterManager::paneRequest), this, [ = ](StatusCenterPane * pane) { if (StateManager::statusCenterManager()->paneType(pane) == StatusCenterManager::Informational) { selectPane(pane); } else { selectPane("SystemSettings"); } }); //Add internal items to the Status Center StateManager::instance()->statusCenterManager()->addPane(new SystemSettings(d->leftPane), StatusCenterManager::Informational); QShortcut* escapeShortcut = new QShortcut(Qt::Key_Escape, this); connect(escapeShortcut, &QShortcut::activated, ui->closeButton, &QToolButton::click); } StatusCenter::~StatusCenter() { delete d; delete ui; } void StatusCenter::on_closeButton_clicked() { StateManager::instance()->statusCenterManager()->hide(); } void StatusCenter::resizeEvent(QResizeEvent* event) { if (this->width() <= SC_DPI(1024)) { detachLeftPane(); } else { attachLeftPane(); } } void StatusCenter::attachLeftPane() { if (d->leftPaneAttached) return; ui->leftPaneContainer->addWidget(d->leftPane); d->leftPane->setAttached(true); StateManager::statusCenterManager()->setIsHamburgerMenuRequired(false); d->leftPaneAttached = true; } void StatusCenter::detachLeftPane() { if (!d->leftPaneAttached) return; ui->leftPaneContainer->removeWidget(d->leftPane); d->leftPane->move(-d->leftPane->width(), 0); d->leftPane->setAttached(false); StateManager::statusCenterManager()->setIsHamburgerMenuRequired(true); d->leftPaneAttached = false; } void StatusCenter::showHamburgerMenu() { if (!tPopover::popoverForWidget(ui->mainWidget)) { tPopover* popover = new tPopover(d->leftPane); popover->setPopoverWidth(d->leftPane->width()); popover->setPopoverSide(tPopover::Leading); connect(StateManager::statusCenterManager(), &StatusCenterManager::hideHamburgerMenu, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(ui->mainWidget); } } void StatusCenter::selectPane(StatusCenterPane* pane) { ui->stackedWidget->setCurrentWidget(pane); if (pane->leftPane()) d->leftPane->pushMenu(pane->leftPane()); d->paneItems.value(pane)->setSelected(true); } void StatusCenter::selectPane(QString pane) { for (QPair loadedPane : d->loadedPanes) { if (loadedPane.first == pane) selectPane(loadedPane.second); } } void StatusCenter::selectPane(int index) { selectPane(d->loadedPanes.at(index).second); } void StatusCenter::enterMenu(int index) { StatusCenterPane* pane = d->loadedPanes.at(index).second; if (pane->leftPane()) { if (d->leftPane->peekMenu() != pane->leftPane()) d->leftPane->pushMenu(pane->leftPane()); } else { StateManager::statusCenterManager()->hideStatusCenterHamburgerMenu(); } } void StatusCenter::addPane(StatusCenterPane* pane) { QListWidgetItem* item = new QListWidgetItem(); item->setText(pane->displayName()); item->setIcon(pane->icon()); connect(pane, &StatusCenterPane::displayNameChanged, this, [ = ] { if (d->paneItems.contains(pane)) { d->paneItems.value(pane)->setText(pane->displayName()); } }); connect(pane, &StatusCenterPane::iconChanged, this, [ = ] { if (d->paneItems.contains(pane)) { d->paneItems.value(pane)->setIcon(pane->icon()); } }); if (pane->leftPane()) { item->setData(Qt::UserRole, true); } d->paneItems.insert(pane, item); QStringList currentItems; for (QPair item : d->loadedPanes) { currentItems.append(item.first); } int index = Common::getInsertionIndex(d->preferredPaneOrder, currentItems, pane->name()); if (index == -1) { //Add it at the end ui->stackedWidget->addWidget(pane); d->leftPane->appendItem(item); d->loadedPanes.append({pane->name(), pane}); } else { //Add this chunk at the correct index ui->stackedWidget->insertWidget(index, pane); d->leftPane->insertItem(index, item); d->loadedPanes.insert(index, {pane->name(), pane}); } } void StatusCenter::removePane(StatusCenterPane* pane) { for (int i = 0; i < d->loadedPanes.count(); i++) { if (d->loadedPanes.at(i).second == pane) { QListWidgetItem* item = d->paneItems.take(pane); d->leftPane->removeItem(item); delete item; ui->stackedWidget->removeWidget(pane); d->loadedPanes.removeAt(i); return; } } } void StatusCenter::addSwitch(QuickSwitch* sw) { QStringList currentItems; for (QPair item : d->switchItems) { currentItems.append(item.first->name()); } StatusCenterQuickSwitch* item = new StatusCenterQuickSwitch(sw); int index = Common::getInsertionIndex(d->preferredSwitchOrder, currentItems, sw->name()); if (index == -1) { //Add it at the end ui->quickSwitchLayout->addWidget(item); d->switchItems.append({sw, item}); } else { //Add this switch at the correct index ui->quickSwitchLayout->insertWidget(index, item); d->switchItems.insert(index, {sw, item}); } } void StatusCenter::removeSwitch(QuickSwitch* sw) { for (int i = 0; i < d->switchItems.count(); i++) { if (d->switchItems.at(i).first == sw) { ui->quickSwitchLayout->removeWidget(d->switchItems.at(i).second); d->switchItems.at(i).second->deleteLater(); d->switchItems.removeAt(i); return; } } } ================================================ FILE: desktop/statuscenter/statuscenter.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef STATUSCENTER_H #define STATUSCENTER_H #include namespace Ui { class StatusCenter; } class StatusCenterPane; class QuickSwitch; struct StatusCenterPrivate; class StatusCenter : public QWidget { Q_OBJECT public: explicit StatusCenter(QWidget* parent = nullptr); ~StatusCenter(); private slots: void on_closeButton_clicked(); private: Ui::StatusCenter* ui; StatusCenterPrivate* d; void resizeEvent(QResizeEvent* event); void attachLeftPane(); void detachLeftPane(); void showHamburgerMenu(); void selectPane(StatusCenterPane* pane); void selectPane(QString pane); void selectPane(int index); void enterMenu(int index); void addPane(StatusCenterPane* pane); void removePane(StatusCenterPane* pane); void addSwitch(QuickSwitch* sw); void removeSwitch(QuickSwitch* sw); }; #endif // STATUSCENTER_H ================================================ FILE: desktop/statuscenter/statuscenter.ui ================================================ StatusCenter 0 0 677 450 Form 0 0 0 0 0 .. true Qt::Horizontal 40 20 16777215 1 Qt::Horizontal 0 0 0 0 0 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
================================================ FILE: desktop/statuscenter/statuscenterleftpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "statuscenterleftpane.h" #include "ui_statuscenterleftpane.h" #include "leftpanedelegate.h" #include #include struct StatusCenterLeftPanePrivate { bool attached; }; StatusCenterLeftPane::StatusCenterLeftPane(QWidget* parent) : QWidget(parent), ui(new Ui::StatusCenterLeftPane) { ui->setupUi(this); d = new StatusCenterLeftPanePrivate(); ui->mainList->setIconSize(SC_DPI_T(QSize(32, 32), QSize)); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); ui->mainList->setItemDelegate(new LeftPaneDelegate(this)); } StatusCenterLeftPane::~StatusCenterLeftPane() { delete d; delete ui; } void StatusCenterLeftPane::appendItem(QListWidgetItem* item) { ui->mainList->addItem(item); } void StatusCenterLeftPane::insertItem(int index, QListWidgetItem* item) { ui->mainList->insertItem(index, item); } void StatusCenterLeftPane::removeItem(QListWidgetItem* item) { ui->mainList->removeItemWidget(item); } void StatusCenterLeftPane::setSelected(QListWidgetItem* item) { item->setSelected(true); } void StatusCenterLeftPane::setAttached(bool attached) { d->attached = attached; if (attached) { if (this->layoutDirection() == Qt::RightToLeft) { this->layout()->setContentsMargins(1, 0, 1, 0); } else { this->layout()->setContentsMargins(0, 0, 1, 0); } this->setFixedWidth(SC_DPI(300) + 1); } else { this->layout()->setContentsMargins(0, 0, 0, 0); this->setFixedWidth(SC_DPI(300)); } } void StatusCenterLeftPane::pushMenu(QWidget* menu) { ui->stackedWidget->addWidget(menu); ui->stackedWidget->setCurrentWidget(menu); } void StatusCenterLeftPane::popMenu() { if (ui->stackedWidget->count() == 1) return; QMetaObject::Connection* connection = new QMetaObject::Connection(); *connection = connect(ui->stackedWidget, &tStackedWidget::currentChanged, this, [=] { disconnect(*connection); delete connection; QWidget* lastWidget = ui->stackedWidget->widget(ui->stackedWidget->currentIndex() + 1); ui->stackedWidget->removeWidget(lastWidget); }); ui->stackedWidget->setCurrentIndex(ui->stackedWidget->currentIndex() - 1); } QWidget* StatusCenterLeftPane::peekMenu() { return ui->stackedWidget->currentWidget(); } void StatusCenterLeftPane::paintEvent(QPaintEvent* event) { if (d->attached) { QPainter painter(this); painter.setPen(libContemporaryCommon::lineColor(this->palette().color(QPalette::WindowText))); if (this->layoutDirection() == Qt::RightToLeft) { painter.drawLine(0, 0, 0, this->height()); } else { painter.drawLine(this->width() - 1, 0, this->width() - 1, this->height()); } } } void StatusCenterLeftPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } else if (event->type() == QEvent::LayoutDirectionChange) { this->setAttached(d->attached); } } void StatusCenterLeftPane::on_mainList_currentRowChanged(int currentRow) { emit indexChanged(currentRow); } void StatusCenterLeftPane::on_mainList_clicked(const QModelIndex& index) { emit enterMenu(index.row()); } ================================================ FILE: desktop/statuscenter/statuscenterleftpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef STATUSCENTERLEFTPANE_H #define STATUSCENTERLEFTPANE_H #include namespace Ui { class StatusCenterLeftPane; } class QListWidgetItem; struct StatusCenterLeftPanePrivate; class StatusCenterLeftPane : public QWidget { Q_OBJECT public: explicit StatusCenterLeftPane(QWidget* parent = nullptr); ~StatusCenterLeftPane(); void appendItem(QListWidgetItem* item); void insertItem(int index, QListWidgetItem* item); void removeItem(QListWidgetItem* item); void setSelected(QListWidgetItem* item); void setAttached(bool attached); void pushMenu(QWidget* menu); void popMenu(); QWidget* peekMenu(); signals: void indexChanged(int index); void enterMenu(int index); private slots: void on_mainList_currentRowChanged(int currentRow); void on_mainList_clicked(const QModelIndex& index); private: Ui::StatusCenterLeftPane* ui; StatusCenterLeftPanePrivate* d; void paintEvent(QPaintEvent* event); void changeEvent(QEvent* event); }; #endif // STATUSCENTERLEFTPANE_H ================================================ FILE: desktop/statuscenter/statuscenterleftpane.ui ================================================ StatusCenterLeftPane 0 0 400 390 Form 0 0 0 0 0 0 0 0 0 0 Status Center QFrame::NoFrame true tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: desktop/statuscenter/statuscenterquickswitch.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "statuscenterquickswitch.h" #include "ui_statuscenterquickswitch.h" #include struct StatusCenterQuickSwitchPrivate { QuickSwitch* sw; }; StatusCenterQuickSwitch::StatusCenterQuickSwitch(QuickSwitch* sw, QWidget* parent) : QWidget(parent), ui(new Ui::StatusCenterQuickSwitch) { ui->setupUi(this); d = new StatusCenterQuickSwitchPrivate(); d->sw = sw; ui->sw->setChecked(sw->isChecked()); ui->titleLabel->setText(sw->title()); sw->setSwitch(ui->sw); connect(sw, &QuickSwitch::titleChanged, ui->titleLabel, &QLabel::setText); } StatusCenterQuickSwitch::~StatusCenterQuickSwitch() { delete d; delete ui; } void StatusCenterQuickSwitch::on_sw_toggled(bool checked) { d->sw->setChecked(checked); } ================================================ FILE: desktop/statuscenter/statuscenterquickswitch.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef STATUSCENTERQUICKSWITCH_H #define STATUSCENTERQUICKSWITCH_H #include namespace Ui { class StatusCenterQuickSwitch; } class QuickSwitch; struct StatusCenterQuickSwitchPrivate; class StatusCenterQuickSwitch : public QWidget { Q_OBJECT public: explicit StatusCenterQuickSwitch(QuickSwitch* sw, QWidget* parent = nullptr); ~StatusCenterQuickSwitch(); private slots: void on_sw_toggled(bool checked); private: Ui::StatusCenterQuickSwitch* ui; StatusCenterQuickSwitchPrivate* d; }; #endif // STATUSCENTERQUICKSWITCH_H ================================================ FILE: desktop/statuscenter/statuscenterquickswitch.ui ================================================ StatusCenterQuickSwitch 0 0 163 43 Form Switch TextLabel tSwitch QPushButton
tswitch.h
================================================ FILE: desktop/systemsettings/about/about.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "about.h" #include "ui_about.h" #include "acknowledgements.h" #include "changehostnamepopover.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct AboutPrivate { QDBusInterface* hostnamed; }; About::About() : StatusCenterPane(), ui(new Ui::About) { ui->setupUi(this); d = new AboutPrivate(); d->hostnamed = new QDBusInterface("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", QDBusConnection::systemBus()); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); // Fill in details from hostnamed ui->deviceTypeLabel->setText(QStringLiteral("%1 %2").arg(d->hostnamed->property("HardwareVendor").toString(), d->hostnamed->property("HardwareModel").toString())); ui->distroWebpage->setText(d->hostnamed->property("HomeURL").toString()); ui->distroName->setText(d->hostnamed->property("OperatingSystemPrettyName").toString()); struct sysinfo* info = new struct sysinfo; if (sysinfo(info) == 0) { ui->availableMemory->setText(QLocale().formattedDataSize(static_cast(info->totalram))); ui->availableSwap->setText(QLocale().formattedDataSize(static_cast(info->totalswap))); } else { ui->availableMemory->setText(tr("Unknown")); ui->availableSwap->setText(tr("Unknown")); } delete info; ui->kernelVersion->setText(QSysInfo::kernelVersion()); ui->qtVersion->setText(qVersion()); QFile cpuInfoFile("/proc/cpuinfo"); cpuInfoFile.open(QFile::ReadOnly); QByteArray cpuInfoBuf = cpuInfoFile.readAll(); QBuffer cpuInfo(&cpuInfoBuf); cpuInfo.open(QBuffer::ReadOnly); QStringList knownCpus; while (!cpuInfo.atEnd()) { QString line = cpuInfo.readLine(); if (line.startsWith("model name")) { QString cpu = line.mid(line.indexOf(":") + 1).trimmed(); knownCpus.append(cpu); } } QStringList shownCpus; while (knownCpus.length() > 0) { QString cpu = knownCpus.value(0); int numberOfThisCpu = knownCpus.count(cpu); knownCpus.removeAll(cpu); if (numberOfThisCpu == 1) { shownCpus.append(cpu); } else { shownCpus.append(QString::number(numberOfThisCpu) + " × " + cpu); } } if (shownCpus.length() == 0) { ui->processorType->setText(tr("Unknown")); } else { ui->processorType->setText(shownCpus.join(" · ")); } QDBusConnection::systemBus().connect("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(updateHostname())); updateHostname(); ui->videoLabel->setText(videoCard()); ui->windowSystemLabel->setText(DesktopWm::windowSystemName()); #ifdef BLUEPRINT ui->versionLabel->setText(tr("theDesk %1 - Blueprint").arg("1.0")); ui->compileDate->setText(tr("You compiled theDesk on %1").arg(__DATE__)); #else ui->versionLabel->setText(tr("theDesk %1").arg(tApplication::applicationVersion())); ui->compileDate->setVisible(false); #endif ui->copyrightNotice->setText(tr("Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later.").arg(tApplication::copyrightYear())); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->sysinfoFrame->layout()->setAlignment(ui->distributionPane, Qt::AlignHCenter); ui->sysinfoFrame->layout()->setAlignment(ui->hardwareSoftwarePane, Qt::AlignHCenter); ui->centralWidget->layout()->setAlignment(ui->aboutPane, Qt::AlignHCenter); ui->centralWidget->layout()->setAlignment(ui->copyrightNotice, Qt::AlignHCenter); ui->distributionPane->setFixedWidth(contentWidth); ui->hardwareSoftwarePane->setFixedWidth(contentWidth); ui->aboutPane->setFixedWidth(contentWidth); ui->copyrightNotice->setFixedWidth(contentWidth); } About::~About() { delete d; delete ui; } void About::on_titleLabel_backButtonClicked() { StateManager::instance()->statusCenterManager()->showStatusCenterHamburgerMenu(); } void About::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } QString About::videoCard() { QSurfaceFormat format; format.setMajorVersion(3); // Specify the version of OpenGL context format.setMinorVersion(2); format.setProfile(QSurfaceFormat::CoreProfile); // Modern OpenGL QOffscreenSurface offscreenSurface; offscreenSurface.setFormat(format); // Apply the format offscreenSurface.create(); // This must be called to actually create the surface QOpenGLContext context; context.setFormat(format); // Again, set the format if (!context.create()) // Try to create the OpenGL context { return tr("Unknown"); } if (!context.makeCurrent(&offscreenSurface)) // Attempt to make the context current { return tr("Unknown"); } QOpenGLFunctions* functions = context.functions(); // Get the OpenGL functions for the current context QString renderer = QString::fromUtf8(reinterpret_cast(functions->glGetString(GL_RENDERER))); // Get the GPU's name context.doneCurrent(); return renderer; } QString About::name() { return "SystemAbout"; } QString About::displayName() { return tr("About"); } QIcon About::icon() { return QIcon::fromTheme("preferences-desktop-about"); } QWidget* About::leftPane() { return nullptr; } void About::on_acknowledgementsButton_clicked() { Acknowledgements* ack = new Acknowledgements(); tPopover* popover = new tPopover(ack); popover->setPopoverWidth(SC_DPI(600)); connect(ack, &Acknowledgements::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, ack, &Acknowledgements::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); } void About::on_debugLogButton_clicked() { StateManager::statusCenterManager()->hide(); tLogger::openDebugLogWindow(); } void About::on_changeHostnameButton_clicked() { ChangeHostnamePopover* changeHostname = new ChangeHostnamePopover(); tPopover* popover = new tPopover(changeHostname); popover->setPopoverWidth(SC_DPI(600)); connect(changeHostname, &ChangeHostnamePopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, changeHostname, &Acknowledgements::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); } void About::updateHostname() { QString hostname = d->hostnamed->property("PrettyHostname").toString(); if (hostname.isEmpty()) hostname = d->hostnamed->property("Hostname").toString(); if (hostname.isEmpty()) hostname = QHostInfo::localHostName(); ui->hostnameLabel->setText(hostname); } ================================================ FILE: desktop/systemsettings/about/about.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ABOUT_H #define ABOUT_H #include namespace Ui { class About; } struct AboutPrivate; class About : public StatusCenterPane { Q_OBJECT public: explicit About(); ~About(); private slots: void on_titleLabel_backButtonClicked(); void on_acknowledgementsButton_clicked(); void on_debugLogButton_clicked(); void on_changeHostnameButton_clicked(); void updateHostname(); private: Ui::About* ui; AboutPrivate* d; void changeEvent(QEvent* event); QString videoCard(); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); }; #endif // ABOUT_H ================================================ FILE: desktop/systemsettings/about/about.ui ================================================ About 0 0 868 573 Form 0 0 0 0 0 About QFrame::NoFrame true 0 -105 854 661 0 0 0 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 9 9 9 9 6 0 0 15 true Distribution Name true DISTRIBUTION PointingHandCursor http://www.distro.org/ You're using 16777215 1 Qt::Horizontal 0 0 9 9 9 9 6 Intel Available Swap true THIS DEVICE Kernel Version Device Name Window System Available Memory Device Type 4.11 Change Device Name Qt Version TextLabel 0 0 8 GiB TextLabel 8 GiB 5.9.0 TextLabel Processor Video AMDx 0 0 16777215 1 Qt::Horizontal 0 0 6 9 9 9 9 15 theDesk %1 Desktop Environment You compiled theDesk on %1 0 Acknowledgements Website ../../../../theShell/shell../../../../theShell/shell File Bug ../../../../theShell/shell../../../../theShell/shell Sources ../../../../theShell/shell../../../../theShell/shell View Debug Log Qt::Horizontal 40 20 Qt::Vertical 20 133 16777215 1 Qt::Horizontal theDesk is Copyright (c) Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. true 9 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStandardLabel QLabel
tstandardlabel.h
================================================ FILE: desktop/systemsettings/about/acknowledgements.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "acknowledgements.h" #include "ui_acknowledgements.h" #include #include #include Acknowledgements::Acknowledgements(QWidget* parent) : QWidget(parent), ui(new Ui::Acknowledgements) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); ui->textBrowser->setSource(QUrl::fromLocalFile(QStringLiteral("/usr/share/thedesk/acknowledgements.html")), QTextDocument::HtmlResource); } Acknowledgements::~Acknowledgements() { delete ui; } void Acknowledgements::on_titleLabel_backButtonClicked() { emit done(); } void Acknowledgements::on_textBrowser_anchorClicked(const QUrl& arg1) { emit done(); StateManager::statusCenterManager()->hide(); QDesktopServices::openUrl(arg1); } ================================================ FILE: desktop/systemsettings/about/acknowledgements.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ACKNOWLEDGEMENTS_H #define ACKNOWLEDGEMENTS_H #include namespace Ui { class Acknowledgements; } class Acknowledgements : public QWidget { Q_OBJECT public: explicit Acknowledgements(QWidget* parent = nullptr); ~Acknowledgements(); signals: void done(); private slots: void on_titleLabel_backButtonClicked(); void on_textBrowser_anchorClicked(const QUrl& arg1); private: Ui::Acknowledgements* ui; }; #endif // ACKNOWLEDGEMENTS_H ================================================ FILE: desktop/systemsettings/about/acknowledgements.ui ================================================ Acknowledgements 0 0 400 300 Form 0 0 0 0 0 Acknowledgements QFrame::NoFrame tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: desktop/systemsettings/about/changehostnamepopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "changehostnamepopover.h" #include "ui_changehostnamepopover.h" #include #include ChangeHostnamePopover::ChangeHostnamePopover(QWidget* parent) : QWidget(parent), ui(new Ui::ChangeHostnamePopover) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); QDBusInterface hostnamed("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", QDBusConnection::systemBus()); QString hostname = hostnamed.property("PrettyHostname").toString(); if (hostname.isEmpty()) hostname = hostnamed.property("Hostname").toString(); if (hostname.isEmpty()) hostname = QHostInfo::localHostName(); ui->hostnameEdit->setText(hostname); } ChangeHostnamePopover::~ChangeHostnamePopover() { delete ui; } void ChangeHostnamePopover::on_titleLabel_backButtonClicked() { emit done(); } void ChangeHostnamePopover::on_renameButton_clicked() { QDBusMessage prettyMessage = QDBusMessage::createMethodCall("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "SetPrettyHostname"); prettyMessage.setArguments({ui->hostnameEdit->text(), true}); QDBusConnection::systemBus().asyncCall(prettyMessage); QDBusMessage staticMessage = QDBusMessage::createMethodCall("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "SetStaticHostname"); staticMessage.setArguments({generateStaticHostname(ui->hostnameEdit->text()), true}); QDBusConnection::systemBus().asyncCall(staticMessage); emit done(); } void ChangeHostnamePopover::on_hostnameEdit_textChanged(const QString& arg1) { ui->networkCompatibleName->setText(generateStaticHostname(arg1)); } QString ChangeHostnamePopover::generateStaticHostname(QString hostname) { QString allowedCharacters = QStringLiteral("abcdefghijklmnopqrstuvwxyz0123456789-"); QString ignoredCharacters = QStringLiteral("'\""); QString staticHostname; bool allowHyphen = false; for (QChar c : hostname) { c = c.toLower(); if (ignoredCharacters.contains(c)) continue; if (allowedCharacters.contains(c)) { staticHostname.append(c); allowHyphen = true; continue; } bool haveCharacter = false; for (QChar ch : c.decomposition()) { if (allowedCharacters.contains(ch)) { staticHostname.append(ch); allowHyphen = true; haveCharacter = true; continue; } } if (haveCharacter) continue; if (allowHyphen) { allowHyphen = false; staticHostname.append("-"); } } if (staticHostname.endsWith("-")) staticHostname.remove(staticHostname.length() - 1, 1); staticHostname.truncate(63); if (staticHostname.isEmpty()) return QStringLiteral("localhost"); return staticHostname; } ================================================ FILE: desktop/systemsettings/about/changehostnamepopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CHANGEHOSTNAMEPOPOVER_H #define CHANGEHOSTNAMEPOPOVER_H #include namespace Ui { class ChangeHostnamePopover; } class ChangeHostnamePopover : public QWidget { Q_OBJECT public: explicit ChangeHostnamePopover(QWidget* parent = nullptr); ~ChangeHostnamePopover(); private slots: void on_titleLabel_backButtonClicked(); void on_renameButton_clicked(); void on_hostnameEdit_textChanged(const QString& arg1); signals: void done(); private: Ui::ChangeHostnamePopover* ui; QString generateStaticHostname(QString hostname); }; #endif // CHANGEHOSTNAMEPOPOVER_H ================================================ FILE: desktop/systemsettings/about/changehostnamepopover.ui ================================================ ChangeHostnamePopover 0 0 400 592 Form 0 0 0 0 0 Change Device Name 9 9 9 9 6 New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. true Network Compatible Name TextLabel Rename this Device .. Qt::Vertical 20 0 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: desktop/systemsettings/pluginmanagement/managepluginpopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "managepluginpopover.h" #include "ui_managepluginpopover.h" #include #include #include "plugins/pluginmanager.h" struct ManagePluginPopoverPrivate { QUuid uuid; }; ManagePluginPopover::ManagePluginPopover(QUuid uuid, QWidget* parent) : QWidget(parent), ui(new Ui::ManagePluginPopover) { ui->setupUi(this); d = new ManagePluginPopoverPrivate(); d->uuid = uuid; ui->titleLabel->setBackButtonShown(true); ui->titleLabel->setText(PluginManager::instance()->pluginMetadata(uuid, "name").toString()); ui->blacklistTitle->setBackButtonShown(true); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); ui->uuidLabel->setText(tr("UUID: %1").arg(uuid.toString())); connect(PluginManager::instance(), &PluginManager::pluginsChanged, this, &ManagePluginPopover::updateState); updateState(); ui->deactivateButton->setProperty("type", "destructive"); ui->blacklistButton->setProperty("type", "destructive"); ui->performBlacklistButton->setProperty("type", "destructive"); } ManagePluginPopover::~ManagePluginPopover() { delete d; delete ui; } void ManagePluginPopover::on_titleLabel_backButtonClicked() { emit done(); } void ManagePluginPopover::updateState() { PluginManager* manager = PluginManager::instance(); if (manager->blacklistedPlugins().contains(d->uuid)) { ui->activateButton->setVisible(false); ui->deactivateButton->setVisible(false); ui->blacklistButton->setVisible(false); ui->errorDetailsWidget->setVisible(false); ui->removeBlacklistButton->setVisible(true); return; } ui->blacklistButton->setVisible(true); ui->removeBlacklistButton->setVisible(false); if (manager->erroredPlugins().contains(d->uuid)) { ui->errorDetailsLabel->setText(manager->pluginErrorReason(d->uuid)); ui->errorDetailsWidget->setVisible(true); } else { ui->errorDetailsWidget->setVisible(false); } if (manager->loadedPlugins().contains(d->uuid)) { ui->activateButton->setVisible(false); ui->deactivateButton->setVisible(true); } else { ui->activateButton->setVisible(true); ui->deactivateButton->setVisible(false); } } void ManagePluginPopover::on_activateButton_clicked() { PluginManager::instance()->activatePlugin(d->uuid); } void ManagePluginPopover::on_deactivateButton_clicked() { PluginManager::instance()->deactivatePlugin(d->uuid); } void ManagePluginPopover::on_blacklistButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->blacklistPage); } void ManagePluginPopover::on_removeBlacklistButton_clicked() { PluginManager::instance()->removeBlacklistPlugin(d->uuid); } void ManagePluginPopover::on_performBlacklistButton_clicked() { PluginManager::instance()->blacklistPlugin(d->uuid); ui->stackedWidget->setCurrentWidget(ui->mainPage); } void ManagePluginPopover::on_blacklistTitle_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->mainPage); } ================================================ FILE: desktop/systemsettings/pluginmanagement/managepluginpopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MANAGEPLUGINPOPOVER_H #define MANAGEPLUGINPOPOVER_H #include namespace Ui { class ManagePluginPopover; } struct ManagePluginPopoverPrivate; class ManagePluginPopover : public QWidget { Q_OBJECT public: explicit ManagePluginPopover(QUuid uuid, QWidget* parent = nullptr); ~ManagePluginPopover(); signals: void done(); private slots: void on_titleLabel_backButtonClicked(); void on_activateButton_clicked(); void on_deactivateButton_clicked(); void on_blacklistButton_clicked(); void on_removeBlacklistButton_clicked(); void on_performBlacklistButton_clicked(); void on_blacklistTitle_backButtonClicked(); private: Ui::ManagePluginPopover* ui; ManagePluginPopoverPrivate* d; void updateState(); }; #endif // MANAGEPLUGINPOPOVER_H ================================================ FILE: desktop/systemsettings/pluginmanagement/managepluginpopover.ui ================================================ ManagePluginPopover 0 0 400 399 Form 0 0 0 0 0 0 0 0 0 0 0 TextLabel QFrame::NoFrame true 0 0 400 382 0 0 0 0 0 0 0 0 0 0 9 9 9 9 75 true ERROR DETAILS TextLabel true 16777215 1 Qt::Horizontal 9 9 9 6 75 true ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist false TextLabel 9 Qt::Vertical 20 153 0 0 0 0 0 Blacklist Plugin Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. true 9 Blacklist Plugin Qt::Vertical 20 289 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1
================================================ FILE: desktop/systemsettings/pluginmanagement/pluginitemdelegate.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "pluginitemdelegate.h" #include #include #include #include #include struct PluginItemDelegatePrivate { struct Rects { QRect iconRect; QRect textRect; QRect descRect; QRect arrowRect; Rects(const QStyleOptionViewItem& option) { QRect newRect = option.rect; QPoint center = newRect.center(); newRect.setWidth(StateManager::statusCenterManager()->preferredContentWidth()); newRect.moveCenter(center); iconRect.setLeft(newRect.left() + SC_DPI(6)); iconRect.setTop(newRect.top() + SC_DPI(6)); iconRect.setBottom(iconRect.top() + SC_DPI(32)); iconRect.setRight(iconRect.left() + SC_DPI(32)); arrowRect.setSize(SC_DPI_T(QSize(16, 16), QSize)); arrowRect.moveCenter(newRect.center()); arrowRect.moveRight(newRect.right() - SC_DPI(6)); textRect.setLeft(iconRect.right() + SC_DPI(6)); textRect.setTop(newRect.top() + SC_DPI(6)); textRect.setBottom(newRect.top() + option.fontMetrics.height() + SC_DPI(6)); textRect.setRight(arrowRect.left() - SC_DPI(6)); descRect.setLeft(iconRect.right() + SC_DPI(6)); descRect.setTop(newRect.top() + option.fontMetrics.height() + SC_DPI(8)); descRect.setBottom(newRect.top() + option.fontMetrics.height() * 2 + SC_DPI(6)); descRect.setRight(arrowRect.left() - SC_DPI(6)); } }; }; PluginItemDelegate::PluginItemDelegate(QObject* parent) : QAbstractItemDelegate(parent) { d = new PluginItemDelegatePrivate(); } PluginItemDelegate::~PluginItemDelegate() { delete d; } void PluginItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { painter->save(); tPaintCalculator calculator; calculator.setPainter(painter); calculator.setLayoutDirection(option.direction); calculator.setDrawBounds(option.rect); painter->setFont(option.font); PluginItemDelegatePrivate::Rects rects(option); QString text = index.data().toString(); QString desc = index.data(Qt::UserRole).toString(); QIcon icon = index.data(Qt::DecorationRole).value(); bool active = index.data(Qt::UserRole + 2).toBool(); bool blacklisted = index.data(Qt::UserRole + 3).toBool(); if (option.state & QStyle::State_Selected) { calculator.addRect(option.rect, [=](QRectF drawBounds) { painter->setPen(Qt::transparent); painter->setBrush(option.palette.color(QPalette::Highlight)); painter->drawRect(drawBounds); }); calculator.addRect(rects.textRect, [=](QRectF drawBounds) { painter->setBrush(Qt::transparent); painter->setPen(option.palette.color(QPalette::HighlightedText)); if (!active) painter->setOpacity(0.5); painter->drawText(drawBounds, Qt::AlignLeading, text); }); calculator.addRect(rects.descRect, [=](QRectF drawBounds) { painter->drawText(drawBounds, Qt::AlignLeading, desc); }); } else if (option.state & QStyle::State_MouseOver) { calculator.addRect(option.rect, [=](QRectF drawBounds) { QColor col = option.palette.color(QPalette::Highlight); col.setAlpha(127); painter->setBrush(col); painter->setPen(Qt::transparent); painter->drawRect(drawBounds); }); calculator.addRect(rects.textRect, [=](QRectF drawBounds) { if (!active) painter->setOpacity(0.5); painter->setBrush(Qt::transparent); painter->setPen(option.palette.color(QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, text); }); calculator.addRect(rects.descRect, [=](QRectF drawBounds) { painter->setPen(option.palette.color(QPalette::Disabled, QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, desc); }); } else { calculator.addRect(rects.textRect, [=](QRectF drawBounds) { if (!active) painter->setOpacity(0.5); painter->setPen(option.palette.color(QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, text); }); calculator.addRect(rects.descRect, [=](QRectF drawBounds) { painter->setPen(option.palette.color(QPalette::Disabled, QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, desc); }); } if (!icon.isNull()) { calculator.addRect(rects.iconRect, [=](QRectF drawBounds) { painter->drawPixmap(drawBounds.toRect(), icon.pixmap(drawBounds.toRect().size())); }); } if (blacklisted) { calculator.addRect(rects.iconRect, [=](QRectF drawBounds) { painter->setOpacity(1); painter->setPen(QPen(option.palette.color(QPalette::WindowText), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter->drawLine(drawBounds.topLeft(), drawBounds.bottomRight()); painter->drawLine(drawBounds.bottomLeft(), drawBounds.topRight()); }); } calculator.addRect(rects.arrowRect, [=](QRectF drawBounds) { painter->setOpacity(1); painter->drawPixmap(drawBounds.toRect(), QIcon::fromTheme("go-next").pixmap(drawBounds.toRect().size())); }); calculator.performPaint(); painter->restore(); } QSize PluginItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { PluginItemDelegatePrivate::Rects rects(option); QRect u = rects.iconRect; u = u.united(rects.textRect); u = u.united(rects.descRect); u.adjust(SC_DPI(-6), SC_DPI(-6), SC_DPI(6), SC_DPI(6)); return u.size(); } ================================================ FILE: desktop/systemsettings/pluginmanagement/pluginitemdelegate.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGINITEMDELEGATE_H #define PLUGINITEMDELEGATE_H #include struct PluginItemDelegatePrivate; class PluginItemDelegate : public QAbstractItemDelegate { Q_OBJECT public: explicit PluginItemDelegate(QObject* parent = nullptr); ~PluginItemDelegate(); signals: private: PluginItemDelegatePrivate* d; // QAbstractItemDelegate interface public: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; }; #endif // PLUGINITEMDELEGATE_H ================================================ FILE: desktop/systemsettings/pluginmanagement/pluginmanagement.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "pluginmanagement.h" #include "ui_pluginmanagement.h" #include #include #include #include "plugins/pluginmanager.h" #include "pluginmodel.h" #include "pluginitemdelegate.h" #include "managepluginpopover.h" #include #include struct PluginManagementPrivate { PluginModel* pluginModel; }; PluginManagement::PluginManagement() : StatusCenterPane(), ui(new Ui::PluginManagement) { ui->setupUi(this); d = new PluginManagementPrivate(); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->descriptionLabel->setFixedWidth(contentWidth); d->pluginModel = new PluginModel(); ui->pluginsList->setModel(d->pluginModel); ui->pluginsList->setItemDelegate(new PluginItemDelegate(this)); } PluginManagement::~PluginManagement() { delete d; delete ui; } void PluginManagement::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } QString PluginManagement::name() { return "SystemPluginManagement"; } QString PluginManagement::displayName() { return tr("Plugins"); } QIcon PluginManagement::icon() { return QIcon::fromTheme("preferences-system-plugins"); } QWidget* PluginManagement::leftPane() { return nullptr; } void PluginManagement::on_pluginsList_activated(const QModelIndex& index) { ManagePluginPopover* manager = new ManagePluginPopover(index.data(Qt::UserRole + 1).toUuid()); tPopover* popover = new tPopover(manager); popover->setPopoverWidth(SC_DPI(600)); connect(manager, &ManagePluginPopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); // connect(popover, &tPopover::dismissed, manager, &ManagePluginPopover::deleteLater); popover->show(this->window()); } void PluginManagement::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } ================================================ FILE: desktop/systemsettings/pluginmanagement/pluginmanagement.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUIGINMANAGEMENT_H #define PLUIGINMANAGEMENT_H #include namespace Ui { class PluginManagement; } struct PluginManagementPrivate; class PluginManagement : public StatusCenterPane { Q_OBJECT public: explicit PluginManagement(); ~PluginManagement(); private: Ui::PluginManagement* ui; PluginManagementPrivate* d; void changeEvent(QEvent* event); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); private slots: void on_pluginsList_activated(const QModelIndex& index); void on_titleLabel_backButtonClicked(); }; #endif // PLUIGINMANAGEMENT_H ================================================ FILE: desktop/systemsettings/pluginmanagement/pluginmanagement.ui ================================================ PluginManagement 0 0 515 481 Form 0 0 0 0 0 Plugins QFrame::NoFrame true 0 0 515 464 0 0 0 0 0 Plugins add core and extra functionality to theDesk. 9 16777215 1 Qt::Horizontal QFrame::NoFrame tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: desktop/systemsettings/pluginmanagement/pluginmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "pluginmodel.h" #include #include #include #include "plugins/pluginmanager.h" PluginModel::PluginModel(QObject* parent) : QAbstractListModel(parent) { connect(PluginManager::instance(), &PluginManager::pluginsChanged, this, [ = ] { emit dataChanged(index(0), index(rowCount())); }); } int PluginModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return PluginManager::instance()->availablePlugins().count(); } QVariant PluginModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); PluginManager* plugins = PluginManager::instance(); QUuid uuid = plugins->availablePlugins().at(index.row()); switch (role) { case Qt::DisplayRole: return plugins->pluginMetadata(uuid, "name").toString(); case Qt::DecorationRole: return QIcon::fromTheme(plugins->pluginMetadata(uuid, "icon").toString(), QIcon::fromTheme("generic-app")); case Qt::UserRole: { if (plugins->loadedPlugins().contains(uuid)) { return tr("Loaded"); } else if (plugins->blacklistedPlugins().contains(uuid)) { return tr("Blacklisted"); } else if (plugins->erroredPlugins().contains(uuid)) { return tr("Unavailable"); } else { return tr("Inactive"); } } case Qt::UserRole + 1: return uuid; case Qt::UserRole + 2: return plugins->loadedPlugins().contains(uuid); case Qt::UserRole + 3: return plugins->blacklistedPlugins().contains(uuid); } return QVariant(); } ================================================ FILE: desktop/systemsettings/pluginmanagement/pluginmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGINMODEL_H #define PLUGINMODEL_H #include class PluginModel : public QAbstractListModel { Q_OBJECT public: explicit PluginModel(QObject *parent = nullptr); // Basic functionality: int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; private: }; #endif // PLUGINMODEL_H ================================================ FILE: desktop/systemsettings/recovery/recovery.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "recovery.h" #include "ui_recovery.h" #include #include #include #include #include Recovery::Recovery() : StatusCenterPane(), ui(new Ui::Recovery) { ui->setupUi(this); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->resetDEContainer->setFixedWidth(contentWidth); ui->resetDeviceContainer->setFixedWidth(contentWidth); ui->resetDEButton->setProperty("type", "destructive"); ui->resetDeviceButton->setProperty("type", "destructive"); if (libContemporaryCommon::searchInPath("scallop-reset-ui").isEmpty()) { ui->resetDeviceContainer->setVisible(false); ui->resetDeviceLine->setVisible(false); } } Recovery::~Recovery() { delete ui; } void Recovery::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } QString Recovery::name() { return "SystemRecovery"; } QString Recovery::displayName() { return tr("Recovery"); } QIcon Recovery::icon() { return QIcon::fromTheme("preferences-system-danger"); } QWidget* Recovery::leftPane() { return nullptr; } void Recovery::on_resetDEButton_clicked() { QMetaObject::Connection* c = new QMetaObject::Connection(); *c = connect(StateManager::instance()->powerManager(), &PowerManager::powerOffOperationCommencing, this, [=] { disconnect(*c); // Clear the settings tSettings settings; settings.clear(); settings.sync(); tSettings platformSettings("theDesk.platform"); platformSettings.clear(); platformSettings.sync(); }); StateManager::instance()->powerManager()->showPowerOffConfirmation(PowerManager::LogOut, tr("%1, log out and reset theDesk settings? This action is irreversible.\n\nWe'll go ahead and reset your settings in %n seconds if you don't do anything."))->then([=] { disconnect(*c); delete c; }); } void Recovery::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void Recovery::on_resetDeviceButton_clicked() { QProcess::startDetached("scallop-reset-ui", QStringList()); StateManager::statusCenterManager()->hide(); } ================================================ FILE: desktop/systemsettings/recovery/recovery.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef RECOVERY_H #define RECOVERY_H #include namespace Ui { class Recovery; } class Recovery : public StatusCenterPane { Q_OBJECT public: explicit Recovery(); ~Recovery(); private: Ui::Recovery* ui; void changeEvent(QEvent* event); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); private slots: void on_resetDEButton_clicked(); void on_titleLabel_backButtonClicked(); void on_resetDeviceButton_clicked(); }; #endif // RECOVERY_H ================================================ FILE: desktop/systemsettings/recovery/recovery.ui ================================================ Recovery 0 0 896 455 Form 0 0 0 0 0 Recovery QFrame::NoFrame true 0 0 896 438 0 0 0 0 0 0 0 0 0 9 9 9 9 6 75 true RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. true Log Out and Reset theDesk .. 16777215 1 Qt::Horizontal 0 0 0 0 0 9 9 9 6 75 true RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. true Reset this device .. Qt::Vertical 20 115 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: desktop/systemsettings/systemsettings.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "systemsettings.h" #include "ui_systemsettings.h" #include #include #include #include #include "common/common.h" #include "systemsettingsleftpane.h" #include "statuscenter/statuscenterleftpane.h" #include #include "about/about.h" #include "recovery/recovery.h" #include "pluginmanagement/pluginmanagement.h" struct SystemSettingsPrivate { SystemSettingsLeftPane* leftPane; StatusCenterLeftPane* mainLeftPane; QList> loadedPanes; QMap paneItems; QStringList preferredPaneOrder; tSettings settings; }; SystemSettings::SystemSettings(StatusCenterLeftPane* leftPane) : StatusCenterPane(), ui(new Ui::SystemSettings) { ui->setupUi(this); d = new SystemSettingsPrivate(); d->mainLeftPane = leftPane; d->leftPane = new SystemSettingsLeftPane(); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Lift); d->preferredPaneOrder = d->settings.delimitedList("StatusCenter/settingsOrder"); connect(StateManager::statusCenterManager(), &StatusCenterManager::paneAdded, this, [ = ](StatusCenterPane * pane, StatusCenterManager::PaneType type) { if (type == StatusCenterManager::SystemSettings) { this->addPane(pane); } }); connect(StateManager::statusCenterManager(), &StatusCenterManager::paneRemoved, this, &SystemSettings::removePane); for (StatusCenterPane* pane : StateManager::statusCenterManager()->panes()) { if (StateManager::statusCenterManager()->paneType(pane) == StatusCenterManager::SystemSettings) this->addPane(pane); } connect(d->leftPane, &SystemSettingsLeftPane::indexChanged, this, QOverload::of(&SystemSettings::selectPane)); connect(d->leftPane, &SystemSettingsLeftPane::enterMenu, this, &SystemSettings::enterMenu); connect(StateManager::statusCenterManager(), QOverload::of(&StatusCenterManager::paneRequest), this, [ = ](QString paneName) { for (StatusCenterPane* pane : StateManager::statusCenterManager()->panes()) { if (pane->name() == paneName) { if (StateManager::statusCenterManager()->paneType(pane) == StatusCenterManager::SystemSettings) { selectPane(pane); } } } }); connect(StateManager::statusCenterManager(), QOverload::of(&StatusCenterManager::paneRequest), this, [ = ](StatusCenterPane * pane) { if (StateManager::statusCenterManager()->paneType(pane) == StatusCenterManager::SystemSettings) { selectPane(pane); } }); StateManager::statusCenterManager()->addPane(new About(), StatusCenterManager::SystemSettings); StateManager::statusCenterManager()->addPane(new Recovery(), StatusCenterManager::SystemSettings); StateManager::statusCenterManager()->addPane(new PluginManagement(), StatusCenterManager::SystemSettings); } SystemSettings::~SystemSettings() { d->leftPane->deleteLater(); delete d; delete ui; } void SystemSettings::selectPane(QString pane) { for (QPair loadedPane : d->loadedPanes) { if (loadedPane.first == pane) selectPane(loadedPane.second); } } void SystemSettings::selectPane(int index) { selectPane(d->loadedPanes.at(index).second); } void SystemSettings::selectPane(StatusCenterPane* pane) { ui->stackedWidget->setCurrentWidget(pane); if (pane->leftPane()) d->mainLeftPane->pushMenu(pane->leftPane()); d->paneItems.value(pane)->setSelected(true); } void SystemSettings::enterMenu(int index) { StatusCenterPane* pane = d->loadedPanes.at(index).second; if (pane->leftPane()) { if (d->mainLeftPane->peekMenu() != pane->leftPane()) d->mainLeftPane->pushMenu(pane->leftPane()); } else { StateManager::statusCenterManager()->hideStatusCenterHamburgerMenu(); } } void SystemSettings::addPane(StatusCenterPane* pane) { QListWidgetItem* item = new QListWidgetItem(); item->setText(pane->displayName()); item->setIcon(pane->icon()); connect(pane, &StatusCenterPane::displayNameChanged, this, [ = ] { if (d->paneItems.contains(pane)) { d->paneItems.value(pane)->setText(pane->displayName()); } }); connect(pane, &StatusCenterPane::iconChanged, this, [ = ] { if (d->paneItems.contains(pane)) { d->paneItems.value(pane)->setIcon(pane->icon()); } }); if (pane->leftPane()) { item->setData(Qt::UserRole, true); } d->paneItems.insert(pane, item); QStringList currentItems; for (QPair item : d->loadedPanes) { currentItems.append(item.first); } int index = Common::getInsertionIndex(d->preferredPaneOrder, currentItems, pane->name()); if (index == -1) { //Add it at the end ui->stackedWidget->addWidget(pane); d->leftPane->appendItem(item); d->loadedPanes.append({pane->name(), pane}); } else { //Add this chunk at the beginning ui->stackedWidget->insertWidget(index, pane); d->leftPane->insertItem(index, item); d->loadedPanes.insert(index, {pane->name(), pane}); } } void SystemSettings::removePane(StatusCenterPane* pane) { for (int i = 0; i < d->loadedPanes.count(); i++) { if (d->loadedPanes.at(i).second == pane) { QListWidgetItem* item = d->paneItems.take(pane); d->leftPane->removeItem(item); delete item; ui->stackedWidget->removeWidget(pane); d->loadedPanes.removeAt(i); return; } } } void SystemSettings::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } QString SystemSettings::name() { return "SystemSettings"; } QString SystemSettings::displayName() { return tr("System Settings"); } QIcon SystemSettings::icon() { return QIcon::fromTheme("preferences-system"); } QWidget* SystemSettings::leftPane() { return d->leftPane; } ================================================ FILE: desktop/systemsettings/systemsettings.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SYSTEMSETTINGS_H #define SYSTEMSETTINGS_H #include namespace Ui { class SystemSettings; } class StatusCenterLeftPane; struct SystemSettingsPrivate; class SystemSettings : public StatusCenterPane { Q_OBJECT public: explicit SystemSettings(StatusCenterLeftPane* leftPane); ~SystemSettings(); private: Ui::SystemSettings* ui; SystemSettingsPrivate* d; void selectPane(QString pane); void selectPane(StatusCenterPane* pane); void selectPane(int index); void enterMenu(int index); void addPane(StatusCenterPane* pane); void removePane(StatusCenterPane* pane); void changeEvent(QEvent* event); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); }; #endif // SYSTEMSETTINGS_H ================================================ FILE: desktop/systemsettings/systemsettings.ui ================================================ SystemSettings 0 0 400 300 Form 0 0 0 0 0 tStackedWidget QStackedWidget
tstackedwidget.h
1
================================================ FILE: desktop/systemsettings/systemsettingsleftpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "systemsettingsleftpane.h" #include "ui_systemsettingsleftpane.h" #include "../statuscenter/leftpanedelegate.h" #include #include #include #include #include struct SystemSettingsLeftPanePrivate { bool isShowingLogOutRequired = false; }; SystemSettingsLeftPane::SystemSettingsLeftPane(QWidget* parent) : QWidget(parent), ui(new Ui::SystemSettingsLeftPane) { ui->setupUi(this); d = new SystemSettingsLeftPanePrivate(); ui->titleLabel->setBackButtonShown(true); ui->mainList->setIconSize(SC_DPI_T(QSize(32, 32), QSize)); ui->mainList->setItemDelegate(new LeftPaneDelegate(this)); ui->logoutRequiredWidget->setFixedHeight(0); ui->logoutRequiredWidget->setVisible(false); ui->logoutButton->setProperty("type", "destructive"); connect(StateManager::statusCenterManager(), &StatusCenterManager::requestLogout, this, [=] { if (d->isShowingLogOutRequired) return; d->isShowingLogOutRequired = true; tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(0); anim->setEndValue(ui->logoutRequiredWidget->sizeHint().height()); anim->setDuration(250); anim->setEasingCurve(QEasingCurve::OutCubic); connect(anim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { ui->logoutRequiredWidget->setFixedHeight(value.toInt()); }); connect(anim, &tVariantAnimation::finished, anim, &tVariantAnimation::deleteLater); anim->start(); ui->logoutRequiredWidget->setVisible(true); }); } SystemSettingsLeftPane::~SystemSettingsLeftPane() { delete d; delete ui; } void SystemSettingsLeftPane::appendItem(QListWidgetItem* item) { ui->mainList->addItem(item); } void SystemSettingsLeftPane::insertItem(int index, QListWidgetItem* item) { ui->mainList->insertItem(index, item); } void SystemSettingsLeftPane::removeItem(QListWidgetItem* item) { ui->mainList->removeItemWidget(item); } void SystemSettingsLeftPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->returnToRootMenu(); } void SystemSettingsLeftPane::on_mainList_currentRowChanged(int currentRow) { emit indexChanged(currentRow); } void SystemSettingsLeftPane::on_mainList_clicked(const QModelIndex& index) { emit enterMenu(index.row()); } void SystemSettingsLeftPane::on_logoutButton_clicked() { StateManager::instance()->powerManager()->showPowerOffConfirmation(PowerManager::LogOut); } void SystemSettingsLeftPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } ================================================ FILE: desktop/systemsettings/systemsettingsleftpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SYSTEMSETTINGSLEFTPANE_H #define SYSTEMSETTINGSLEFTPANE_H #include namespace Ui { class SystemSettingsLeftPane; } class QListWidgetItem; struct SystemSettingsLeftPanePrivate; class SystemSettingsLeftPane : public QWidget { Q_OBJECT public: explicit SystemSettingsLeftPane(QWidget* parent = nullptr); ~SystemSettingsLeftPane(); void appendItem(QListWidgetItem* item); void insertItem(int index, QListWidgetItem* item); void removeItem(QListWidgetItem* item); signals: void indexChanged(int index); void enterMenu(int index); private slots: void on_titleLabel_backButtonClicked(); void on_mainList_currentRowChanged(int currentRow); void on_mainList_clicked(const QModelIndex& index); void on_logoutButton_clicked(); private: Ui::SystemSettingsLeftPane* ui; SystemSettingsLeftPanePrivate* d; void changeEvent(QEvent* event); }; #endif // SYSTEMSETTINGSLEFTPANE_H ================================================ FILE: desktop/systemsettings/systemsettingsleftpane.ui ================================================ SystemSettingsLeftPane 0 0 307 456 Form 0 0 0 0 0 System Settings QFrame::NoFrame 0 0 0 0 0 16777215 1 Qt::Horizontal 6 9 9 9 9 75 true LOG OUT You've changed some settings that require you to log out for them to apply completely true Qt::Horizontal 40 20 Log Out tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: desktop/thedesk.conf ================================================ [Onboarding] lastOnboarding=0 order=OnboardingWelcome:OnboardingBetaThankYou:OnboardingRegion:OnboardingNetwork:OnboardingTheme:OnboardingFinal onboardingVideo=true onboardingAudio=true audio.start=/usr/share/thedesk/media/intro.ogg audio.loop=/usr/share/thedesk/media/loop.ogg videos.start=/usr/share/thedesk/media/welcome1.webm videos.middle=/usr/share/thedesk/media/welcome2.webm videos.loop=/usr/share/thedesk/media/welcome3.webm welcomeGraphic=:/libthedesk/images/splash-background.svg [StatusCenter] panesOrder=OverviewPane:NetworkManagerPane:NotificationsPane quickSwitchOrder=NetworkFlight:NetworkWireless:NetworkCellular:Bluetooth:PowerStretch:Redshift settingsOrder=BluetoothSettings:DisplaySettings:ThemeSettings:InputSettings:PowerSettings:LocaleSettings:UsersSettings:DateTimeSettings:DefaultAppsSettings:AccessibilitySettings:SystemPluginManagement:SystemRecovery:SystemAbout [Locale] locales=en formats=en_US [Plugins] blacklist= [Appearance] translucent=true [Display] dpi=96 [Session] UseInitializationScript=false InitializationScript=/etc/thedesk/init_thedesk.sh WindowManager=kwin_x11 WindowManagerArguments=--replace:--no-kactivities ================================================ FILE: desktop/translations/ar_SA.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/au_AU.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/cy.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/da.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/de.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/en_AU.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. Hey %1, ready to head out? We'll %2 in %n second if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/en_CA.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/en_GB.ts ================================================ About DISTRIBUTION DISTRIBUTION You're using You're using Device Name Device Name Processor Processor THIS DEVICE THIS DEVICE Available Memory Available Memory Available Swap Available Swap Qt Version Qt Version Kernel Version Kernel Version Change Device Name Change Device Name Window System Device Type Video Desktop Environment Desktop Environment Website Website File Bug File Bug Sources Sources View Debug Log View Debug Log Acknowledgements Acknowledgements Unknown Unknown theDesk %1 - Blueprint theDesk %1 - Blueprint You compiled theDesk on %1 You compiled theDesk on %1 theDesk %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About About Acknowledgements Acknowledgements Acknowledgements AppSearchProvider Application Application AppSelectionModel Application Application Background Sorry, there was a problem displaying the background. Sorry, there was a problem displaying the background. Try Again Try Again Background Background IMAGE IMAGE Select an image to display on your background and lock screen Select a photograph to display on your background and lock screen COMMUNITY BACKGROUNDS COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Images from the theDesk community will be cycled through every so often. Show image information Show image information STRETCH STRETCH Select how you'd like the background image to be sized Select how you'd like your background image to be sized Stretch To Fit Stretch To Fit Zoom and Crop Zoom and Crop Center Center Tile Tile Zoom To Fit Zoom To Fit Change Background Change Background End Session End Session by %1 by %1 For desktop For desktop Select Background Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name Change Device Name New Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Network Compatible Name Rename this Device Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager Internal use; the path to a local socket to communicate with the session manager path path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session End Session Power Off Power Off Turns off your computer. Turns off your computer. Reboot Reboot Turns off your computer and turns it on again Turns off your computer and turns it on again Reboot and install updates Reboot and install updates Turns off your computer, installs pending updates and turns it on again Turns off your computer, installs pending updates and turns it on again Log Out Log Out Ends your session but keeps your computer on for other people to use Ends your session but keeps your computer on for other people to use Suspend Suspend Puts your computer in a low power state so it reopens quickly Puts your computer in a low power state so it reopens quickly Lock Lock Locks your workspace with your password Locks your workspace with your password Turn Off Screen Turn Off Screen Turns off the screen, but keeps everything else running in the background Turns off the screen, but keeps everything else running in the background Switch Users Switch Users Switches to the logon screen, but keeps your session in the background Switches to the logon screen, but keeps your session in the background Hibernate Hibernate Powers off your computer, but restores the session when powered back on Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Updates are available. What would you like to do? Reboot and update Reboot and update We'll perform system updates once this device has rebooted. We'll perform system updates once this device has rebooted. We'll reboot your device normally. We'll reboot your device normally. power off the system power off the system reboot the system reboot the system reboot the system and install any pending updates reboot the system and install any pending updates log you out log you out suspend the system suspend the system lock the screen lock the screen turn off the screen turn off the screen switch users switch users hibernate the system hibernate the system Advanced Reboot Advanced Reboot Reboot into System UEFI Setup Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway Gateway CATEGORIES All Apps Preparing the Gateway... Preparing the Gateway... Type to search... Type to search... Status Center Status Center System Settings System Preferences End Session End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ERROR DETAILS ACTIONS ACTIONS Activate Plugin Activate Plugin Deactivate Plugin Deactivate Plugin Blacklist Plugin Blacklist Plugin Remove Plugin from Blacklist Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 UUID: %1 PluginManagement Plugins Plugins Plugins add core and extra functionality to theDesk. Plugins add core and extra functionality to theDesk. PluginModel Loaded Loaded Blacklisted Blacklisted Unavailable Unavailable Inactive Inactive Recovery Recovery Recovery RESET THEDESK RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User preferences will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. %1, log out and reset theDesk preferences? This action is irreversible. We'll go ahead and reset your preferences in %n seconds if you don't do anything. RunDialog Run Run Enter a command to run. Enter a command to run. Run this command Run this command StatusCenterLeftPane Status Center Status Center SystemSettings System Settings System Preferences SystemSettingsLeftPane System Settings System Preferences LOG OUT LOG OUT You've changed some settings that require you to log out for them to apply completely You've changed some preferences that require you to log out for them to apply completely Log Out Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/en_NZ.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. Hey %1, ready to head out? We'll %2 in %n second if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/en_US.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen Choose an image for your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Images from the theDesk community are cycled through occasionally. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager Internally; the path to a local socket that communicates with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Ends your session but keeps your computer on for others Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Locks your computer with your password Turn Off Screen Turn Off Display Turns off the screen, but keeps everything else running in the background Turns off the display, but keeps everything running Switch Users Switches to the logon screen, but keeps your session in the background Switches to the login screen, but keeps your session running Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll update your system after a reboot. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. Hey %1, ready to head out? We'll %2 in %n second if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Search here... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. Putting this plugin on the blacklist won't let it load the next time you log in. If it isn't already deactivated, it'll also be deactivated. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be reset - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while it's being reset. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. %1, log out and reset theDesk settings? This action is irreversible. We'll reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Some settings changed that require a log out to apply Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? The CTRL key was held. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/es.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/es_VE.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/fr_FR.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Version de Qt Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/id_ID.ts ================================================ About DISTRIBUTION DISTRIBUSI You're using Anda menggunakan Device Name Processor Prosesor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Lingkungan Desktop Website File Bug Sources View Debug Log Acknowledgements Unknown Tidak diketahui theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. Hak cipta © Victor Tran %1. Dilisensi di bawah ketentuan Lisensi Publik GNU (GNU GPL), versi 3 ke atas. About Tentang Acknowledgements Acknowledgements AppSearchProvider Application Aplikasi AppSelectionModel Application Aplikasi Background Sorry, there was a problem displaying the background. Maaf, terdapat masalah menampilkan background. Try Again Coba Lagi Background IMAGE Select an image to display on your background and lock screen Pilihlah gambar untuk dipakai sebagai background desktop serta lockscreen COMMUNITY BACKGROUNDS BACKGROUND KOMUNITAS Images from the theDesk community will be cycled through every so often. Gambar dari komunitas theDesk akan diganti secara berkala. Show image information Tampilkan informasi mengenai gambar STRETCH BENTANGAN Select how you'd like the background image to be sized Pilih cara menampilkan background Stretch To Fit Regang Agar Sesuai Zoom and Crop Besarkan dengan Pemotongan Center Taruh di Tengah Tile Mengubin Zoom To Fit Besarkan Agar Sesuai Change Background Ganti Background End Session Akhiri Sesi by %1 oleh %1 For desktop Untuk desktop Select Background Pilih Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Mulai theDesk dalam Mode Aman Internal use; the path to a local socket to communicate with the session manager Pemakaian internal saja; lokasi soket lokal untuk berkomunikasi dengan manajer sesi path lokasi CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Akhiri Sesi Power Off Matikan Turns off your computer. Mematikan komputer Anda. Reboot Nyalakan ulang Turns off your computer and turns it on again Mematikan komputer Anda kemudian menyalakannya lagi Reboot and install updates Nyalakan ulang dan install update Turns off your computer, installs pending updates and turns it on again Mematikan komputer Anda, menginstall update kemudian menyalakannya lagi Log Out Keluar Ends your session but keeps your computer on for other people to use Mengakhiri sesi Anda namun membiarkan komputer menyala agar dapat dipakai orang lain Suspend Puts your computer in a low power state so it reopens quickly Membuat komputer berjalan dengan daya rendah agar dapat dibuka kembali dengan cepat Lock Kunci Locks your workspace with your password Mengunci komputer dengan password Anda Turn Off Screen Matikan Layar Turns off the screen, but keeps everything else running in the background Mematikan layar, namun aplikasi-aplikasi akan tetap berjalan Switch Users Ganti User Switches to the logon screen, but keeps your session in the background Menampilkan logon screen, namun sesi Anda akan tetap berjalan Hibernate Hibernasi Powers off your computer, but restores the session when powered back on Mematikan komputer, namun mengembalikan sesi Anda ketika dinyalakan kembali Updates are available. What do you want to do? Update tersedia. Apa yang ingin Anda lakukan? Reboot and update Nyalakan ulang dan update We'll perform system updates once this device has rebooted. Sistem akan di-update setelah dinyalakan kembali. We'll reboot your device normally. Sistem akan reboot seperti biasa. power off the system matikan sistem reboot the system menyalakan ulang sistem reboot the system and install any pending updates nyalakan ulang sistem dan install update-update yang menunggu log you out me-logout suspend the system menonaktifkan sistem lock the screen mengunci desktop turn off the screen mematikan layar switch users mengganti user hibernate the system menonaktifkan sistem Advanced Reboot Reboot Lanjutan Reboot into System UEFI Setup Reboot ke Pengaturan UEFI Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. Hey %1, ingin keluar? Kami akan %2 dalam %n detik jika Anda tak melakukan apa-apa. MainGatewayWidget Gateway Gerbang CATEGORIES All Apps Preparing the Gateway... Menyiapkan Gerbang Aplikasi... Type to search... Ketik untuk mencari... Status Center Status Umum System Settings Pengaturan Sistem End Session Akhiri Sesi A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS RINCIAN ERROR ACTIONS AKSI Activate Plugin Aktifkan Plugin Deactivate Plugin Nonaktifkan Plugin Blacklist Plugin Larang Plugin Remove Plugin from Blacklist Bolehkan Plugin Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. Melarang plugin untuk diaktifkan dalam login selanjutnya. Jika belum dinonaktifkan, melarang plugin juga akan menonaktifkan plugin tersebut. UUID: %1 PluginManagement Plugins Plugin Plugins add core and extra functionality to theDesk. Plugin menambahkan fitur pada theDesk. PluginModel Loaded Blacklisted Dilarang Unavailable Tidak Ada Inactive Tidak Aktif Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Jika theDesk tidak berjalan semestinya, mungkin me-reset akan membantu. Hal berikut akan terjadi: - Pengaturan user akan terhapus dan kembali ke default - Ketika masuk kembali ke theDesk, Anda harus menjalani setup lagi Simpan pekerjaan Anda dan tutup semua aplikasi sebelum me-reset. Ini tidak akan memakan waktu lama, namun saat me-reset Anda akan logout. Anda belum dapat memakai sistem saat reset sedang berlangsung. Log Out and Reset theDesk Keluar dan Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. %1, keluar dan reset pengaturan theDesk? Pengaturan Anda tidak dapat dikembalikan. Pengaturan theDesk akan reset dalam %n detik jika Anda tak melakukan apa-apa. RunDialog Run Jalankan Enter a command to run. Masukkan perintah untuk dijalankan. Run this command Jalankan perintah ini StatusCenterLeftPane Status Center Status Umum SystemSettings System Settings Pengaturan Sistem SystemSettingsLeftPane System Settings Pengaturan Sistem LOG OUT KELUAR You've changed some settings that require you to log out for them to apply completely Anda telah mengganti beberapa pengaturan yang mengharuskan Anda log out terlebih dahulu agar dapat diterapkan Log Out Keluar TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode Mode Aman You're holding the CTRL key. Start theDesk in Safe Mode? Anda sedang menekan tombol CTRL. Mulai theDesk dalam Mode Aman? ================================================ FILE: desktop/translations/ja.ts ================================================ About DISTRIBUTION You're using Device Name デバイスの名前 Processor THIS DEVICE このデバイス Available Memory Available Swap Qt Version Kernel Version Change Device Name 構築の名前を変更する Window System Device Type Video Desktop Environment Website ウェブサイト File Bug Sources ソースコード View Debug Log デバッグの履歴を見る Acknowledgements 認知 Unknown 未知 theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About 情報 Acknowledgements Acknowledgements 礼状 AppSearchProvider Application アプリケーション AppSelectionModel Application アプリケーション Background Sorry, there was a problem displaying the background. Try Again Background 背景 IMAGE 映像 Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH 伸ばす Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center 中心 Tile Zoom To Fit Change Background 壁紙を変更する End Session セッションを終了する by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name 構築の名前を変更する New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device 構築の名前を変更する ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path 経路 CurrentAppWidgetMenu Close Window ウィンドウを終了する QUIT IMMEDIATELY すぐに止める Cancel 止める Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session セッションを終了する Power Off 電源を消す Turns off your computer. コンピューターを消す Reboot 再起動 Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out ログアウト Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock セッションをロックする Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session セッションを終了する A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out ログアウト TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/nl.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/pl_PL.ts ================================================ About DISTRIBUTION DYSTRYBUCJA You're using Używasz Device Name Processor Procesor THIS DEVICE Available Memory Dostępna Pamięć Available Swap Dostępne Swap Qt Version Wesja Qt Kernel Version Wesrsja Kernel Change Device Name Window System Device Type Video Desktop Environment Pulpit Website Strona Internetowa File Bug Błąd Pliku Sources Żródła View Debug Log Acknowledgements Unknown Nieznany theDesk %1 - Blueprint Program theDesk %1 - Blueprint You compiled theDesk on %1 Skompilowałeś theDesk na %1 theDesk %1 Program theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. Prawa Autorskie © Victor Tran %1. Licencjonowany na warunkach GNU General Public Licence, wersja 3 lub dalej. About O Acknowledgements Acknowledgements AppSearchProvider Application Aplikacja AppSelectionModel Application Aplikacja Background Sorry, there was a problem displaying the background. Przepraszam, wystąpił problem z wyświetlaniem tła. Try Again Spróbuj Ponownie Background Tło IMAGE OBRAZ Select an image to display on your background and lock screen Wybierz obraz do wyświetlania na tle i ekranie blokady COMMUNITY BACKGROUNDS TŁA ZE SPOŁECZNOŚCI Images from the theDesk community will be cycled through every so often. Obrazy ze społeczności theDesk będą cyklicznie zmieniane. Show image information Wyświetl informacje o obrazie STRETCH STRETCH Select how you'd like the background image to be sized Wybierz, w jaki sposób ma być zmieniany rozmiar obrazu tła Stretch To Fit Rozciągnij, aby dopasować Zoom and Crop Powiększanie i kadrowanie Center Środek Tile Efekt Płytek Zoom To Fit Powiększ, aby Dopasować Change Background Zmień Tło End Session Zakończ sesję by %1 przez %1 For desktop Dla tła pulpitu Select Background Wybierz Tło Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Startuj theDesk w trybie bezpieczeństwa Internal use; the path to a local socket to communicate with the session manager Wewnętrzny użytek; ścieżka do lokalnego gniazda do komunikacji z menedżerem sesji path ścieżka CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Zakończ tą Sesje Power Off Wyłącz Turns off your computer. Wyłącza twój komputer. Reboot Restartuj Turns off your computer and turns it on again Wyłacza twój komputer i ponownie włącza go Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Wyloguj Ends your session but keeps your computer on for other people to use Kończy sesję, ale utrzymuje komputer włączony, aby inni mogli z niego korzystać Suspend Zawieś Puts your computer in a low power state so it reopens quickly Przełącza komputer w stan niskiego zużycia energii, dzięki czemu szybko się ponownie otwiera Lock Zablokuj Locks your workspace with your password Blokuje obszar roboczy za pomocą hasła Turn Off Screen Wyłącz ekran Turns off the screen, but keeps everything else running in the background Wyłącza ekran, ale wszystko pozostaje działać w tle Switch Users Zamień Użytkownika Switches to the logon screen, but keeps your session in the background Przełącza na ekran logowania, ale utrzymuje twoją sesję w tle Hibernate Hibernacja Powers off your computer, but restores the session when powered back on Wyłącza komputer, ale przywraca sesję po ponownym włączeniu Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system wyłącz system reboot the system zrestartuj system reboot the system and install any pending updates log you out wylogować się suspend the system zawiesić system lock the screen zablokuj ekran turn off the screen wyłącz ekran switch users przełącz użytkowników hibernate the system hibernuj system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. Hej %1, gotowy do wyjścia? Otrzymamy %2 za %n sekund, jeśli nic nie zrobisz. MainGatewayWidget Gateway Brama CATEGORIES All Apps Preparing the Gateway... Przygotowywanie Bramy... Type to search... Wpisz aby wyszukać... Status Center Centrum Statusu System Settings Ustawienia Systemu End Session Zakończ Sesje A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS INFORMACJE O BŁĘDZIE ACTIONS AKCJA Activate Plugin Aktywuj wtyczkę Deactivate Plugin Dezaktywuj Wtyczkę Blacklist Plugin Umieść wtyczkę na czarnej liście Remove Plugin from Blacklist Usuń wtyczkę z czarnej listy Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. Umieszczenie tej wtyczki na czarnej liście zapobiegnie jej wczytaniu przy następnym logowaniu. Jeśli wtyczka nie została jeszcze dezaktywowana, również ją dla Ciebie dezaktywujemy. UUID: %1 UUID: %1 PluginManagement Plugins Wtyczki Plugins add core and extra functionality to theDesk. Wtyczki dodają główne i dodatkowe funkcje do theDesk. PluginModel Loaded Załadowane Blacklisted Na czarnej liście Unavailable Niedostępne Inactive Nieaktywny Recovery Recovery Naprawa RESET THEDESK RESETUJ THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Jeśli coś nie działa poprawnie, resetowanie theDesk może pomóc. Oto co się stanie: - Ustawienia użytkownika zostaną usunięte i przywrócone do wartości domyślnych - Następnym razem, gdy zalogujesz się do programu, będziesz musiał ponownie uruchomić konfigurację Zapisz dokumenty i zamknij wszystkie aplikacje przed rozpoczęciem resetowania. To nie potrwa długo, ale musisz się wylogować, aby wykonać reset. Podczas resetowania nie będzie można korzystać z urządzenia. Log Out and Reset theDesk Wyloguj i resetuj theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. %1, wylogować i resetować ustawienia theDesk? To działanie jest nieodwracalne. Pójdziemy i zresetujemy twoje ustawienia za %n sekund, jeśli nic nie zrobisz. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center Centrum Statusu SystemSettings System Settings Ustawienia Systemu SystemSettingsLeftPane System Settings Ustawienia Systemu LOG OUT WYLOGUJ You've changed some settings that require you to log out for them to apply completely Zmieniłeś niektóre ustawienia, które wymagają wylogowania, aby zostały całkowicie zastosowane Log Out Wyloguj TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode Tryb bezpieczeństwa You're holding the CTRL key. Start theDesk in Safe Mode? Trzymasz klawisz CTRL. Uruchomić theDesk w trybie awaryjnym? ================================================ FILE: desktop/translations/pt_BR.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/ro_RO.ts ================================================ About DISTRIBUTION DISTRIBUȚIE You're using Folosiți Device Name Nume dispozitiv Processor Procesor THIS DEVICE ACEST DISPOZITIV Available Memory Memorie disponibilă Available Swap Memorie Swap disponibilă Qt Version Versiune Qt Kernel Version Versiune nucleu Change Device Name Schimbă numele dispozitivului Window System Device Type Video Desktop Environment Mediu desktop Website Site web File Bug Raportați o problemă Sources Surse View Debug Log Vizualizați jurnalul de depanare Acknowledgements Recunoașteri Unknown Necunoscut theDesk %1 - Blueprint theDesk %1 - Blueprint You compiled theDesk on %1 Ați compilat theDesk pe data de %1 theDesk %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. Copyright © Victor Tran %1. Licențiat sub termenii licenței GNU General Public Licence, versiunea 3 sau ulterioară. About Despre Acknowledgements Acknowledgements Mulțumiri AppSearchProvider Application Aplicație AppSelectionModel Application Aplicația Background Sorry, there was a problem displaying the background. Ne pare rău, a intervenit o problemă la afișarea acestui fundal. Try Again Reîncercați Background Fundal IMAGE IMAGINE Select an image to display on your background and lock screen Selectați o imagine pentru a fi folosită ca și fundalul desktopului și al ecranului de blocare COMMUNITY BACKGROUNDS Fundaluri create de comunitate Images from the theDesk community will be cycled through every so often. Imaginile din comunitatea theDesk vor fi schimbate din când în când. Show image information Arată informații despre imagini STRETCH ÎNTINDERE Select how you'd like the background image to be sized Selectați cum ați dori să fie afișată imaginea de fundal Stretch To Fit Întinsă până la potrivire Zoom and Crop Mărită și decupată Center Centrată Tile În mozaic Zoom To Fit Mărită până se potrivește Change Background Schimbă fundalul End Session Închide sesiunea by %1 de %1 For desktop Pentru desktop Select Background Selectați fundalul Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name Schimbă numele dispozitivului New Device Name Noul nume al dispozitivului This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Numele acesta este folosit pentru a identifica dispozitivul în rețea cât și prin Bluetooth. Network Compatible Name Nume compatibil în rețea Rename this Device Redenumește dispozitivul ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Porniți theDesk în modul de siguranță Internal use; the path to a local socket to communicate with the session manager Uz intern; calea către un socket local de comunicare cu managerul de sesiune path cale CurrentAppWidgetMenu Close Window Închide fereastra QUIT IMMEDIATELY TERMINĂ IMEDIAT Cancel Anulare Force Stop Termină forțat Force Stop %1 Termină forțat %1 %1 will be forced to exit and won't have a chance to save any unsaved data. %1 va fi terminat forțat, iar toate datele nesalvate vor fi pierdute. EndSession End Session Închide sesiunea Power Off Oprire Turns off your computer. Oprește calculatorul. Reboot Repornire Turns off your computer and turns it on again Orpește calculatorul și îl pornește din nou Reboot and install updates Repornește și instalează actualizările Turns off your computer, installs pending updates and turns it on again Oprește calculatorul, instalează actualizările în așteptare și îl pornește din nou Log Out Deconectare Ends your session but keeps your computer on for other people to use Închide sesiunea dvs, dar menține calculatorul pornit pentru a putea fi folosit de alte persoane Suspend Suspendă Puts your computer in a low power state so it reopens quickly Pune calculatorul dvs într-o stare de consum redus, pentru redeschidere rapidă Lock Blocare Locks your workspace with your password Blochează spațiul dvs de lucru cu parola dvs Turn Off Screen Închide ecranul Turns off the screen, but keeps everything else running in the background Închide ecranul, dar menține programele deschise Switch Users Schimbă utilizatorul Switches to the logon screen, but keeps your session in the background Trece la ecranul de conectare, punând sesiunea curentă în fundal Hibernate Hibernare Powers off your computer, but restores the session when powered back on Oprește calculatorul, dar va restaura această sesiune la următoarea pornire Updates are available. What do you want to do? Sunt disponibile actualizări. Cum doriți să procedați? Reboot and update Repornește și actualizează We'll perform system updates once this device has rebooted. Vom aplica actualizările de îndată ce sistemul va reporni. We'll reboot your device normally. Dispozitivul va reporni ca de obicei. power off the system opri sistemul reboot the system reporni sistemul reboot the system and install any pending updates reporni sistemul și vom instala actualizările în așteptare log you out deconecta suspend the system suspenda sistemul lock the screen închide ecranul turn off the screen opri ecranul switch users schimba utilizatorul hibernate the system hibernăm sistemul Advanced Reboot Repornire avansată Reboot into System UEFI Setup Repornește în configurările UEFI ale sistemului Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. %1, sunteți gata de plecare? O să %2 în %n secunde dacă nu faceți nimic. MainGatewayWidget Gateway Portal CATEGORIES CATEGORII All Apps Toate aplicațiile Preparing the Gateway... Pregătim portalul... Type to search... Tastați pentru a căuta... Status Center Centrul de stare System Settings Configurări de sistem End Session Închide sesiunea A/V Audio/Video Development Dezvoltare Education Educație Games Jocuri Graphics Grafică Networking Rețelistică Office Birou Science Știință Utilities Utilitare Actions for %1 ManagePluginPopover ERROR DETAILS DETALII EROARE ACTIONS ACȚIUNI Activate Plugin Activează extensia Deactivate Plugin Dezactivează extensia Blacklist Plugin Pune extensia pe lista neagră Remove Plugin from Blacklist Elimină extensia de pe lista neagră Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. Plasarea acestei extensii pe lista neagră va împiedica pornirea sa la următoarea conectare. Extensia va fi dezactivată dacă nu este deja. UUID: %1 UUID: %1 PluginManagement Plugins Extensii Plugins add core and extra functionality to theDesk. Extensiile activează funcționalitățile theDesk și/sau adaugă unele noi. PluginModel Loaded În funcțiune Blacklisted Pe lista neagră Unavailable Indisponibilă Inactive Inactivă Recovery Recovery Recuperare RESET THEDESK RESETEAZĂ THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Dacă lucrurile nu merg cum trebuie puteți reseta theDesk. Ce se va întâmpla: - Setările dumneavoastră vor fi readuse la cele din fabrică - Atunci când vă veți conecta din nou în theDesk, va trebui să treceți prin procedura de configurare din nou Salvați-vă documentele și închideți toate aplicațiile deschise înainte de a începe. Resetarea nu va dura mult, dar va trebui să vă deconectați pentru a executa operațiunea. Nu vă veți putea folosi sistemul în timp ce se restaurează. Log Out and Reset theDesk Deconectați-vă și resetați theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. %1, doriți să vă deconectați și să resetați theDesk? Această acțiune este ireversibilă. O să continuăm cu resetarea în %n secunde dacă nu faceți nimic. RunDialog Run Execută Enter a command to run. Introduceți o comandă pentru a fi executată. Run this command Executați această comandă StatusCenterLeftPane Status Center Centrul de stare SystemSettings System Settings Configurări de sistem SystemSettingsLeftPane System Settings Configurări de sistem LOG OUT DECONECTARE You've changed some settings that require you to log out for them to apply completely Ați schimbat niște setări ce necesită să vă deconectați pentru a se putea aplica în totalitate Log Out Deconectare TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode Modul de siguranță You're holding the CTRL key. Start theDesk in Safe Mode? Țineți apăsata tasta CTRL. Porniți theDesk în modul de siguranță? ================================================ FILE: desktop/translations/sv.ts ================================================ About DISTRIBUTION You're using Device Name Processor THIS DEVICE Available Memory Available Swap Qt Version Kernel Version Change Device Name Window System Device Type Video Desktop Environment Website File Bug Sources View Debug Log Acknowledgements Unknown theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. About Acknowledgements Acknowledgements AppSearchProvider Application AppSelectionModel Application Background Sorry, there was a problem displaying the background. Try Again Background IMAGE Select an image to display on your background and lock screen COMMUNITY BACKGROUNDS Images from the theDesk community will be cycled through every so often. Show image information STRETCH Select how you'd like the background image to be sized Stretch To Fit Zoom and Crop Center Tile Zoom To Fit Change Background End Session by %1 For desktop Select Background Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode Internal use; the path to a local socket to communicate with the session manager path CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session Power Off Turns off your computer. Reboot Turns off your computer and turns it on again Reboot and install updates Turns off your computer, installs pending updates and turns it on again Log Out Ends your session but keeps your computer on for other people to use Suspend Puts your computer in a low power state so it reopens quickly Lock Locks your workspace with your password Turn Off Screen Turns off the screen, but keeps everything else running in the background Switch Users Switches to the logon screen, but keeps your session in the background Hibernate Powers off your computer, but restores the session when powered back on Updates are available. What do you want to do? Reboot and update We'll perform system updates once this device has rebooted. We'll reboot your device normally. power off the system reboot the system reboot the system and install any pending updates log you out suspend the system lock the screen turn off the screen switch users hibernate the system Advanced Reboot Reboot into System UEFI Setup Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. MainGatewayWidget Gateway CATEGORIES All Apps Preparing the Gateway... Type to search... Status Center System Settings End Session A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS ACTIONS Activate Plugin Deactivate Plugin Blacklist Plugin Remove Plugin from Blacklist Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. UUID: %1 PluginManagement Plugins Plugins add core and extra functionality to theDesk. PluginModel Loaded Blacklisted Unavailable Inactive Recovery Recovery RESET THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Log Out and Reset theDesk RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. RunDialog Run Enter a command to run. Run this command StatusCenterLeftPane Status Center SystemSettings System Settings SystemSettingsLeftPane System Settings LOG OUT You've changed some settings that require you to log out for them to apply completely Log Out TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode You're holding the CTRL key. Start theDesk in Safe Mode? ================================================ FILE: desktop/translations/tr_TR.ts ================================================ About DISTRIBUTION DAĞITIM You're using Kullanıyorsun Device Name Cihaz adı Processor İşlemci THIS DEVICE BU CİHAZ Available Memory Kullanılabilir Hafıza Available Swap Mevcut Takas Qt Version Qt Sürümü Kernel Version Çekirdek sürümü Change Device Name Cihaz Adını Değiştirin Window System Device Type Video Desktop Environment Masaüstü Ortamı Website İnternet sitesi File Bug Dosya Hatası Sources Kaynaklar View Debug Log Hata Ayıklama Günlüğünü Görüntüle Acknowledgements Alındılar Unknown Bilinmeyen theDesk %1 - Blueprint theDesk %1 - Blueprint You compiled theDesk on %1 theDesk %1 üzerinde derlediniz theDesk %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. Telif hakkı © Victor Tran %1. GNU Genel Kamu Lisansı, sürüm 3 veya üzeri koşulları kapsamında lisanslanmıştır. About Hakkında Acknowledgements Acknowledgements Alındılar AppSearchProvider Application Uygulama AppSelectionModel Application Uygulama Background Sorry, there was a problem displaying the background. Üzgünüz, arka planı görüntülerken bir sorun oluştu. Try Again Tekrar deneyin Background Arka fon IMAGE Resim Select an image to display on your background and lock screen Arka planınızda ve kilit ekranınızda görüntülenecek bir resim seçin COMMUNITY BACKGROUNDS TOPLULUK ARKA PLANLARI Images from the theDesk community will be cycled through every so often. theDesk topluluğundaki görseller ara sıra gözden geçirilir. Show image information Görüntü bilgilerini göster STRETCH UZATMAK Select how you'd like the background image to be sized Arka plan resminin nasıl boyutlandırılmasını istediğinizi seçin Stretch To Fit Sığacak şekilde uzatmak Zoom and Crop Yakınlaştır ve Kırp Center Merkez Tile Fayans Zoom To Fit Sığdırmak İçin Yakınlaştır Change Background Arka Planı Değiştir End Session Oturumu Sonlandır by %1 %1 tarafından For desktop Masaüstü için Select Background Arkaplan seç Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name Cihaz Adını Değiştirin New Device Name Yeni Cihaz Adı This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Bu cihaz adı, bu cihazı tanımlamak için ağ üzerinden kullanılır. Bu cihazı Bluetooth üzerinden tanımlamak için de kullanılır. Network Compatible Name Ağ Uyumlu Ad Rename this Device Rename This Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode theDesk Güvenli Modda başlatın Internal use; the path to a local socket to communicate with the session manager İç kullanım; oturum yöneticisi ile iletişim kurmak için yerel bir sokete giden yol path yol CurrentAppWidgetMenu Close Window Sekmeyi kapat QUIT IMMEDIATELY ŞİMDİ ÇIKIN Cancel İptal Force Stop Zorla durdurma Force Stop %1 %1 zorla durdurma %1 will be forced to exit and won't have a chance to save any unsaved data. %1 çıkmak zorunda kalacak ve kaydedilmemiş verileri kaydetme şansı olmayacak. EndSession End Session Oturum sonu Power Off Kapat Turns off your computer. Bilgisayarınızı kapatır. Reboot Yeniden başlat Turns off your computer and turns it on again Bilgisayarınızı kapatır ve tekrar açar Reboot and install updates Güncellemeleri yeniden başlatın ve yükleyin Turns off your computer, installs pending updates and turns it on again Bilgisayarınızı kapatır, bekleyen güncellemeleri yükler ve yeniden açar Log Out Çıkış Yap Ends your session but keeps your computer on for other people to use Oturumunuzu sonlandırır ancak bilgisayarınızı başkalarının kullanması için açık tutar Suspend Askıya al Puts your computer in a low power state so it reopens quickly Bilgisayarınızı düşük güç durumuna geçirir, böylece hızlı bir şekilde yeniden açılır Lock Kilit Locks your workspace with your password Çalışma alanınızı şifrenizle kilitler Turn Off Screen Ekranı Kapat Turns off the screen, but keeps everything else running in the background Ekranı kapatır, ancak diğer her şeyin arka planda çalışmasını sağlar Switch Users Kullanıcı Değiştir Switches to the logon screen, but keeps your session in the background Oturum açma ekranına geçer ancak oturumunuzu arka planda tutar Hibernate Hazırda beklet Powers off your computer, but restores the session when powered back on Bilgisayarınızı kapatır, ancak tekrar açıldığında oturumu geri yükler Updates are available. What do you want to do? Güncellemeler mevcuttur. Ne yapmak istiyorsun? Reboot and update Yeniden başlat ve güncelle We'll perform system updates once this device has rebooted. Bu cihaz yeniden başlatıldığında sistem güncellemelerini gerçekleştireceğiz. We'll reboot your device normally. Cihazınızı normal şekilde yeniden başlatacağız. power off the system sistemi kapat reboot the system sistemi yeniden başlat reboot the system and install any pending updates sistemi yeniden başlatın ve bekleyen güncellemeleri yükleyin log you out oturumu kapat suspend the system sistemi askıya almak lock the screen ekranı kilitle turn off the screen ekranı kapat switch users kullanıcıları değiştir hibernate the system sistemi hazırda bekletmek Advanced Reboot Gelişmiş Yeniden Başlatma Reboot into System UEFI Setup Sistem UEFI Kurulumunu Yeniden Başlatın Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. Hey %1, gitmeye hazır mısın? Eğer bir şey yapmazsan, %n saniye içinde %2 yapacağız. MainGatewayWidget Gateway Ağ geçidi CATEGORIES KATEGORİLER All Apps Tüm Uygulamalar Preparing the Gateway... Ağ Geçidini Hazırlama... Type to search... Aramak için yazın... Status Center Durum Merkezi System Settings Sistem Ayarları End Session Oturum sonu A/V A/V Development Gelişim Education Eğitim Games Oyunlar Graphics Grafik Networking Office Ofisçe Science Bilim Utilities Araçlar Actions for %1 ManagePluginPopover ERROR DETAILS HATA DETAYLARI ACTIONS HAREKETLER Activate Plugin Eklentiyi Etkinleştir Deactivate Plugin Eklentiyi Devre Dışı Bırak Blacklist Plugin Kara Liste Eklentisi Remove Plugin from Blacklist Eklentiyi Kara Listeden Kaldır Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. Bu eklentiyi kara listeye yerleştirmek, bir sonraki oturum açışınızda yüklenmesini engelleyecektir. Eklenti henüz devre dışı bırakılmamışsa, sizin için devre dışı bırakacağız. UUID: %1 UUID: %1 PluginManagement Plugins Eklentiler Plugins add core and extra functionality to theDesk. Eklentiler, theDesk'e çekirdek ve ekstra işlevsellik ekler. PluginModel Loaded Yüklü Blacklisted Kara listeye alındı Unavailable Kullanım dışı Inactive Etkin değil Recovery Recovery Kurtarma RESET THEDESK THEDESK'İ SIFIRLA If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. İşler düzgün çalışmıyorsa, theDesk sıfırlamak yardımcı olabilir. İşte ne olacak: - Kullanıcı ayarları temizlenir ve varsayılan olarak sıfırlanır - Bir dahaki sefere theDesk'e giriş yaptığınızda, kurulumu tekrar çalıştırmanız gerekir Sıfırlamaya başlamadan önce belgelerinizi kaydedin ve tüm uygulamaları kapatın. Bu uzun sürmez, ancak sıfırlamayı gerçekleştirmek için oturumu kapatmanız gerekir. Bunu sıfırlamak yer alıyor, cihazı kullanmak mümkün olmayacaktır. Log Out and Reset theDesk Oturumu Kapatın ve theDesk Sıfırlayın RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. %1, oturumu kapat ve çalışma masası Ayarlarını Sıfırla? Bu eylem geri döndürülemez. Hiçbir şey yapmazsanız, ayarlarınızı %n saniye içinde sıfırlayacağız. RunDialog Run Çalıştırmak Enter a command to run. Çalıştırmak için bir komut girin. Run this command Bu komutu çalıştırın StatusCenterLeftPane Status Center Durum Merkezi SystemSettings System Settings Sistem Ayarları SystemSettingsLeftPane System Settings Sistem Ayarları LOG OUT ÇIKIŞ YAP You've changed some settings that require you to log out for them to apply completely Tamamen uygulanmaları için oturumu kapatmanızı gerektiren bazı ayarları değiştirdiniz Log Out Çıkış yap TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode Güvenli mod You're holding the CTRL key. Start theDesk in Safe Mode? CTRL tuşunu basılı tutuyorsunuz. Güvenli modda theDesk başlatmak? ================================================ FILE: desktop/translations/vi_VN.ts ================================================ About DISTRIBUTION BẢN PHÂN PHỐI You're using Bạn đang sử dụng Device Name Tên thiết bị Processor Bộ xử lý THIS DEVICE THIẾT BỊ NÀY Available Memory Bộ nhớ trống Available Swap Bộ nhớ trao đổi trống Qt Version Phiên bản Qt Kernel Version Phiên bản Nhân HĐH Change Device Name Đổi tên thiết bị Window System Hệ thống cửa sổ Device Type Kiểu thiết bị Video Desktop Environment Môi trường Desktop Website Trang Web File Bug Báo cáo lỗi Sources Mã nguồn View Debug Log Xem nhật ký gỡ lỗi Acknowledgements Công nhận Unknown Không xác định theDesk %1 - Blueprint theDesk %1 - Blueprint You compiled theDesk on %1 Bạn biên dịch theDesk trong ngày %1 theDesk %1 theDesk %1 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. Bản Quyền © Victor Tran %1. Được cấp phép theo điều khoản của Giấy phép Công cộng GNU, phiên bản 3, hoặc mới hơn. About Giới Thiệu Acknowledgements Acknowledgements Công nhận AppSearchProvider Application Ứng Dụng AppSelectionModel Application Ứng Dụng Background Sorry, there was a problem displaying the background. Rất tiếc, chúng tôi gặp sự cố khi có hiển thị hình nền. Try Again Thử lại Background Hình nền IMAGE HÌNH ẢNH Select an image to display on your background and lock screen Chọn một hình ảnh để hiện trên bảng nền và màn hình khóa COMMUNITY BACKGROUNDS HÌNH NỀN CỘNG ĐỒNG Images from the theDesk community will be cycled through every so often. Hình ảnh từ cộng đồng theDesk sẽ được hiện lên và bị đổi thường xuyên. Show image information Hiển thị thông tin về hình ảnh STRETCH KÍCH THƯỚC Select how you'd like the background image to be sized Chọn cách bạn muốn hình nền có kích thước Stretch To Fit Căng để vừa Zoom and Crop Thu phóng và cắt Center Đặt trong giữa Tile Ngói Zoom To Fit Thu phóng để vừa Change Background Đổi hình ảnh nền End Session Kết phiên by %1 bởi %1 For desktop Cho bảng nền Select Background Chọn hình ảnh nền Set Background Đặt ảnh màn hình Set as Desktop Background Sử dụng cho ảnh màn hình Set as Lock Screen Background Sử dụng cho ảnh màn hình khóa Set for both Sử dụng cho cả hai ChangeHostnamePopover Change Device Name Đổi tên thiết bị New Device Name Tên thiết bị mới This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Tên thiết bị sẽ bị sử dụng qua mạng để nhận định thiết bị này. Nó cũng bị dùng để nhận định qua Bluetooth. Network Compatible Name Tên tương thích với mạng Rename this Device Đổi tên thiết bị này ChunkContainer Open Status Center Mở trạng thái CommandLine Start theDesk in Safe Mode Khởi chạy theBeat trong chế độ an toàn Internal use; the path to a local socket to communicate with the session manager Sử dụng nội bộ; đường dẫn đến ổ cắm nội bộ để liên hệ với với trình quản lý phiên path đường dẫn CurrentAppWidgetMenu Close Window Đóng cửa sổ QUIT IMMEDIATELY THOÁT NGAY Cancel Hủy Force Stop Buộc dừng Force Stop %1 Buộc dừng %1 %1 will be forced to exit and won't have a chance to save any unsaved data. %1 sẽ bị bắt buộc dừng lại, và sẽ không có cơ hội để lưu dữ liệu nào chưa được lưu. EndSession End Session Kết phiên Power Off Tắt nguồn Turns off your computer. Tắt máy tính của bạn. Reboot Khởi động lại Turns off your computer and turns it on again Tắt máy tính của bạn, rồi bật nó lại Reboot and install updates Khởi động lại và cài đặt bản cập nhật Turns off your computer, installs pending updates and turns it on again Tắt máy tính của bạn, cài bản cập nhật rồi bắt nó lại Log Out Đăng xuất Ends your session but keeps your computer on for other people to use Kết thúc phiên của bạn, nhưng vẫn giữ máy tính của bạn cho người khác sử dụng Suspend Tạm dừng Puts your computer in a low power state so it reopens quickly Đặt máy tính của bạn vào chế độ tiêu ít năng lượng để cho nó mở lại nhanh Lock Khóa phiên Locks your workspace with your password Khóa phiên của bạn với mật khẩu của bạn Turn Off Screen Tắt màn hình Turns off the screen, but keeps everything else running in the background Tắt màn hình, nhưng giữ mọi thứ khác chạy trong nền Switch Users Chuyển đổi người dùng Switches to the logon screen, but keeps your session in the background Chuyển đổi sang màn hình đăng nhập, nhưng giữ phiên của bạn trong nền Hibernate Ngủ đông Powers off your computer, but restores the session when powered back on Tắt máy tính của bạn, nhưng khôi phục phiên khi bật lại Updates are available. What do you want to do? Bản cập nhật đang chờ xử lý. Bạn muốn làm gì? Reboot and update Khởi động lại và cài We'll perform system updates once this device has rebooted. Chúng tôi sẽ thực hiện các bản cập nhật sau khi thiết bị này khởi động lại. We'll reboot your device normally. Chúng tôi sẽ khởi động lại bình thường. power off the system tắt hệ thống reboot the system khởi động hệ thống lại reboot the system and install any pending updates khởi động lại và cài các cập nhật chờ xử lý log you out đăng xuất bản suspend the system tạm dừng hệ thống lock the screen khóa màn hình turn off the screen tắt màn hình switch users chuyển đổi người dùng hibernate the system đặt hệ thống vào chế độ ngủ đông Advanced Reboot Khởi động lại nâng cao Reboot into System UEFI Setup Khởi động lại vào trình thiết lập UEFI hệ thống Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. %1, sẵn sàng rời đi chưa? Chúng tôi sẽ %2 sau %n giay nếu bạn không làm gì. MainGatewayWidget Gateway Cửa CATEGORIES THỂ LOẠI All Apps Các ứng dụng Preparing the Gateway... Đang chuẩn bị Cửa... Type to search... Gõ để tìm kiếm... Status Center Bảng Trạng thái System Settings Cài đặt hệ thống End Session Kết phiên A/V Âm thanh / Video Development Phát triển Education Giáo dục Games Trò chơi Graphics Đồ họa Networking Mạng Office Văn phòng Science Khoa học Utilities Tiện ích Actions for %1 Hoạt động cho %1 ManagePluginPopover ERROR DETAILS CHI TIẾT VỀ LỖI ACTIONS HOẠT ĐỘNG Activate Plugin Kích hoạt phần mở rộng Deactivate Plugin Vô hiệu phần mở rộng Blacklist Plugin Đặt phần mở rộng trên danh sách đen Remove Plugin from Blacklist Xóa phần mở rộng khỏi danh sách đen Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. Khi bạn đặt phần mở rộng này trên danh sách đen, bạn sẽ không cho nó tải khi bạn đăng nhập lần sau. Nếu phần mở rộng này chưa bị vô hiệu, chúng tôi cũng sẽ vô hiệu nó cho bạn. UUID: %1 UUID: %1 PluginManagement Plugins Phần mở rộng Plugins add core and extra functionality to theDesk. Phần mở rộng sẽ thêm vào tính năng cốt lõi và tính năng bổ sung vào theDesk. PluginModel Loaded Đã tải Blacklisted Trên danh sách đen Unavailable Không có sẵn Inactive Bị vô hiệu Recovery Recovery Khôi phục RESET THEDESK ĐẶT LẠI THEDESK If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. Nếu bạn có điều nào không có hoạt dụng đúng, bạn có thể đặt lại Word để xem nếu nó có khắc phục được sự cố không. Đây là những gì sẽ xảy ra: - Các cài đặt của bạn sẽ bị xóa và đặt lại mặc định - Lần sau bạn đăng nhập vào theDesk, bạn cần thực hiện các thiết lập lần đầu Lưu các tài liệu, và đóng các ứng dụng trước khi bạn bắt đầu đặt lại. Điều này sẽ không mất nhiều thời gian, nhưng bạn cần đăng xuất để thực hiện hoạt động đặt lại. Bạn không thể sử dụng thiết bị của bạn khi hoạt động đặt lại đang thực hiện. Log Out and Reset theDesk Đăng xuất và đặt lại theDesk RESET DEVICE ĐẶT LẠI THIẾT BỊ If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Nếu hoạt động đặt lại theDesk không giải quyết vấn đề, hoặc nếu bạn chỉ cần bắt đầu lại, bạn có thể đặt lại thiết bị này. Reset this device Đặt lại thiết bị này %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. %1, đăng xuất và đặt lại các cài đặt của theDesk? Hoạt động này sẽ không được bị hoàn tác. Chúng tôi sẽ đặt cài đặt của bạn lại sau %n giay nếu bạn không làm gì. RunDialog Run Chạy Enter a command to run. Điền vào một lệnh để chạy. Run this command Chạy lệnh này StatusCenterLeftPane Status Center Bảng Trạng thái SystemSettings System Settings Cài đặt hệ thống SystemSettingsLeftPane System Settings Cài đặt hệ thống LOG OUT ĐĂNG XUẤT You've changed some settings that require you to log out for them to apply completely Bạn đã thay đổi một số cài đặt yêu cầu bạn đăng xuất để áp dụng nó đầy đủ Log Out Đăng xuất TaskbarApplicationWidget Move to desktop Chuyển sang màn hình ảo For %1 Cho %1 All Desktops Các màn hình ảo New Desktop Màn hình ảo mới Close Đóng For %n %1 windows Cho %n cửa sổ %1 For %n windows Cho %n cửa sổ Close All Đóng tất cả main Safe Mode Chế độ an toàn You're holding the CTRL key. Start theDesk in Safe Mode? Bạn đang giữ nút CTRL. Khởi chạy theDesk vào chế độ an toàn? ================================================ FILE: desktop/translations/zh_CN.ts ================================================ About DISTRIBUTION 发行 You're using 你正在使用 Device Name Processor 处理器 THIS DEVICE Available Memory 可用内存 Available Swap 可用虚拟内存 Qt Version Qt 版本 Kernel Version 内核版本 Change Device Name Window System Device Type Video Desktop Environment 桌面环境 Website 网页 File Bug 上传Bug Sources 来源 View Debug Log Acknowledgements Unknown 未知 theDesk %1 - Blueprint theDesk %1 - 蓝图 You compiled theDesk on %1 你在 %1 编译了 theDesk theDesk %1 theDesk %1。 Copyright © Victor Tran %1. Licensed under the terms of the GNU General Public License, version 3 or later. 版权 © Victor Tran %1 根据GNU通用公共许可版本3或更高版本许可。 About 关于 Acknowledgements Acknowledgements AppSearchProvider Application 应用程序 AppSelectionModel Application 应用程序 Background Sorry, there was a problem displaying the background. 抱歉,显示背景时出现问题。 Try Again 请重试 Background 背景 IMAGE 图片 Select an image to display on your background and lock screen 选择要在背景和锁定屏幕上显示的图像 COMMUNITY BACKGROUNDS 社区背景 Images from the theDesk community will be cycled through every so often. 来自theDesk社区的图像循环播放。 Show image information 显示图片信息 STRETCH 拉伸 Select how you'd like the background image to be sized 选择你想要更换大小的背景 Stretch To Fit 拉抻到屏幕 Zoom and Crop 放大和裁剪 Center 居中 Tile 叠加 Zoom To Fit 放大以填充 Change Background 更换背景 End Session 结束进程 by %1 与 %1 For desktop 桌面 Select Background 选择背景 Set Background Set as Desktop Background Set as Lock Screen Background Set for both ChangeHostnamePopover Change Device Name New Device Name This device name is used over the network to identify this device. It is also used to identify this device over Bluetooth. Network Compatible Name Rename this Device ChunkContainer Open Status Center CommandLine Start theDesk in Safe Mode 在安全模式中启动theDesk Internal use; the path to a local socket to communicate with the session manager 内部使用; 与会话管理器进行通信的本地套接字的路径 path 路径 CurrentAppWidgetMenu Close Window QUIT IMMEDIATELY Cancel Force Stop Force Stop %1 %1 will be forced to exit and won't have a chance to save any unsaved data. EndSession End Session 结束进程 Power Off 关机 Turns off your computer. 将关闭你的计算机。 Reboot 重启 Turns off your computer and turns it on again 重启 Reboot and install updates 重启安装更新 Turns off your computer, installs pending updates and turns it on again 关机, 安装更新后重启 Log Out 注销 Ends your session but keeps your computer on for other people to use 结束会话,但让计算机保持打开状态以供其他人使用 Suspend 暂停 Puts your computer in a low power state so it reopens quickly 使您的计算机处于低功耗状态,因此快速重新打开 Lock 锁定 Locks your workspace with your password 锁定工作区域 Turn Off Screen 关闭屏幕 Turns off the screen, but keeps everything else running in the background 关闭屏幕,但让其他所有内容在后台运行 Switch Users 更换用户 Switches to the logon screen, but keeps your session in the background 切换到登录屏幕,但将会话保持在后台 Hibernate 休眠 Powers off your computer, but restores the session when powered back on 关闭计算机电源,但重新开机后恢复会话 Updates are available. What do you want to do? 有可用的更新。 你想让我做什么? Reboot and update 重启与安装更新 We'll perform system updates once this device has rebooted. 该设备重新启动后,我们将执行系统更新。 We'll reboot your device normally. 我们将正常重启您的设备。 power off the system 关闭系统 reboot the system 重启系统 reboot the system and install any pending updates 重新启动系统并安装所有挂起的更新 log you out 讲注销 suspend the system 休眠此系统 lock the screen 锁定屏幕 turn off the screen 关闭屏幕 switch users 更换用户 hibernate the system 休眠此系统 Advanced Reboot 高级重启 Reboot into System UEFI Setup 重新启动进入系统UEFI设置 Hey %1, ready to head out? We'll %2 in %n seconds if you don't do anything. 你好 %1, 准备出门了吗? 我们将 在 %2 %n 秒内将你登出。 MainGatewayWidget Gateway 网关 CATEGORIES All Apps Preparing the Gateway... 准备网关中。。。 Type to search... 输入以搜索。。。 Status Center 状态中心 System Settings 系统设置 End Session 结束进程 A/V Development Education Games Graphics Networking Office Science Utilities Actions for %1 ManagePluginPopover ERROR DETAILS 错误信息 ACTIONS 行动 Activate Plugin 启动插件 Deactivate Plugin 取消插件 Blacklist Plugin 黑名单插件 Remove Plugin from Blacklist 将此插件从黑名单中移除 Placing this plugin on the blacklist will prevent it from being loaded next time you log in. If the plugin is not already deactivated, we'll also deactivate it for you. 将此插件放置在黑名单上可防止您下次登录时加载该插件。如果尚未停用该插件,我们还将为您停用它。 UUID: %1 UUID: %1 PluginManagement Plugins 插件 Plugins add core and extra functionality to theDesk. 插件为theDesk添加了核心功能和额外功能。 PluginModel Loaded 已加载 Blacklisted 已加入黑名单 Unavailable 不可用 Inactive 待用 Recovery Recovery 复原 RESET THEDESK 重置TheDesk If things aren't working correctly, resetting theDesk might help. Here's what will happen: - User settings will be cleared and reset to defaults - The next time you log into theDesk, you'll need to run through the setup again Save your documents and close all apps before starting the reset. This won't take long, but you'll need to log out to perform the reset. You won't be able to use your device while the reset is taking place. 如果一切工作不正常,重置桌面可能会有所帮助。 将会发生以下情况: -用户设置将被清除并重置为默认值 -下次登录桌面时,您需要再次运行设置 在开始重置之前,请保存您的文档并关闭所有应用。 这不会花很长时间,但是您需要注销才能执行重置。 重置发生时,您将无法使用设备。 Log Out and Reset theDesk 注销并重置桌面 RESET DEVICE If resetting theDesk didn't work, or if you just need a fresh start, you can reset this device. Reset this device %1, log out and reset theDesk settings? This action is irreversible. We'll go ahead and reset your settings in %n seconds if you don't do anything. %1,注销并重置桌面设置? 此动作是不可逆的。 如果您什么都不做,我们将在%n秒内继续进行设置。 RunDialog Run 运行 Enter a command to run. 输入要运行的命令。 Run this command 运行此命令 StatusCenterLeftPane Status Center 状态中心 SystemSettings System Settings 系统设置 SystemSettingsLeftPane System Settings 系统设置 LOG OUT 注销 You've changed some settings that require you to log out for them to apply completely 您更改了一些设置,要求您注销才能完全应用 Log Out 注销 TaskbarApplicationWidget Move to desktop For %1 All Desktops New Desktop Close For %n %1 windows For %n windows Close All main Safe Mode 安全模式 You're holding the CTRL key. Start theDesk in Safe Mode? 您按住CTRL键。 以安全模式启动theDesk? ================================================ FILE: desktop-portal/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) project(xdg-portal VERSION 1.0.0 LANGUAGES C CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS WaylandClient) find_program(WAYLAND_SCANNER wayland-scanner) if(NOT WAYLAND_SCANNER) message(FATAL_ERROR "wayland-scanner not found!") endif() message(STATUS "Found wayland-scanner: ${WAYLAND_SCANNER}") find_program(QT_WAYLAND_SCANNER qtwaylandscanner) if(NOT QT_WAYLAND_SCANNER) message(FATAL_ERROR "qtwaylandscanner not found!") endif() message(STATUS "Found qtwaylandscanner: ${QT_WAYLAND_SCANNER}") function(portal_register_wayland_protocol_extension target) set(multiValueArgs FILES) cmake_parse_arguments(REGISTER_WAYLAND_PROTOCOL_EXTENSIONS "" "" "${multiValueArgs}" ${ARGN}) foreach(_file ${REGISTER_WAYLAND_PROTOCOL_EXTENSIONS_FILES}) get_filename_component(_basename ${_file} NAME_WE) # Wayland scanner add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.h" COMMAND ${WAYLAND_SCANNER} client-header ${CMAKE_CURRENT_SOURCE_DIR}/${_file} "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.h" DEPENDS ${_file} VERBATIM) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.c" COMMAND ${WAYLAND_SCANNER} public-code ${CMAKE_CURRENT_SOURCE_DIR}/${_file} "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.c" DEPENDS ${_file} VERBATIM) # Qt Wayland scanner add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.h" COMMAND ${QT_WAYLAND_SCANNER} client-header ${CMAKE_CURRENT_SOURCE_DIR}/${_file} > "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.h" DEPENDS ${_file} VERBATIM) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.cpp" COMMAND ${QT_WAYLAND_SCANNER} client-code ${CMAKE_CURRENT_SOURCE_DIR}/${_file} > "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.cpp" DEPENDS ${_file} VERBATIM) # Include in sources set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.cpp" PROPERTY SKIP_AUTOGEN ON) set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.h" PROPERTY SKIP_AUTOGEN ON) set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.c" PROPERTY SKIP_AUTOGEN ON) set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.h" PROPERTY SKIP_AUTOGEN ON) target_sources(${target} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.c" "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.h" "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.h" "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.cpp") endforeach() endfunction() find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network DBus) find_package(libcontemporary REQUIRED) find_package(libtdesktopenvironment REQUIRED) find_package(libthefrisbee REQUIRED) find_package(libthefile REQUIRED) set(SOURCES main.cpp portalhandle.cpp portalcommon.cpp screenshotmanager.cpp interfaces/filechooserinterface.cpp interfaces/settingsinterface.cpp interfaces/accessinterface.cpp interfaces/accountinterface.cpp interfaces/screenshotinterface.cpp interfaces/notificationinterface.cpp dialogs/filedialog.cpp dialogs/filedialog.ui dialogs/accountdialog.cpp dialogs/accountdialog.ui dialogs/screenshotwindow.cpp dialogs/screenshotwindow.ui dialogs/accessdialog.cpp dialogs/accessdialog.ui dialogs/penbutton.cpp backend/abstractportalbackend.cpp backend/x11portalbackend.cpp backend/waylandportalbackend.cpp backend/private/waylandportalscreencopyframe.h screenshot_resources.qrc ) set(HEADERS portalhandle.h portalcommon.h screenshotmanager.h interfaces/filechooserinterface.h interfaces/settingsinterface.h interfaces/accessinterface.h interfaces/accountinterface.h interfaces/screenshotinterface.h interfaces/notificationinterface.h dialogs/filedialog.h dialogs/accountdialog.h dialogs/screenshotwindow.h dialogs/penbutton.h dialogs/accessdialog.h backend/abstractportalbackend.h backend/x11portalbackend.h backend/waylandportalbackend.h backend/private/waylandportalscreencopyframe.cpp ) add_executable(xdg-portal ${SOURCES} ${HEADERS}) set_target_properties(xdg-portal PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_GUI_IDENTIFIER com.vicr123.thedesk.xdg-portal WIN32_EXECUTABLE TRUE CNTP_DATA_SUBDIR thedesk/portal) cntp_init(xdg-portal 20) cntp_translate(xdg-portal) cntp_target_name(xdg-portal "thedesk-desktop-portal") #cntp_defaults_file(xdg-portal # DEFAULTS_FILE xdg-portal.conf) portal_register_wayland_protocol_extension(xdg-portal FILES backend/wlr-screencopy-unstable-v1.xml ) target_link_libraries(xdg-portal Qt::Widgets Qt::Network Qt::DBus Qt::WaylandClient Qt::GuiPrivate libcontemporary libtdesktopenvironment libthedesk libthefile) target_include_directories(xdg-portal PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) install(TARGETS xdg-portal RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} BUNDLE DESTINATION /Applications) configure_file(org.freedesktop.impl.portal.desktop.thedesk.service.in ${CMAKE_BINARY_DIR}/org.freedesktop.impl.portal.desktop.thedesk.service) configure_file(xdg-desktop-portal-thedesk.service.in ${CMAKE_BINARY_DIR}/xdg-desktop-portal-thedesk.service) install(FILES thedesk.portal DESTINATION ${CMAKE_INSTALL_DATADIR}/xdg-desktop-portal/portals) install(FILES thedesk-portals.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/xdg-desktop-portal) install(FILES ${CMAKE_BINARY_DIR}/org.freedesktop.impl.portal.desktop.thedesk.service DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/services) install(FILES ${CMAKE_BINARY_DIR}/xdg-desktop-portal-thedesk.service DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/user/) ================================================ FILE: desktop-portal/backend/abstractportalbackend.cpp ================================================ #include "abstractportalbackend.h" #include "waylandportalbackend.h" #include "x11portalbackend.h" #include AbstractPortalBackend::AbstractPortalBackend(QObject* parent) : QObject{parent} { } AbstractPortalBackend* AbstractPortalBackend::instance() { static AbstractPortalBackend* instance = nullptr; if (!instance) { if (tX11Info::isPlatformX11()) { instance = new X11PortalBackend(); } else { instance = new WaylandPortalBackend(); } } return instance; } ================================================ FILE: desktop-portal/backend/abstractportalbackend.h ================================================ #ifndef ABSTRACTPORTALBACKEND_H #define ABSTRACTPORTALBACKEND_H #include #include #include class AbstractPortalBackend : public QObject { Q_OBJECT public: explicit AbstractPortalBackend(QObject* parent = nullptr); static AbstractPortalBackend* instance(); virtual QCoro::Task takeScreenshot(QScreen* screen) = 0; signals: }; #endif // ABSTRACTPORTALBACKEND_H ================================================ FILE: desktop-portal/backend/private/waylandportalscreencopyframe.cpp ================================================ #include "waylandportalscreencopyframe.h" #include #include #include #include #include struct WaylandPortalScreencopyFramePrivate { wl_shm* shm; wl_display* display; bool ok = false; QImage::Format qimageFormat; void* data; wl_buffer* buf; quint32 width; quint32 height; quint32 size; std::function transform; QImage image; }; WaylandPortalScreencopyFrame::WaylandPortalScreencopyFrame(struct ::zwlr_screencopy_frame_v1* object, wl_shm* shm, wl_display* display) : QObject{nullptr}, QtWayland::zwlr_screencopy_frame_v1{object} { d = new WaylandPortalScreencopyFramePrivate(); d->shm = shm; d->display = display; tDebug("WaylandPortalScreencopyFrame") << "Created screencopy frame"; } WaylandPortalScreencopyFrame::~WaylandPortalScreencopyFrame() { tDebug("WaylandPortalScreencopyFrame") << "Destroyed screencopy frame"; this->destroy(); delete d; } bool WaylandPortalScreencopyFrame::ok() { return d->ok; } QPixmap WaylandPortalScreencopyFrame::pixmap() { return QPixmap::fromImage(d->image); } void WaylandPortalScreencopyFrame::zwlr_screencopy_frame_v1_buffer(uint32_t format, uint32_t width, uint32_t height, uint32_t stride) { tDebug("WaylandPortalScreencopyFrame") << "Buffer f: " << format << " w: " << width << " h: " << height << " s: " << stride; wl_shm_format fmt = static_cast(format); d->qimageFormat = QImage::Format_Invalid; d->transform = [](quint32*, quint32) { }; // noop switch (fmt) { case WL_SHM_FORMAT_ARGB8888: d->qimageFormat = QImage::Format_ARGB32; break; case WL_SHM_FORMAT_XRGB8888: d->qimageFormat = QImage::Format_ARGB32; break; case WL_SHM_FORMAT_XBGR8888: d->qimageFormat = QImage::Format_ARGB32; d->transform = [](quint32* data, quint32 size) { for (auto i = 0; i < size; i++) { auto r = (data[i] >> 0) & 0xff; auto g = (data[i] >> 8) & 0xff; auto b = (data[i] >> 16) & 0xff; auto a = 0xff; data[i] = (a << 24) | (r << 16) | (g << 8) | b; } }; break; case WL_SHM_FORMAT_C8: case WL_SHM_FORMAT_RGB332: case WL_SHM_FORMAT_BGR233: case WL_SHM_FORMAT_XRGB4444: case WL_SHM_FORMAT_XBGR4444: case WL_SHM_FORMAT_RGBX4444: case WL_SHM_FORMAT_BGRX4444: case WL_SHM_FORMAT_ARGB4444: case WL_SHM_FORMAT_ABGR4444: case WL_SHM_FORMAT_RGBA4444: case WL_SHM_FORMAT_BGRA4444: case WL_SHM_FORMAT_XRGB1555: case WL_SHM_FORMAT_XBGR1555: case WL_SHM_FORMAT_RGBX5551: case WL_SHM_FORMAT_BGRX5551: case WL_SHM_FORMAT_ARGB1555: case WL_SHM_FORMAT_ABGR1555: case WL_SHM_FORMAT_RGBA5551: case WL_SHM_FORMAT_BGRA5551: case WL_SHM_FORMAT_RGB565: case WL_SHM_FORMAT_BGR565: case WL_SHM_FORMAT_RGB888: case WL_SHM_FORMAT_BGR888: case WL_SHM_FORMAT_RGBX8888: case WL_SHM_FORMAT_BGRX8888: case WL_SHM_FORMAT_ABGR8888: case WL_SHM_FORMAT_RGBA8888: case WL_SHM_FORMAT_BGRA8888: case WL_SHM_FORMAT_XRGB2101010: case WL_SHM_FORMAT_XBGR2101010: case WL_SHM_FORMAT_RGBX1010102: case WL_SHM_FORMAT_BGRX1010102: case WL_SHM_FORMAT_ARGB2101010: case WL_SHM_FORMAT_ABGR2101010: case WL_SHM_FORMAT_RGBA1010102: case WL_SHM_FORMAT_BGRA1010102: case WL_SHM_FORMAT_YUYV: case WL_SHM_FORMAT_YVYU: case WL_SHM_FORMAT_UYVY: case WL_SHM_FORMAT_VYUY: case WL_SHM_FORMAT_AYUV: case WL_SHM_FORMAT_NV12: case WL_SHM_FORMAT_NV21: case WL_SHM_FORMAT_NV16: case WL_SHM_FORMAT_NV61: case WL_SHM_FORMAT_YUV410: case WL_SHM_FORMAT_YVU410: case WL_SHM_FORMAT_YUV411: case WL_SHM_FORMAT_YVU411: case WL_SHM_FORMAT_YUV420: case WL_SHM_FORMAT_YVU420: case WL_SHM_FORMAT_YUV422: case WL_SHM_FORMAT_YVU422: case WL_SHM_FORMAT_YUV444: case WL_SHM_FORMAT_YVU444: case WL_SHM_FORMAT_R8: case WL_SHM_FORMAT_R16: case WL_SHM_FORMAT_RG88: case WL_SHM_FORMAT_GR88: case WL_SHM_FORMAT_RG1616: case WL_SHM_FORMAT_GR1616: case WL_SHM_FORMAT_XRGB16161616F: case WL_SHM_FORMAT_XBGR16161616F: case WL_SHM_FORMAT_ARGB16161616F: case WL_SHM_FORMAT_ABGR16161616F: case WL_SHM_FORMAT_XYUV8888: case WL_SHM_FORMAT_VUY888: case WL_SHM_FORMAT_VUY101010: case WL_SHM_FORMAT_Y210: case WL_SHM_FORMAT_Y212: case WL_SHM_FORMAT_Y216: case WL_SHM_FORMAT_Y410: case WL_SHM_FORMAT_Y412: case WL_SHM_FORMAT_Y416: case WL_SHM_FORMAT_XVYU2101010: case WL_SHM_FORMAT_XVYU12_16161616: case WL_SHM_FORMAT_XVYU16161616: case WL_SHM_FORMAT_Y0L0: case WL_SHM_FORMAT_X0L0: case WL_SHM_FORMAT_Y0L2: case WL_SHM_FORMAT_X0L2: case WL_SHM_FORMAT_YUV420_8BIT: case WL_SHM_FORMAT_YUV420_10BIT: case WL_SHM_FORMAT_XRGB8888_A8: case WL_SHM_FORMAT_XBGR8888_A8: case WL_SHM_FORMAT_RGBX8888_A8: case WL_SHM_FORMAT_BGRX8888_A8: case WL_SHM_FORMAT_RGB888_A8: case WL_SHM_FORMAT_BGR888_A8: case WL_SHM_FORMAT_RGB565_A8: case WL_SHM_FORMAT_BGR565_A8: case WL_SHM_FORMAT_NV24: case WL_SHM_FORMAT_NV42: case WL_SHM_FORMAT_P210: case WL_SHM_FORMAT_P010: case WL_SHM_FORMAT_P012: case WL_SHM_FORMAT_P016: case WL_SHM_FORMAT_AXBXGXRX106106106106: case WL_SHM_FORMAT_NV15: case WL_SHM_FORMAT_Q410: case WL_SHM_FORMAT_Q401: case WL_SHM_FORMAT_XRGB16161616: case WL_SHM_FORMAT_XBGR16161616: case WL_SHM_FORMAT_ARGB16161616: case WL_SHM_FORMAT_ABGR16161616: tDebug("WaylandPortalScreencopyFrame") << "Unsupported SHM format: " << fmt; break; } if (d->qimageFormat == QImage::Format_Invalid) { emit done(); return; } d->width = width; d->height = height; d->size = stride * height; QString filename = QStringLiteral("/tdportal-%1").arg(QUuid::createUuid().toString(QUuid::Id128)); auto fd = shm_open(filename.toUtf8().data(), O_RDWR | O_CREAT | O_EXCL, 0600); shm_unlink(filename.toUtf8().data()); ftruncate(fd, d->size); d->data = mmap(nullptr, d->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); auto pool = wl_shm_create_pool(d->shm, fd, d->size); d->buf = wl_shm_pool_create_buffer(pool, 0, width, height, stride, format); wl_shm_pool_destroy(pool); close(fd); copy(d->buf); wl_display_roundtrip(d->display); } void WaylandPortalScreencopyFrame::zwlr_screencopy_frame_v1_ready(uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { tDebug("WaylandPortalScreencopyFrame") << "Ready h: " << tv_sec_hi << " l: " << tv_sec_lo << " n: " << tv_nsec; QImage image(reinterpret_cast(d->data), d->width, d->height, d->qimageFormat); d->image = image.copy(); for (auto i = 0; i < image.height(); i++) { d->transform(reinterpret_cast(d->image.scanLine(i)), d->image.bytesPerLine() / 4); } d->ok = true; munmap(d->data, d->size); wl_buffer_destroy(d->buf); emit done(); } void WaylandPortalScreencopyFrame::zwlr_screencopy_frame_v1_failed() { tDebug("WaylandPortalScreencopyFrame") << "Screencopy failed"; munmap(d->data, d->size); wl_buffer_destroy(d->buf); emit done(); } ================================================ FILE: desktop-portal/backend/private/waylandportalscreencopyframe.h ================================================ #ifndef WAYLANDPORTALSCREENCOPYFRAME_H #define WAYLANDPORTALSCREENCOPYFRAME_H #include #include struct WaylandPortalScreencopyFramePrivate; class WaylandPortalScreencopyFrame : public QObject, public QtWayland::zwlr_screencopy_frame_v1 { Q_OBJECT public: explicit WaylandPortalScreencopyFrame(struct ::zwlr_screencopy_frame_v1* object, wl_shm* shm, wl_display* display); ~WaylandPortalScreencopyFrame(); bool ok(); QPixmap pixmap(); signals: void done(); private: WaylandPortalScreencopyFramePrivate* d; // zwlr_screencopy_frame_v1 interface protected: void zwlr_screencopy_frame_v1_buffer(uint32_t format, uint32_t width, uint32_t height, uint32_t stride); void zwlr_screencopy_frame_v1_ready(uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec); void zwlr_screencopy_frame_v1_failed(); }; #endif // WAYLANDPORTALSCREENCOPYFRAME_H ================================================ FILE: desktop-portal/backend/waylandportalbackend.cpp ================================================ #include "waylandportalbackend.h" #include "private/waylandportalscreencopyframe.h" #include #include #include #include #include #include struct WaylandPortalBackendPrivate { WaylandPortalBackend* parent; wl_display* display; wl_seat* seat; QList outputs; wl_shm* shm; }; WaylandPortalBackend::WaylandPortalBackend(QObject* parent) : AbstractPortalBackend{parent} { d = new WaylandPortalBackendPrivate(); d->parent = this; d->display = reinterpret_cast(qApp->platformNativeInterface()->nativeResourceForIntegration("display")); wl_registry_listener listener = { [](void* data, wl_registry* registry, quint32 name, const char* interface, quint32 version) { auto* backend = static_cast(data); if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) { backend->parent->QtWayland::zwlr_screencopy_manager_v1::init(registry, name, 1); } else if (strcmp(interface, wl_output_interface.name) == 0) { auto output = static_cast(wl_registry_bind(registry, name, &wl_output_interface, std::min(version, static_cast(1)))); backend->outputs.append(output); } else if (strcmp(interface, wl_seat_interface.name) == 0) { wl_seat* seat = static_cast(wl_registry_bind(registry, name, &wl_seat_interface, std::min(version, static_cast(1)))); backend->seat = seat; } else if (strcmp(interface, wl_shm_interface.name) == 0) { backend->shm = static_cast(wl_registry_bind(registry, name, &wl_shm_interface, std::min(version, static_cast(1)))); } }, [](void* data, wl_registry* registry, quint32 name) { Q_UNUSED(data) Q_UNUSED(registry) Q_UNUSED(name) }}; wl_registry* registry = wl_display_get_registry(d->display); wl_registry_add_listener(registry, &listener, d); wl_display_roundtrip(d->display); if (!this->QtWayland::zwlr_screencopy_manager_v1::isInitialized()) { tWarn("WaylandPortalBackend") << "The compositor doesn't support the wlr-screencopy-manager-v1 protocol"; } wl_registry_destroy(registry); } WaylandPortalBackend::~WaylandPortalBackend() { delete d; } QCoro::Task WaylandPortalBackend::takeScreenshot(QScreen* screen) { WaylandPortalScreencopyFrame capture(this->capture_output(false, d->outputs.first()), d->shm, d->display); co_await qCoro(&capture, &WaylandPortalScreencopyFrame::done); if (capture.ok()) { co_return capture.pixmap(); } else { QPixmap px(screen->size()); px.fill(Qt::red); co_return px; } } ================================================ FILE: desktop-portal/backend/waylandportalbackend.h ================================================ #ifndef WAYLANDPORTALBACKEND_H #define WAYLANDPORTALBACKEND_H #include "abstractportalbackend.h" #include #include struct WaylandPortalBackendPrivate; class WaylandPortalBackend : public AbstractPortalBackend, public QtWayland::zwlr_screencopy_manager_v1 { Q_OBJECT public: explicit WaylandPortalBackend(QObject* parent = nullptr); ~WaylandPortalBackend(); private: WaylandPortalBackendPrivate* d; // AbstractPortalBackend interface public: QCoro::Task takeScreenshot(QScreen* screen); }; #endif // WAYLANDPORTALBACKEND_H ================================================ FILE: desktop-portal/backend/wlr-screencopy-unstable-v1.xml ================================================ Copyright © 2018 Simon Ser Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This protocol allows clients to ask the compositor to copy part of the screen content to a client buffer. Warning! The protocol described in this file is experimental and backward incompatible changes may be made. Backward compatible changes may be added together with the corresponding interface version bump. Backward incompatible changes are done by bumping the version number in the protocol and interface names and resetting the interface version. Once the protocol is to be declared stable, the 'z' prefix and the version number in the protocol and interface names are removed and the interface version number is reset. This object is a manager which offers requests to start capturing from a source. Capture the next frame of an entire output. Capture the next frame of an output's region. The region is given in output logical coordinates, see xdg_output.logical_size. The region will be clipped to the output's extents. All objects created by the manager will still remain valid, until their appropriate destroy request has been called. This object represents a single frame. When created, a "buffer" event will be sent. The client will then be able to send a "copy" request. If the capture is successful, the compositor will send a "flags" followed by a "ready" event. If the capture failed, the "failed" event is sent. This can happen anytime before the "ready" event. Once either a "ready" or a "failed" event is received, the client should destroy the frame. Provides information about the frame's buffer. This event is sent once as soon as the frame is created. The client should then create a buffer with the provided attributes, and send a "copy" request. Copy the frame to the supplied buffer. The buffer must have a the correct size, see zwlr_screencopy_frame_v1.buffer. The buffer needs to have a supported format. If the frame is successfully copied, a "flags" and a "ready" events are sent. Otherwise, a "failed" event is sent. Provides flags about the frame. This event is sent once before the "ready" event. Called as soon as the frame is copied, indicating it is available for reading. This event includes the time at which presentation happened at. The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples, each component being an unsigned 32-bit value. Whole seconds are in tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo, and the additional fractional part in tv_nsec as nanoseconds. Hence, for valid timestamps tv_nsec must be in [0, 999999999]. The seconds part may have an arbitrary offset at start. After receiving this event, the client should destroy the object. This event indicates that the attempted frame copy has failed. After receiving this event, the client should destroy the object. Destroys the frame. This request can be sent at any time by the client. ================================================ FILE: desktop-portal/backend/x11portalbackend.cpp ================================================ #include "x11portalbackend.h" #include X11PortalBackend::X11PortalBackend(QObject* parent) : AbstractPortalBackend{parent} { } QCoro::Task X11PortalBackend::takeScreenshot(QScreen* screen) { co_return screen->grabWindow(0); } ================================================ FILE: desktop-portal/backend/x11portalbackend.h ================================================ #ifndef X11PORTALBACKEND_H #define X11PORTALBACKEND_H #include "abstractportalbackend.h" #include class X11PortalBackend : public AbstractPortalBackend { Q_OBJECT public: explicit X11PortalBackend(QObject* parent = nullptr); // AbstractPortalBackend interface public: QCoro::Task takeScreenshot(QScreen* screen); }; #endif // X11PORTALBACKEND_H ================================================ FILE: desktop-portal/desktop-portal.pro ================================================ QT += gui widgets thelib thefile SHARE_APP_NAME = thedesk/portal TARGET = thedesk-desktop-portal CONFIG += c++20 console CONFIG -= app_bundle # Include the-libs build tools include(/usr/share/the-libs/pri/buildmaster.pri) # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ dialogs/filedialog.cpp \ interfaces/filechooserinterface.cpp \ interfaces/settingsinterface.cpp \ main.cpp \ portalhandle.cpp DBUS_ADAPTOR_HEADERS = portalhandle.h qtPrepareTool(QDBUSCPP2XML, qdbuscpp2xml) cpp2xml.output = ${QMAKE_FILE_BASE}.xml cpp2xml.commands = $$QDBUSCPP2XML -a -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} cpp2xml.input = DBUS_ADAPTOR_HEADERS cpp2xml.CONFIG = no_link target_predeps cpp2xml.variable_out = DBUS_ADAPTORS QMAKE_EXTRA_COMPILERS += cpp2xml DBUS_ADAPTORS = portalhandle.xml unix { target.path = $$THELIBS_INSTALL_LIB portaldef.files = thedesk.portal portaldef.path = $$THELIBS_INSTALL_PREFIX/share/xdg-desktop-portal/portals dbusactivation.files = org.freedesktop.impl.portal.desktop.thedesk.service dbusactivation.path = $$THELIBS_INSTALL_PREFIX/share/dbus-1/services systemdservice.files = xdg-desktop-portal-thedesk.service systemdservice.path = $$THELIBS_INSTALL_PREFIX/lib/systemd/user/ INSTALLS += target portaldef dbusactivation systemdservice } DISTFILES += \ org.freedesktop.impl.portal.desktop.thedesk.service \ thedesk.portal \ xdg-desktop-portal-thedesk.service HEADERS += \ dialogs/filedialog.h \ interfaces/filechooserinterface.h \ interfaces/settingsinterface.h \ portalhandle.h FORMS += \ dialogs/filedialog.ui ================================================ FILE: desktop-portal/dialogs/accessdialog.cpp ================================================ #include "accessdialog.h" #include "ui_accessdialog.h" AccessDialog::AccessDialog(QWidget* parent) : QWidget(parent), ui(new Ui::AccessDialog) { ui->setupUi(this); ui->rejectButton->setProperty("type", "destructive"); } AccessDialog::~AccessDialog() { delete ui; } void AccessDialog::setTitle(QString title) { ui->titleLabel->setText(title); } void AccessDialog::setSubtitle(QString subtitle) { ui->subtitleLabel->setText(subtitle); } void AccessDialog::setBody(QString body) { ui->bodyLabel->setText(body); } void AccessDialog::setDenyButtonText(QString text) { ui->rejectButton->setText(text); } void AccessDialog::setAllowButtonText(QString text) { ui->acceptButton->setText(text); } void AccessDialog::on_titleLabel_backButtonClicked() { emit reject(); } void AccessDialog::on_acceptButton_clicked() { emit accept(); } void AccessDialog::on_rejectButton_clicked() { emit reject(); } ================================================ FILE: desktop-portal/dialogs/accessdialog.h ================================================ #ifndef ACCESSDIALOG_H #define ACCESSDIALOG_H #include namespace Ui { class AccessDialog; } class AccessDialog : public QWidget { Q_OBJECT public: explicit AccessDialog(QWidget* parent = nullptr); ~AccessDialog(); void setTitle(QString title); void setSubtitle(QString subtitle); void setBody(QString body); void setDenyButtonText(QString text); void setAllowButtonText(QString text); signals: void reject(); void accept(); private slots: void on_titleLabel_backButtonClicked(); void on_acceptButton_clicked(); void on_rejectButton_clicked(); private: Ui::AccessDialog* ui; }; #endif // ACCESSDIALOG_H ================================================ FILE: desktop-portal/dialogs/accessdialog.ui ================================================ AccessDialog 0 0 1440 747 Form 0 0 0 0 0 Qt::Vertical 20 307 Qt::Horizontal 627 20 20 TextLabel false TextLabel 0 PushButton PushButton Qt::Horizontal 627 20 Qt::Vertical 20 306 Permission Request tTitleLabel QLabel
ttitlelabel.h
backButtonClicked() backButtonClicked()
================================================ FILE: desktop-portal/dialogs/accountdialog.cpp ================================================ #include "accountdialog.h" #include "ui_accountdialog.h" #include #include #include #include AccountDialog::AccountDialog(QString appId, QString reason, QWidget* parent) : QDialog(parent), ui(new Ui::AccountDialog) { ui->setupUi(this); new tContentSizer(ui->appInfoWidget); new tContentSizer(ui->userInfoWidget); new tContentSizer(ui->okButton); Application app(appId); ui->appInfoDescriptionLabel->setText(tr("%1 is requesting information about your profile.").arg(QLocale().quoteString(app.getProperty("Name").toString()))); if (reason.isEmpty()) { ui->reasonLabel->setVisible(false); } else { ui->reasonLabel->setText(reason); } ui->usernameLabel->setText(DesktopWm::userUserName()); ui->realNameLabel->setText(DesktopWm::userDisplayName()); } AccountDialog::~AccountDialog() { delete ui; } QVariantMap AccountDialog::results() { QTemporaryFile tempFile; tempFile.setAutoRemove(false); tempFile.open(); QIcon::fromTheme("user").pixmap(QSize(512, 512)).save(&tempFile, "PNG"); tempFile.close(); return { {"id", DesktopWm::userUserName() }, {"name", DesktopWm::userDisplayName() }, {"image", QUrl::fromLocalFile(tempFile.fileName()).toString()} }; } void AccountDialog::on_okButton_clicked() { this->accept(); } void AccountDialog::on_titleLabel_backButtonClicked() { this->reject(); } ================================================ FILE: desktop-portal/dialogs/accountdialog.h ================================================ #ifndef ACCOUNTDIALOG_H #define ACCOUNTDIALOG_H #include namespace Ui { class AccountDialog; } class AccountDialog : public QDialog { Q_OBJECT public: explicit AccountDialog(QString appId, QString reason, QWidget* parent = nullptr); ~AccountDialog(); QVariantMap results(); private slots: void on_okButton_clicked(); void on_titleLabel_backButtonClicked(); private: Ui::AccountDialog* ui; }; #endif // ACCOUNTDIALOG_H ================================================ FILE: desktop-portal/dialogs/accountdialog.ui ================================================ AccountDialog 0 0 655 236 Request for Account Information 0 0 0 0 0 Request for Account Information TextLabel true false TextLabel true Real Name Username 0 0 TextLabel TextLabel Information to be shared Share Account Information .. Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked() backButtonClicked()
tSubtitleLabel QLabel
tsubtitlelabel.h
================================================ FILE: desktop-portal/dialogs/filedialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "filedialog.h" #include "ui_filedialog.h" #include #include #include #include struct FileDialogPrivate { QStringList urls; }; struct Filter { uint type; QString pattern; }; Q_DECLARE_METATYPE(Filter) QDBusArgument& operator<<(QDBusArgument& argument, const Filter& filter) { argument.beginStructure(); argument << filter.type << filter.pattern; argument.endStructure(); return argument; } const QDBusArgument& operator>>(const QDBusArgument& argument, Filter& filter) { argument.beginStructure(); argument >> filter.type >> filter.pattern; argument.endStructure(); return argument; } struct FilterCategory { QString name; QList filters; }; Q_DECLARE_METATYPE(FilterCategory) QDBusArgument& operator<<(QDBusArgument& argument, const FilterCategory& filter) { argument.beginStructure(); argument << filter.name << filter.filters; argument.endStructure(); return argument; } const QDBusArgument& operator>>(const QDBusArgument& argument, FilterCategory& filter) { argument.beginStructure(); argument >> filter.name >> filter.filters; argument.endStructure(); return argument; } FileDialog::FileDialog(bool isSave, QVariantMap options, QWidget* parent) : QDialog(parent), ui(new Ui::FileDialog) { ui->setupUi(this); d = new FileDialogPrivate(); ui->titleLabel->setBackButtonShown(true); bool setOpenButton = true; QList columnActions; if (isSave) { columnActions.append({ tr("Save Here"), tr("Create New File Here"), [ = ](DirectoryPtr directory) { QUrl directoryUrl = directory->url(); if (!directoryUrl.path().endsWith("/")) directoryUrl.setPath(directoryUrl.path() + "/"); bool saved = false; QString filename; while (!saved) { bool ok; filename = tInputDialog::getText(this, tr("Name this file"), tr("What do you want to name the file?"), QLineEdit::Normal, filename, &ok); if (!ok) return; saved = acceptSave(directoryUrl.resolved(filename)); } } }); } else { if (options.value("directory", false).toBool()) { columnActions.append({ tr("Open Folder"), tr("Choose This Folder"), [ = ](DirectoryPtr directory) { d->urls.append(directory->url().toString()); this->accept(); } }); setOpenButton = false; } } ui->filePicker->setColumnActions(columnActions); if (setOpenButton) { QString openButtonText = options.value("accept_label", isSave ? tr("Overwrite") : tr("Open")).toString(); QIcon openButtonIcon = QIcon::fromTheme(isSave ? "document-save" : "document-open"); ui->filePicker->setOpenFileButtons({ { openButtonText, openButtonIcon, [ = ](QList selected) { if (isSave) { acceptSave(selected.first()); } else { for (QUrl url : selected) { d->urls.append(url.toString()); } this->accept(); } }, true } }); } //Set up filters qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType>(); qDBusRegisterMetaType>(); QDBusArgument filtersArgument = options.value("filters").value(); QList filters; filtersArgument >> filters; QList pickerFilters; for (FilterCategory filterCatg : filters) { for (Filter filter : filterCatg.filters) { pickerFilters.append(FileTab::Filter{filter.type == 1, filter.pattern}); } } ui->filePicker->setFilters(pickerFilters); this->resize(SC_DPI_T(this->size(), QSize)); } FileDialog::~FileDialog() { delete d; delete ui; } QStringList FileDialog::uris() { return d->urls; } QVariant FileDialog::choices() { return QVariant(); } bool FileDialog::isWritable() { return true; } void FileDialog::setWindowTitle(QString windowTitle) { QDialog::setWindowTitle(windowTitle); ui->titleLabel->setText(windowTitle); } void FileDialog::on_titleLabel_backButtonClicked() { this->reject(); } bool FileDialog::acceptSave(QUrl url) { if (ResourceManager::parentDirectoryForUrl(url)->isFile(url.fileName())) { QMessageBox box(this); box.setWindowTitle(tr("Overwrite?")); box.setText(tr("A file named %1 already exists. Do you want to overwrite it?").arg(QLocale().quoteString(url.fileName()))); box.setInformativeText(tr("Overwriting the file will replace its contents.")); box.setIcon(QMessageBox::Warning); box.setStandardButtons(QMessageBox::Yes | QMessageBox::No); if (box.exec() == QMessageBox::No) return false; } d->urls.append(url.toString()); this->accept(); return true; } ================================================ FILE: desktop-portal/dialogs/filedialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef FILEDIALOG_H #define FILEDIALOG_H #include #include namespace Ui { class FileDialog; } struct FileDialogPrivate; class FileDialog : public QDialog { Q_OBJECT public: explicit FileDialog(bool isSave, QVariantMap options, QWidget* parent = nullptr); ~FileDialog(); QStringList uris(); QVariant choices(); bool isWritable(); void setWindowTitle(QString windowTitle); private slots: void on_titleLabel_backButtonClicked(); private: Ui::FileDialog* ui; FileDialogPrivate* d; bool acceptSave(QUrl url); }; #endif // FILEDIALOG_H ================================================ FILE: desktop-portal/dialogs/filedialog.ui ================================================ FileDialog 0 0 945 661 Dialog 0 0 0 0 0 Dialog Title 0 0 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
FileTab QWidget
filetab.h
1
================================================ FILE: desktop-portal/dialogs/penbutton.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "penbutton.h" #include #include #include #include struct PenButtonPrivate { PenButton::PenType penType; QColor color; tVariantAnimation* heightAnim; QSvgRenderer* renderer; }; PenButton::PenButton(PenType penType, QColor color, QWidget* parent) : QPushButton(parent) { d = new PenButtonPrivate(); d->color = color; d->penType = penType; QString data; if (penType == Pen) { this->setFixedSize(SC_DPI_T(QSize(40, 60), QSize)); QFile penFile(":/screenshot/icons/pen.svg"); penFile.open(QFile::ReadOnly); data = penFile.readAll(); data = data.arg(color.name(QColor::HexRgb)); } else { this->setFixedSize(SC_DPI_T(QSize(60, 60), QSize)); QFile penFile(":/screenshot/icons/eraser.svg"); penFile.open(QFile::ReadOnly); data = penFile.readAll(); data = data.arg(tr("Erase-o", "This and the next translation span two lines. Be spiffy with these!")) .arg(tr("matic 2000", "This and the previous translation span two lines. Be spiffy with these!")) .arg(this->font().family()); } d->heightAnim = new tVariantAnimation(this); d->heightAnim->setStartValue(0); d->heightAnim->setEndValue(0); d->heightAnim->setEasingCurve(QEasingCurve::OutCubic); d->heightAnim->setDuration(250); connect(d->heightAnim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { this->setFixedHeight(value.toInt()); }); d->renderer = new QSvgRenderer(); d->renderer->load(data.toUtf8()); this->setCheckable(true); this->setAutoExclusive(true); } PenButton::~PenButton() { d->renderer->deleteLater(); delete d; } QColor PenButton::color() const { return d->color; } void PenButton::paintEvent(QPaintEvent* event) { QPainter painter(this); d->renderer->render(&painter, QRectF(0, 0, this->width(), SC_DPI(100))); } void PenButton::updateChecked() { d->heightAnim->setStartValue(this->height()); if (this->isChecked()) { d->heightAnim->setEndValue(SC_DPI(100)); } else { d->heightAnim->setEndValue(SC_DPI(60)); } d->heightAnim->start(); } void PenButton::checkStateSet() { updateChecked(); } void PenButton::nextCheckState() { this->setChecked(!this->isChecked()); updateChecked(); } ================================================ FILE: desktop-portal/dialogs/penbutton.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PENBUTTON_H #define PENBUTTON_H #include struct PenButtonPrivate; class PenButton : public QPushButton { Q_OBJECT public: enum PenType { Pen, Eraser }; explicit PenButton(PenType penType, QColor color, QWidget* parent = nullptr); ~PenButton(); QColor color() const; signals: private: void paintEvent(QPaintEvent* event); PenButtonPrivate* d; void updateChecked(); // QAbstractButton interface protected: void checkStateSet(); void nextCheckState(); }; #endif // PENBUTTON_H ================================================ FILE: desktop-portal/dialogs/screenshotwindow.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "screenshotwindow.h" #include "ui_screenshotwindow.h" #include "backend/abstractportalbackend.h" #include "penbutton.h" #include #include #include #include #include #include #include struct ScreenshotWindowPrivate { enum Operation { Crop, Redact, Pen }; Operation currentOperation = Crop; QColor currentColor; QPainter::CompositionMode compMode = QPainter::CompositionMode_SourceOver; qreal penWidth; QScreen* screen; QPixmap originalShot; tVariantAnimation* darkenAnim; tVariantAnimation* viewportAnim; QRect cropRect; QPoint topLeftDrag; QRect editingRect; QPixmap overlay; ScreenshotWindow::Type type = ScreenshotWindow::Type::ApplicationScreenshot; }; ScreenshotWindow::ScreenshotWindow(QScreen* screen, QWidget* parent) : QWidget(parent), ui(new Ui::ScreenshotWindow) { ui->setupUi(this); this->setWindowFlag(Qt::FramelessWindowHint); this->setWindowFlag(Qt::WindowStaysOnTopHint); this->setAttribute(Qt::WA_TranslucentBackground); d = new ScreenshotWindowPrivate(); d->screen = screen; d->darkenAnim = new tVariantAnimation(this); d->darkenAnim->setStartValue(0.0); d->darkenAnim->setEndValue(0.5); d->darkenAnim->setEasingCurve(QEasingCurve::OutCubic); d->darkenAnim->setDuration(250); connect(d->darkenAnim, &tVariantAnimation::valueChanged, this, [=] { this->update(); }); connect(d->darkenAnim, &tVariantAnimation::finished, this, [=] { this->update(); }); d->darkenAnim->start(); d->viewportAnim = new tVariantAnimation(this); d->viewportAnim->setStartValue(QRect(0, 0, screen->geometry().width(), screen->geometry().height())); d->viewportAnim->setEndValue(QRect(0, 0, screen->geometry().width(), screen->geometry().height())); d->viewportAnim->setEasingCurve(QEasingCurve::OutCubic); d->viewportAnim->setDuration(250); connect(d->viewportAnim, &tVariantAnimation::valueChanged, this, [=] { this->update(); }); connect(d->viewportAnim, &tVariantAnimation::finished, this, [=] { this->update(); }); this->setGeometry(screen->geometry()); d->overlay = QPixmap(screen->geometry().size()); d->overlay.fill(Qt::transparent); for (QColor col : { QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255), QColor(255, 255, 0), QColor(0, 255, 255), QColor(255, 0, 255)}) { PenButton* b = new PenButton(PenButton::Pen, col, this); connect(b, &PenButton::toggled, this, [=](bool checked) { if (checked) { d->currentOperation = ScreenshotWindowPrivate::Pen; d->currentColor = b->color(); d->compMode = QPainter::CompositionMode_SourceOver; d->penWidth = SC_DPI(3); this->update(); } }); ui->pensLayout->addWidget(b, 0, Qt::AlignBottom); } PenButton* eraser = new PenButton(PenButton::Eraser, QColor(0, 0, 0, 0), this); connect(eraser, &PenButton::toggled, this, [=](bool checked) { if (checked) { d->currentOperation = ScreenshotWindowPrivate::Pen; d->currentColor = eraser->color(); d->compMode = QPainter::CompositionMode_Source; d->penWidth = SC_DPI(10); this->update(); } }); ui->pensLayout->addWidget(eraser, 0, Qt::AlignBottom); QShortcut* discardShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this); connect(discardShortcut, &QShortcut::activated, this, [=] { ui->discardButton->click(); }); this->setType(Type::ApplicationScreenshot); ui->discardButton->setProperty("type", "destructive"); } void ScreenshotWindow::paintEvent(QPaintEvent* event) { bool editing = d->editingRect.isValid(); QRect cropRect; if (ui->cropButton->isChecked() && editing) { cropRect = d->editingRect; } else { cropRect = d->cropRect; } QPainter painter(this); painter.setViewport(d->viewportAnim->currentValue().toRect()); painter.drawPixmap(0, 0, this->width(), this->height(), d->originalShot); if (d->type != Type::ColourPicker) { if (cropRect.isValid() || d->currentOperation == ScreenshotWindowPrivate::Crop) { painter.setOpacity(d->darkenAnim->currentValue().toDouble()); painter.setPen(Qt::transparent); painter.setBrush(Qt::black); painter.drawRect(0, 0, this->width(), this->height()); painter.setOpacity(1); if (cropRect.isValid()) { painter.drawPixmap(cropRect, d->originalShot, cropRect); } } painter.drawPixmap(0, 0, this->width(), this->height(), d->overlay); if (d->currentOperation == ScreenshotWindowPrivate::Redact && editing) { painter.setPen(Qt::transparent); painter.setBrush(Qt::black); painter.drawRect(d->editingRect); } if (cropRect.isValid()) { painter.setPen(Qt::white); painter.setBrush(Qt::transparent); painter.drawRect(cropRect.adjusted(-1, -1, 0, 0)); } } } ScreenshotWindow::~ScreenshotWindow() { delete d; delete ui; } QCoro::Task<> ScreenshotWindow::prepareWindow() { d->originalShot = co_await AbstractPortalBackend::instance()->takeScreenshot(d->screen); } void ScreenshotWindow::take(QScreen* screen, int delay) { ScreenshotWindow* w = new ScreenshotWindow(screen); w->showFullScreen(); } void ScreenshotWindow::animateDiscard() { d->viewportAnim->setEndValue(QRect(0, this->height(), this->width(), this->height())); d->viewportAnim->setEasingCurve(QEasingCurve::InCubic); d->viewportAnim->start(); tVariantAnimation* paneAnim = new tVariantAnimation(this); paneAnim->setStartValue(ui->bottomPane->height()); paneAnim->setEndValue(0); paneAnim->setDuration(250); paneAnim->setEasingCurve(QEasingCurve::OutCubic); connect(paneAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { ui->bottomPane->setFixedHeight(value.toInt()); }); paneAnim->start(); connect(d->viewportAnim, &tVariantAnimation::finished, this, &ScreenshotWindow::animationComplete); } void ScreenshotWindow::animateTake() { d->viewportAnim->setEndValue(QRect(0, -this->height(), this->width(), this->height())); d->viewportAnim->setEasingCurve(QEasingCurve::InCubic); d->viewportAnim->start(); tVariantAnimation* paneAnim = new tVariantAnimation(this); paneAnim->setStartValue(ui->bottomPane->height()); paneAnim->setEndValue(0); paneAnim->setDuration(250); paneAnim->setEasingCurve(QEasingCurve::OutCubic); connect(paneAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { ui->bottomPane->setFixedHeight(value.toInt()); }); paneAnim->start(); connect(d->viewportAnim, &tVariantAnimation::finished, this, &ScreenshotWindow::animationComplete); } void ScreenshotWindow::setType(Type type) { d->type = type; switch (type) { case Type::ApplicationScreenshot: { ui->discardButton->setText(tr("Cancel")); ui->copyButton->setText(tr("Share Screenshot")); ui->copyButton->setIcon(QIcon::fromTheme("dialog-ok")); ui->topPane->setVisible(false); ui->bottomPane->setVisible(true); this->setMouseTracking(false); this->setCursor(QCursor(Qt::CrossCursor)); break; } case Type::TheDeskScreenshot: { ui->discardButton->setText(tr("Discard")); ui->copyButton->setText(tr("Copy")); ui->copyButton->setIcon(QIcon::fromTheme("edit-copy")); ui->topPane->setVisible(false); ui->bottomPane->setVisible(true); this->setMouseTracking(false); this->setCursor(QCursor(Qt::CrossCursor)); break; } case Type::ColourPicker: { ui->topPane->setVisible(false); ui->bottomPane->setVisible(false); this->setMouseTracking(true); break; } } } void ScreenshotWindow::on_discardButton_clicked() { emit cancelled(); } void ScreenshotWindow::mousePressEvent(QMouseEvent* event) { if (d->type == Type::ColourPicker) { emit colourClicked(d->originalShot.toImage().pixelColor(event->position().toPoint())); } else { d->topLeftDrag = event->pos(); } } void ScreenshotWindow::mouseReleaseEvent(QMouseEvent* event) { if (d->type == Type::ColourPicker) { } else { if (d->currentOperation == ScreenshotWindowPrivate::Crop) { d->cropRect = d->editingRect; this->update(); } else if (d->currentOperation == ScreenshotWindowPrivate::Redact) { QPainter painter(&d->overlay); painter.setPen(Qt::transparent); painter.setBrush(Qt::black); painter.drawRect(d->editingRect); } d->editingRect = QRect(); this->update(); } } void ScreenshotWindow::mouseMoveEvent(QMouseEvent* event) { if (d->type == Type::ColourPicker) { auto col = d->originalShot.toImage().pixelColor(event->position().toPoint()); QSize cursorSize(32, 32); QRect circle(QPoint(0, 0), cursorSize); QRect innerCircle = circle.adjusted(3, 3, -3, -3); QPolygon pointer; pointer.append(circle.topLeft()); pointer.append(QPoint(circle.width() / 2, 0)); pointer.append(QPoint(0, circle.height() / 2)); QPixmap cursorPic(cursorSize); cursorPic.fill(Qt::transparent); QPainter painter(&cursorPic); painter.setPen(Qt::transparent); painter.setBrush(Qt::black); painter.drawEllipse(circle); painter.drawPolygon(pointer); painter.setBrush(col); painter.drawEllipse(innerCircle); painter.end(); QCursor cursor(cursorPic, 0, 0); this->setCursor(cursor); } else { if (d->currentOperation == ScreenshotWindowPrivate::Pen) { QPainter painter(&d->overlay); painter.setCompositionMode(d->compMode); painter.setPen(QPen(d->currentColor, d->penWidth)); painter.drawLine(d->topLeftDrag, event->pos()); d->topLeftDrag = event->pos(); } else { d->editingRect = QRect(d->topLeftDrag, event->pos()); d->editingRect = d->editingRect.normalized(); } this->update(); } } QPixmap ScreenshotWindow::finalResult() { QPixmap result = d->originalShot; // Draw in any edits QPainter painter(&result); painter.drawPixmap(0, 0, this->width(), this->height(), d->overlay); painter.end(); // Crop the image if (d->cropRect.isValid()) { result = result.copy(d->cropRect); } return result; } void ScreenshotWindow::on_copyButton_clicked() { auto result = finalResult(); if (d->type == Type::TheDeskScreenshot) { // Also copy to the clipboard QApplication::clipboard()->setPixmap(finalResult()); } emit screenshotAvailable(result); } void ScreenshotWindow::on_cropButton_toggled(bool checked) { if (checked) { d->currentOperation = ScreenshotWindowPrivate::Crop; this->update(); } } void ScreenshotWindow::on_redactButton_toggled(bool checked) { if (checked) { d->currentOperation = ScreenshotWindowPrivate::Redact; this->update(); } } void ScreenshotWindow::on_resetButton_clicked() { d->overlay.fill(Qt::transparent); this->update(); } ================================================ FILE: desktop-portal/dialogs/screenshotwindow.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SCREENSHOTWINDOW_H #define SCREENSHOTWINDOW_H #include #include namespace Ui { class ScreenshotWindow; } struct ScreenshotWindowPrivate; class ScreenshotWindow : public QWidget { Q_OBJECT public: explicit ScreenshotWindow(QScreen* screen, QWidget* parent = nullptr); ~ScreenshotWindow(); QCoro::Task<> prepareWindow(); enum class Type { ApplicationScreenshot, TheDeskScreenshot, ColourPicker }; static void take(QScreen* screen, int delay = 0); void animateDiscard(); void animateTake(); void setType(Type type); private slots: void on_discardButton_clicked(); void on_copyButton_clicked(); void on_cropButton_toggled(bool checked); void on_redactButton_toggled(bool checked); void on_resetButton_clicked(); signals: void screenshotAvailable(QPixmap result); void colourClicked(QColor color); void cancelled(); void animationComplete(); private: void paintEvent(QPaintEvent* event); void mousePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); QPixmap finalResult(); Ui::ScreenshotWindow* ui; ScreenshotWindowPrivate* d; }; #endif // SCREENSHOTWINDOW_H ================================================ FILE: desktop-portal/dialogs/screenshotwindow.ui ================================================ ScreenshotWindow 0 0 891 512 Form 0 0 0 0 9 9 9 9 true SCREENSHOT Qt::Vertical 20 207 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 Crop .. true true true Redact .. true true Qt::Horizontal 40 20 0 9 9 9 9 Reset Markup .. Cancel .. Share Screenshot .. ================================================ FILE: desktop-portal/interfaces/accessinterface.cpp ================================================ #include "accessinterface.h" #include "dialogs/accessdialog.h" #include #include #include AccessInterface::AccessInterface(QObject* parent) : QDBusAbstractAdaptor{parent} { } uint AccessInterface::AccessDialog(QDBusObjectPath handle, QString appId, QString parentWindow, QString title, QString subtitle, QString body, QVariantMap options, const QDBusMessage& message, QVariantMap& results) { auto dialog = new class AccessDialog(); dialog->setTitle(title); dialog->setSubtitle(subtitle); dialog->setBody(body); dialog->setDenyButtonText(options.value("deny_label", tr("Deny")).toString()); dialog->setAllowButtonText(options.value("grant_label", tr("Allow")).toString()); auto replyTemplate = message.createReply(); auto* popover = new SystemPopover(dialog); popover->setPopoverWidth(600); popover->setPopoverSide(tPopover::Bottom); connect(dialog, &AccessDialog::accept, this, [popover, replyTemplate] { auto reply = QDBusMessage(replyTemplate); reply.setArguments({uint(0), QVariantMap()}); QDBusConnection::sessionBus().send(replyTemplate); popover->dismiss(); }); connect(dialog, &AccessDialog::reject, this, [popover, replyTemplate] { auto reply = QDBusMessage(replyTemplate); reply.setArguments({uint(1), QVariantMap()}); QDBusConnection::sessionBus().send(replyTemplate); popover->dismiss(); }); connect(popover, &tPopover::dismissed, this, [popover] { popover->deleteLater(); }); popover->show(); message.setDelayedReply(true); return 1; } ================================================ FILE: desktop-portal/interfaces/accessinterface.h ================================================ #ifndef ACCESSINTERFACE_H #define ACCESSINTERFACE_H #include #include class QDBusMessage; class AccessInterface : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Access") public: explicit AccessInterface(QObject* parent = nullptr); public slots: Q_SCRIPTABLE uint AccessDialog(QDBusObjectPath handle, QString appId, QString parentWindow, QString title, QString subtitle, QString body, QVariantMap options, const QDBusMessage& message, QVariantMap& results); signals: }; #endif // ACCESSINTERFACE_H ================================================ FILE: desktop-portal/interfaces/accountinterface.cpp ================================================ #include "accountinterface.h" #include "dialogs/accountdialog.h" #include "portalcommon.h" #include #include #include #include AccountInterface::AccountInterface(QObject* parent) : QDBusAbstractAdaptor{parent} { } uint AccountInterface::version() { return 1; } uint AccountInterface::GetUserInformation(QDBusObjectPath handle, QString appId, QString window, QVariantMap options, const QDBusMessage& message, QVariantMap& results) { PortalCommon::setupCoro([message, options, appId, window](QDBusMessage reply) -> QCoro::Task<> { QString reason; if (options.contains("reason")) reason = options.value("reason").toString(); auto dialog = new AccountDialog(appId, reason); PortalCommon::reparentWindow(dialog, window); dialog->show(); auto result = co_await qCoro(dialog, &AccountDialog::finished); if (result == AccountDialog::Rejected) { reply.setArguments({uint(1), QVariantMap()}); QDBusConnection::sessionBus().send(reply); } else { reply.setArguments({uint(0), dialog->results()}); QDBusConnection::sessionBus().send(reply); } }, message); return 0; } ================================================ FILE: desktop-portal/interfaces/accountinterface.h ================================================ #ifndef ACCOUNTINTERFACE_H #define ACCOUNTINTERFACE_H #include #include class QDBusMessage; class AccountInterface : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Account") Q_PROPERTY(uint version READ version) public: explicit AccountInterface(QObject* parent = nullptr); uint version(); public slots: Q_SCRIPTABLE uint GetUserInformation(QDBusObjectPath handle, QString appId, QString window, QVariantMap options, const QDBusMessage& message, QVariantMap& results); }; #endif // ACCOUNTINTERFACE_H ================================================ FILE: desktop-portal/interfaces/filechooserinterface.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "filechooserinterface.h" #include "dialogs/filedialog.h" #include "portalcommon.h" #include "portalhandle.h" #include #include #include #include #include FileChooserInterface::FileChooserInterface(QObject* parent) : QDBusAbstractAdaptor(parent) { } uint FileChooserInterface::OpenFile(const QDBusObjectPath& handle, const QString& app_id, const QString& parent_window, const QString& title, const QVariantMap& options, const QDBusMessage& message, QVariantMap& results) { tDebug("FileChooserInterface") << "Open File"; PortalCommon::setupCoro([options, parent_window, handle, title, this](QDBusMessage reply) -> QCoro::Task<> { auto* portalHandle = new PortalHandle(handle); FileDialog dialog(false, options); PortalCommon::reparentWindow(&dialog, parent_window); if (title.isEmpty()) { dialog.setWindowTitle(tr("Open")); } else { dialog.setWindowTitle(title); } connect(portalHandle, &PortalHandle::closed, &dialog, [&dialog] { dialog.close(); }); dialog.open(); auto result = co_await qCoro(&dialog, &FileDialog::finished); if (result == FileDialog::Accepted) { reply.setArguments({ uint(0), QVariantMap{ {"uris", dialog.uris()}, {"writable", dialog.isWritable()}} }); QDBusConnection::sessionBus().send(reply); } else { reply.setArguments({uint(1), QVariantMap()}); QDBusConnection::sessionBus().send(reply); } portalHandle->deleteLater(); }, message); return 0; } uint FileChooserInterface::SaveFile(const QDBusObjectPath& handle, const QString& app_id, const QString& parent_window, const QString& title, const QVariantMap& options, const QDBusMessage& message, QVariantMap& results) { PortalCommon::setupCoro([options, parent_window, handle, title, this](QDBusMessage reply) -> QCoro::Task<> { auto* portalHandle = new PortalHandle(handle); FileDialog dialog(true, options); PortalCommon::reparentWindow(&dialog, parent_window); if (title.isEmpty()) { dialog.setWindowTitle(tr("Save")); } else { dialog.setWindowTitle(title); } connect(portalHandle, &PortalHandle::closed, &dialog, [&dialog] { dialog.close(); }); dialog.open(); auto result = co_await qCoro(&dialog, &FileDialog::finished); if (result == FileDialog::Accepted) { reply.setArguments({ uint(0), QVariantMap{ {"uris", dialog.uris()}, {"writable", dialog.isWritable()}} }); QDBusConnection::sessionBus().send(reply); } else { reply.setArguments({uint(1), QVariantMap()}); QDBusConnection::sessionBus().send(reply); } portalHandle->deleteLater(); }, message); return 0; } uint FileChooserInterface::SaveFiles(const QDBusObjectPath& handle, const QString& app_id, const QString& parent_window, const QString& title, const QVariantMap& options, const QDBusMessage& message, QVariantMap& results) { return 0; } ================================================ FILE: desktop-portal/interfaces/filechooserinterface.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef FILECHOOSERINTERFACE_H #define FILECHOOSERINTERFACE_H #include #include #include #include class FileChooserInterface : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.FileChooser") public: explicit FileChooserInterface(QObject* parent = nullptr); public slots: Q_SCRIPTABLE uint OpenFile(const QDBusObjectPath& handle, const QString& app_id, const QString& parent_window, const QString& title, const QVariantMap& options, const QDBusMessage& message, QVariantMap& results); Q_SCRIPTABLE uint SaveFile(const QDBusObjectPath& handle, const QString& app_id, const QString& parent_window, const QString& title, const QVariantMap& options, const QDBusMessage& message, QVariantMap& results); Q_SCRIPTABLE uint SaveFiles(const QDBusObjectPath& handle, const QString& app_id, const QString& parent_window, const QString& title, const QVariantMap& options, const QDBusMessage& message, QVariantMap& results); signals: }; #endif // FILECHOOSERINTERFACE_H ================================================ FILE: desktop-portal/interfaces/notificationinterface.cpp ================================================ #include "notificationinterface.h" #include #include typedef QPair NotificationIdentifier; struct NotificationInterfacePrivate { QMap, tNotification*> notifications; }; NotificationInterface::NotificationInterface(QObject* parent) : QDBusAbstractAdaptor{parent} { d = new NotificationInterfacePrivate(); } NotificationInterface::~NotificationInterface() { delete d; } void NotificationInterface::AddNotification(QString app_id, QString id, QVariantMap notification) { auto title = notification.value("title").toString(); auto body = notification.value("body").toString(); auto priority = notification.value("priority").toString(); auto defaultAction = notification.value("default-action").toString(); auto defaultActionTarget = notification.value("default-action-target"); auto buttons = qdbus_cast>(notification.value("buttons").value()); Application app(app_id); NotificationIdentifier nid{app_id, id}; tNotification* n; if (d->notifications.contains(nid)) { n = d->notifications.value(nid); } else { n = new tNotification(); connect(n, &tNotification::actionClicked, this, [app_id, id, this, buttons, defaultActionTarget, defaultAction](QString key) { if (key == defaultAction) { emit ActionInvoked(app_id, id, key, {defaultActionTarget}); } for (const auto &button : buttons) { auto action = button.value("action").toString(); if (action == key) { auto target = button.value("target"); emit ActionInvoked(app_id, id, key, {target}); } } }); } n->insertHint("desktop-entry", app_id); n->setAppName(app.getProperty("Name").toString()); n->setAppIcon(app.getProperty("Icon").toString()); n->setSummary(title); n->setText(body); if (priority == "low") n->setUrgency(tNotification::Low); if (priority == "normal") n->setUrgency(tNotification::Normal); if (priority == "high") n->setUrgency(tNotification::Critical); if (priority == "urgent") n->setUrgency(tNotification::Critical); n->insertAction(defaultAction, tr("Activate")); for (const auto &button : buttons) { n->insertAction(button.value("action").toString(), button.value("label").toString()); } n->post(false); d->notifications.insert(nid, n); } void NotificationInterface::RemoveNotification(QString app_id, QString id) { NotificationIdentifier nid{app_id, id}; if (d->notifications.contains(nid)) { auto notification = d->notifications.take(nid); notification->dismiss(); notification->deleteLater(); } } ================================================ FILE: desktop-portal/interfaces/notificationinterface.h ================================================ #ifndef NOTIFICATIONINTERFACE_H #define NOTIFICATIONINTERFACE_H #include struct NotificationInterfacePrivate; class NotificationInterface : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Notification") public: explicit NotificationInterface(QObject* parent = nullptr); ~NotificationInterface(); public slots: Q_SCRIPTABLE void AddNotification(QString app_id, QString id, QVariantMap notification); Q_SCRIPTABLE void RemoveNotification(QString app_id, QString id); signals: Q_SCRIPTABLE void ActionInvoked(QString app_id, QString id, QString action, QVariantList parameter); private: NotificationInterfacePrivate* d; }; #endif // NOTIFICATIONINTERFACE_H ================================================ FILE: desktop-portal/interfaces/screenshotinterface.cpp ================================================ #include "screenshotinterface.h" #include "backend/abstractportalbackend.h" #include "portalcommon.h" #include "screenshotmanager.h" #include #include #include #include #include #include #include #include QDBusArgument& operator<<(QDBusArgument& argument, const ScreenshotColorReply& myStruct) { argument.beginStructure(); argument << myStruct.red << myStruct.green << myStruct.blue; argument.endStructure(); return argument; } const QDBusArgument& operator>>(const QDBusArgument& argument, ScreenshotColorReply& myStruct) { argument.beginStructure(); argument >> myStruct.red >> myStruct.green >> myStruct.blue; argument.endStructure(); return argument; } ScreenshotInterface::ScreenshotInterface(QObject* parent) : QDBusAbstractAdaptor{parent} { qDBusRegisterMetaType(); } uint ScreenshotInterface::version() { return 2; } uint ScreenshotInterface::Screenshot(QDBusObjectPath handle, QString app_id, QString parent_window, QVariantMap options, const QDBusMessage& message, QVariantMap& results) { PortalCommon::setupCoro([options, parent_window, handle, this, app_id](QDBusMessage reply) -> QCoro::Task<> { auto interactive = options.value("interactive", false).toBool(); auto permissionStoreChecked = options.value("permission_store_checked", false).toBool(); auto isTheDesk = app_id == "com.vicr123.thedesk" && options.value("x-thedesk-screenshot", false).toBool(); QPixmap finalPixmap; if (interactive) { ScreenshotManager mgr; if (isTheDesk) { mgr.setType(ScreenshotWindow::Type::TheDeskScreenshot); } co_await mgr.prepareScreenshotWindows(); mgr.showScreenshotWindows(); co_await qCoro(&mgr, &ScreenshotManager::finished); if (!mgr.accepted()) { reply.setArguments({uint(1), QVariantMap()}); QDBusConnection::sessionBus().send(reply); co_return; } finalPixmap = mgr.finalPixmap(); } else { if (!permissionStoreChecked) { // We haven't checked permissions of the app, so deny the request reply.setArguments({uint(2), QVariantMap()}); QDBusConnection::sessionBus().send(reply); co_return; } // Compile a picture QRect rect; for (auto screen : qApp->screens()) { rect = rect.united(screen->geometry()); } QPixmap pixmap(rect.size()); pixmap.fill(Qt::black); QPainter painter(&pixmap); for (auto screen : qApp->screens()) { painter.drawPixmap(screen->geometry(), co_await AbstractPortalBackend::instance()->takeScreenshot(screen)); } finalPixmap = pixmap; } QTemporaryFile temp; temp.setAutoRemove(false); temp.open(); finalPixmap.save(&temp, "PNG"); temp.close(); reply.setArguments({ uint(0), QVariantMap({{"uri", QUrl::fromLocalFile(temp.fileName()).toString()}} ) }); QDBusConnection::sessionBus().send(reply); }, message); return 0; } uint ScreenshotInterface::PickColor(QDBusObjectPath handle, QString app_id, QString parent_window, QVariantMap options, const QDBusMessage& message, QVariantMap& results) { PortalCommon::setupCoro([options, parent_window, handle, this, app_id](QDBusMessage reply) -> QCoro::Task<> { ScreenshotManager mgr; mgr.setType(ScreenshotWindow::Type::ColourPicker); co_await mgr.prepareScreenshotWindows(); mgr.showScreenshotWindows(); co_await qCoro(&mgr, &ScreenshotManager::finished); if (!mgr.accepted()) { reply.setArguments({uint(1), QVariantMap()}); QDBusConnection::sessionBus().send(reply); co_return; } auto color = mgr.clickedColor(); ScreenshotColorReply replyArg; replyArg.red = color.redF(); replyArg.green = color.greenF(); replyArg.blue = color.blueF(); QDBusArgument arg; arg << replyArg; reply.setArguments({uint(0), QVariantMap{{"color", QVariant::fromValue(arg)}}}); QDBusConnection::sessionBus().send(reply); }, message); return 0; } ================================================ FILE: desktop-portal/interfaces/screenshotinterface.h ================================================ #ifndef SCREENSHOTINTERFACE_H #define SCREENSHOTINTERFACE_H #include #include class QDBusMessage; class ScreenshotInterface : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Screenshot") Q_PROPERTY(uint version READ version) public: explicit ScreenshotInterface(QObject* parent = nullptr); uint version(); public slots: Q_SCRIPTABLE uint Screenshot(QDBusObjectPath handle, QString app_id, QString parent_window, QVariantMap options, const QDBusMessage& message, QVariantMap& results); Q_SCRIPTABLE uint PickColor(QDBusObjectPath handle, QString app_id, QString parent_window, QVariantMap options, const QDBusMessage& message, QVariantMap& results); }; struct ScreenshotColorReply { double red; double green; double blue; }; Q_DECLARE_METATYPE(ScreenshotColorReply); #endif // SCREENSHOTINTERFACE_H ================================================ FILE: desktop-portal/interfaces/settingsinterface.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "settingsinterface.h" #include #include SettingsInterface::SettingsInterface(QObject* parent) : QDBusAbstractAdaptor(parent) { qDBusRegisterMetaType>(); qDBusRegisterMetaType>>(); } uint SettingsInterface::version() { return 1; } QMap> SettingsInterface::ReadAll(QStringList namespaces) { return { {"org.freedesktop.appearance", {{"color-scheme", QDBusVariant(0u)}}} }; } QDBusVariant SettingsInterface::Read(QString ns, QString key) { if (ns == "org.freedesktop.appearance" && key == "color-scheme") { tSettings themeSettings("theDesk.platform"); QString baseColor = themeSettings.value("Palette/base").toString(); if (baseColor == "dark") { return QDBusVariant(1u); } else if (baseColor == "light") { return QDBusVariant(2u); } else { return QDBusVariant(0u); } } return QDBusVariant(QVariant()); } ================================================ FILE: desktop-portal/interfaces/settingsinterface.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SETTINGSINTERFACE_H #define SETTINGSINTERFACE_H #include #include #include class SettingsInterface : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Settings"); Q_PROPERTY(uint version READ version) public: explicit SettingsInterface(QObject* parent = nullptr); uint version(); public slots: Q_SCRIPTABLE QMap > ReadAll(QStringList namespaces); Q_SCRIPTABLE QDBusVariant Read(QString ns, QString key); signals: Q_SCRIPTABLE void SettingChanged(QString ns, QString key, QDBusVariant value); }; #endif // SETTINGSINTERFACE_H ================================================ FILE: desktop-portal/main.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include #include "interfaces/accessinterface.h" #include "interfaces/accountinterface.h" #include "interfaces/filechooserinterface.h" #include "interfaces/notificationinterface.h" #include "interfaces/screenshotinterface.h" #include "interfaces/settingsinterface.h" #include #include int main(int argc, char* argv[]) { // Turn off flatpak forwarding for ourselves qputenv("TD_PLATFORM_NO_FLATPAK_FORWARD", "1"); tApplication a(argc, argv); a.setQuitOnLastWindowClosed(false); QDBusConnection::sessionBus().registerService("org.freedesktop.impl.portal.desktop.thedesk"); tSettings::registerDefaults("theSuite", "theDesk.platform", "/usr/share/defaults/thedesk-platform.conf"); QObject* rootDbusObject = new QObject(); new FileChooserInterface(rootDbusObject); new SettingsInterface(rootDbusObject); new AccessInterface(rootDbusObject); new AccountInterface(rootDbusObject); new ScreenshotInterface(rootDbusObject); new NotificationInterface(rootDbusObject); QDBusConnection::sessionBus().registerObject("/org/freedesktop/portal/desktop", rootDbusObject, QDBusConnection::ExportAdaptors); return a.exec(); } ================================================ FILE: desktop-portal/org.freedesktop.impl.portal.desktop.thedesk.service.in ================================================ [D-BUS Service] Name=org.freedesktop.impl.portal.desktop.thedesk Exec=${CMAKE_INSTALL_FULL_LIBDIR}/xdg-desktop-portal-thedesk SystemdService=xdg-desktop-portal-thedesk.service ================================================ FILE: desktop-portal/portalcommon.cpp ================================================ #include "portalcommon.h" #include void PortalCommon::reparentWindow(QWidget* w, QString parentWindow) { if (parentWindow.startsWith("x11:")) { w->setAttribute(Qt::WA_NativeWindow, true); w->setWindowModality(Qt::WindowModal); auto parent = QWindow::fromWinId(parentWindow.mid(4).toULongLong(nullptr, 16)); w->windowHandle()->setTransientParent(parent); QObject::connect(w, &QWidget::destroyed, parent, &QWindow::deleteLater); } } void PortalCommon::setupCoro(std::function(QDBusMessage)> coro, const QDBusMessage& message) { message.setDelayedReply(true); coro(message.createReply()); } ================================================ FILE: desktop-portal/portalcommon.h ================================================ #ifndef PORTALCOMMON_H #define PORTALCOMMON_H #include #include #include namespace PortalCommon { void reparentWindow(QWidget* w, QString parentWindow); void setupCoro(std::function(QDBusMessage)> coro, const QDBusMessage& message); }; // namespace PortalCommon #endif // PORTALCOMMON_H ================================================ FILE: desktop-portal/portalhandle.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "portalhandle.h" #include PortalHandle::PortalHandle(QDBusObjectPath path, QObject* parent) : QObject(parent) { QDBusConnection::sessionBus().registerObject(path.path(), this, QDBusConnection::ExportScriptableContents); } void PortalHandle::Close() { emit closed(); } ================================================ FILE: desktop-portal/portalhandle.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PORTALHANDLE_H #define PORTALHANDLE_H #include #include class PortalHandle : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Request"); public: explicit PortalHandle(QDBusObjectPath path, QObject* parent = nullptr); public slots: Q_SCRIPTABLE void Close(); signals: void closed(); }; #endif // PORTALHANDLE_H ================================================ FILE: desktop-portal/screenshot_resources.qrc ================================================ icons/pen.svg icons/eraser.svg ================================================ FILE: desktop-portal/screenshotmanager.cpp ================================================ #include "screenshotmanager.h" #include "dialogs/screenshotwindow.h" #include struct ScreenshotManagerPrivate { QPixmap finalResult; QColor clickedColor; bool accepted = false; QList screenshotWindows; ScreenshotWindow::Type type = ScreenshotWindow::Type::ApplicationScreenshot; }; ScreenshotManager::ScreenshotManager(QObject* parent) : QObject{parent} { d = new ScreenshotManagerPrivate(); for (auto screen : qApp->screens()) { auto w = new ScreenshotWindow(screen); connect(w, &ScreenshotWindow::screenshotAvailable, this, &ScreenshotManager::acceptPixmap); connect(w, &ScreenshotWindow::colourClicked, this, &ScreenshotManager::acceptColor); connect(w, &ScreenshotWindow::cancelled, this, &ScreenshotManager::reject); d->screenshotWindows.append(w); } } ScreenshotManager::~ScreenshotManager() { for (auto window : d->screenshotWindows) { window->deleteLater(); } delete d; } void ScreenshotManager::setType(ScreenshotWindow::Type type) { d->type = type; for (auto window : d->screenshotWindows) { window->setType(type); } } QCoro::Task<> ScreenshotManager::prepareScreenshotWindows() { for (auto window : d->screenshotWindows) { co_await window->prepareWindow(); } } void ScreenshotManager::showScreenshotWindows() { for (auto window : d->screenshotWindows) { window->showFullScreen(); } } QPixmap ScreenshotManager::finalPixmap() { return d->finalResult; } QColor ScreenshotManager::clickedColor() { return d->clickedColor; } bool ScreenshotManager::accepted() { return d->accepted; } void ScreenshotManager::acceptPixmap(QPixmap pixmap) { d->finalResult = pixmap; d->accepted = true; auto w = d->screenshotWindows.constFirst(); connect(w, &ScreenshotWindow::animationComplete, this, &ScreenshotManager::finished); for (auto window : d->screenshotWindows) { window->animateTake(); } } void ScreenshotManager::acceptColor(QColor color) { d->clickedColor = color; d->accepted = true; // Skip the animation since this is a colour picker emit finished(); } void ScreenshotManager::reject() { d->accepted = false; auto w = d->screenshotWindows.constFirst(); connect(w, &ScreenshotWindow::animationComplete, this, &ScreenshotManager::finished); for (auto window : d->screenshotWindows) { window->animateDiscard(); } } ================================================ FILE: desktop-portal/screenshotmanager.h ================================================ #ifndef SCREENSHOTMANAGER_H #define SCREENSHOTMANAGER_H #include "dialogs/screenshotwindow.h" #include struct ScreenshotManagerPrivate; class ScreenshotManager : public QObject { Q_OBJECT public: explicit ScreenshotManager(QObject* parent = nullptr); ~ScreenshotManager(); void setType(ScreenshotWindow::Type type); QCoro::Task<> prepareScreenshotWindows(); void showScreenshotWindows(); QPixmap finalPixmap(); QColor clickedColor(); bool accepted(); signals: void finished(); private: ScreenshotManagerPrivate* d; void acceptPixmap(QPixmap pixmap); void acceptColor(QColor color); void reject(); }; #endif // SCREENSHOTMANAGER_H ================================================ FILE: desktop-portal/thedesk-portals.conf ================================================ [preferred] default=thedesk ================================================ FILE: desktop-portal/thedesk.portal ================================================ [portal] DBusName=org.freedesktop.impl.portal.desktop.thedesk Interfaces=org.freedesktop.impl.portal.FileChooser;org.freedesktop.impl.portal.Settings;org.freedesktop.impl.portal.Account;org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.Access;org.freedesktop.impl.portal.Notification UseIn=theDesk ================================================ FILE: desktop-portal/translations/ar_SA.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/au_AU.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/cy.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/da.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/de.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/en_US.qm ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/es.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/es_VE.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/id.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/nl.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Openen Save Opslaan FileDialog Open Openen Overwrite Overschrijven Save Here Hier Opslaan Create New File Here Hier een Nieuw Bestand Maken Open Folder Map Openen Choose This Folder Deze Map Kiezen Name this file Geef dit bestand een naam What do you want to name the file? Hoe wil je dit bestand noemen? Overwrite? Overschrijven? A file named %1 already exists. Do you want to overwrite it? Er bestaat al een bestand met de naam %1. Wil je deze overschrijven? Overwriting the file will replace its contents. Het bestand overschrijven zal de inhoud ervan vervangen. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/pt_BR.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/sv.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Save FileDialog Open Overwrite Save Here Create New File Here Open Folder Choose This Folder Name this file What do you want to name the file? Overwrite? A file named %1 already exists. Do you want to overwrite it? Overwriting the file will replace its contents. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/translations/vi.ts ================================================ AccessDialog Form AccessInterface Deny Allow AccountDialog Request for Account Information TextLabel Real Name Username Information to be shared Share Account Information %1 is requesting information about your profile. FileChooserInterface Open Mở Save Lưu FileDialog Open Mở Overwrite Ghi đè Save Here Lưu đây Create New File Here Tạo tệp mới đây Open Folder Mở thư mục Choose This Folder Chọn thư mục này Name this file Đặt tên tệp này What do you want to name the file? Bạn muốn gọi tệp này tên gì? Overwrite? Ghi đè? A file named %1 already exists. Do you want to overwrite it? Tệp tên %1 đã tồn tại. Bạn có muốn ghi đè không? Overwriting the file will replace its contents. Việc ghi đè tệp này sẽ thay thế nội dung của nó. NotificationInterface Activate PenButton Erase-o This and the next translation span two lines. Be spiffy with these! matic 2000 This and the previous translation span two lines. Be spiffy with these! ScreenshotWindow SCREENSHOT Crop Redact Reset Markup Cancel Share Screenshot Discard Copy ================================================ FILE: desktop-portal/xdg-desktop-portal-thedesk.service.in ================================================ [Unit] Description=XDG Portal (theDesk) [Service] Type=dbus BusName=org.freedesktop.impl.portal.desktop.thedesk ExecStart=${CMAKE_INSTALL_FULL_LIBDIR}/thedesk-desktop-portal Restart=no ================================================ FILE: dist/thedesk-blueprint.spec ================================================ Name: thedesk-blueprint Version: beta5 Release: 2%{?dist} Summary: Desktop Environment built on Qt License: GPLv3+ URL: https://github.com/vicr123/thedesk Source0: https://github.com/vicr123/thedesk/archive/%{version}.tar.gz Conflicts: thedesk Provides: thedesk %if 0%{?fedora} >= 33 BuildRequires: make qt5-qtbase-devel the-libs-blueprint-devel libtdesktopenvironment-blueprint-devel libX11-devel libXi-devel xorg-x11-drv-libinput-devel kf5-networkmanager-qt-devel kf5-modemmanager-qt-devel pulseaudio-qt-devel polkit-qt5-devel libtwebservices-blueprint-devel qt5-qtmultimedia-devel qt5-qtquickcontrols2-devel qt5-qtx11extras-devel qt5-qtlocation-devel qt5-qtbase-private-devel qt5-qtsvg-devel qt5-linguist qrencode-devel kf5-bluez-qt-devel wayfire-devel wayland-devel wlroots-devel Requires: qt5-qtbase kwin the-libs-blueprint libtdesktopenvironment-blueprint libX11 libXi kf5-networkmanager-qt kf5-modemmanager-qt pulseaudio-qt accountsservice contemporary-widgets-blueprint contemporary-icons ttf-contemporary polkit-qt5 libtwebservices-blueprint qt5-qtmultimedia qt5-qtquickcontrols2 qt5-qtx11extras qt5-qtlocation qt5-qtsvg libthedesk-blueprint qrencode kf5-bluez-qt thedesk-xdg-utils-blueprint %endif %define debug_package %{nil} %define _unpackaged_files_terminate_build 0 %description Desktop Environment built on Qt %package -n libthedesk-blueprint Summary: Libraries for %{name} plugins Conflicts: libthedesk Provides: libthedesk %description -n libthedesk-blueprint Libraries for theDesk plugins %package -n libthedesk-blueprint-devel Summary: Development files for libthedesk-blueprint Requires: libthedesk-blueprint%{?_isa} = %{version}-%{release} Conflicts: libthedesk-devel Provides: libthedesk-devel %description -n libthedesk-blueprint-devel The libthedesk-blueprint-devel package contains libraries and header files for developing applications that use libthedesk-blueprint. %prep %setup %build mkdir build cd build qmake-qt5 .. make %install cd build rm -rf $RPM_BUILD_ROOT make install INSTALL_ROOT=$RPM_BUILD_ROOT find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %{_bindir}/* %{_datarootdir}/* %{_libdir}/td-polkitagent %{_libdir}/thedesk/plugins/*.so %{_libdir}/qt5/plugins/platformthemes/*.so %{_libdir}/wayfire/*.so %{_sysconfdir}/* %files -n libthedesk-blueprint %{_libdir}/libthedesk.so* %files -n libthedesk-blueprint-devel %{_includedir}/* %changelog * Sun May 3 2020 Victor Tran - ================================================ FILE: dist/thedesk.spec ================================================ Name: thedesk Version: beta4 Release: 12%{?dist} Summary: Desktop Environment built on Qt License: GPLv3+ URL: https://github.com/vicr123/thedesk Source0: https://github.com/vicr123/thedesk/archive/%{version}.tar.gz %if 0%{?fedora} >= 33 BuildRequires: make qt5-qtbase-devel the-libs-devel libtdesktopenvironment-devel libX11-devel libXi-devel xorg-x11-drv-libinput-devel kf5-networkmanager-qt-devel kf5-modemmanager-qt-devel pulseaudio-qt-devel polkit-qt5-devel libtwebservices-devel qt5-qtmultimedia-devel qt5-qtquickcontrols2-devel qt5-qtx11extras-devel qt5-qtlocation-devel qt5-qtbase-private-devel qt5-qtsvg-devel qt5-linguist qrencode-devel kf5-bluez-qt-devel Requires: qt5-qtbase kwin the-libs libtdesktopenvironment libX11 libXi kf5-networkmanager-qt kf5-modemmanager-qt pulseaudio-qt accountsservice contemporary-widgets contemporary-icons ttf-contemporary polkit-qt5 libtwebservices qt5-qtmultimedia qt5-qtquickcontrols2 qt5-qtx11extras qt5-qtlocation qt5-qtsvg libthedesk qrencode kf5-bluez-qt thedesk-xdg-utils %endif %define debug_package %{nil} %define _unpackaged_files_terminate_build 0 %description Desktop Environment built on Qt %package -n libthedesk Summary: Libraries for %{name} plugins Conflicts: libthedesk Provides: libthedesk %description -n libthedesk Libraries for theDesk plugins %package -n libthedesk-devel Summary: Development files for libthedesk Requires: libthedesk%{?_isa} = %{version}-%{release} Conflicts: libthedesk-devel Provides: libthedesk-devel %description -n libthedesk-devel The libthedesk-devel package contains libraries and header files for developing applications that use libthedesk. %prep %setup %build mkdir build cd build qmake-qt5 .. make %install cd build rm -rf $RPM_BUILD_ROOT make install INSTALL_ROOT=$RPM_BUILD_ROOT find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %{_bindir}/* %{_datarootdir}/* %{_libdir}/td-polkitagent %{_libdir}/thedesk/plugins/*.so %{_libdir}/qt5/plugins/platformthemes/*.so %{_sysconfdir}/* %files -n libthedesk %{_libdir}/libthedesk.so* %files -n libthedesk-devel %{_includedir}/* %changelog * Sun May 3 2020 Victor Tran - ================================================ FILE: libthedesk/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) project(lib VERSION 1.0.0 LANGUAGES CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Multimedia DBus Svg QuickWidgets MultimediaWidgets) find_package(libcontemporary REQUIRED) find_package(libtdesktopenvironment REQUIRED) # TODO: Port NetworkManager portions # TODO: Port Wayland portions # TODO: Port pulseaudip portions set(SOURCES actionquickwidget.cpp barmanager.cpp chunk.cpp common.cpp gatewaymanager.cpp gatewaysearchprovider.cpp hudmanager.cpp icontextchunk.cpp keygrab.cpp localemanager.cpp onboarding/onboarding.cpp onboarding/onboardingbar.cpp onboarding/onboardingcontroller.cpp onboarding/onboardingfinal.cpp onboarding/onboardingstepper.cpp onboarding/onboardingvideo.cpp onboarding/onboardingwelcome.cpp onboardingmanager.cpp onboardingpage.cpp plugins/pluginmanager.cpp powermanager.cpp private/keyboardlayoutmodel.cpp private/keyboardlayoutselector.cpp private/localeselector.cpp private/quickwidgetcontainer.cpp quickswitch.cpp quietmodemanager.cpp server/sessionserver.cpp statemanager.cpp statuscentermanager.cpp statuscenterpane.cpp transparentdialog.cpp actionquickwidget.ui icontextchunk.ui onboarding/onboarding.ui onboarding/onboardingbar.ui onboarding/onboardingfinal.ui onboarding/onboardingvideo.ui onboarding/onboardingwelcome.ui private/keyboardlayoutselector.ui private/localeselector.ui private/quickwidgetcontainer.ui transparentdialog.ui libthedesk_resources.qrc ) set(HEADERS actionquickwidget.h barmanager.h chunk.h common.h gatewaymanager.h gatewaysearchprovider.h hudmanager.h icontextchunk.h keygrab.h libthedesk_global.h localemanager.h onboarding/onboarding.h onboarding/onboardingbar.h onboarding/onboardingcontroller.h onboarding/onboardingfinal.h onboarding/onboardingstepper.h onboarding/onboardingvideo.h onboarding/onboardingwelcome.h onboardingmanager.h onboardingpage.h plugins/pluginmanager.h plugins/plugininterface.h powermanager.h private/keyboardlayoutmodel.h private/keyboardlayoutselector.h private/localeselector.h private/onboardingmanager_p.h private/quickwidgetcontainer.h quickswitch.h quietmodemanager.h server/sessionserver.h statemanager.h statuscentermanager.h statuscenterpane.h transparentdialog.h ) set(PRIVATE_HEADERS ) add_library(libthedesk SHARED) cntp_init(libthedesk 20) set_target_properties(libthedesk PROPERTIES OUTPUT_NAME thedesk FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER com.vicr123.libthedesk VERSION 1.0.0) cntp_target_public_headers(libthedesk DESTINATION_DIRECTORY libthedesk HEADERS ${HEADERS} ) target_link_libraries(libthedesk Qt::Widgets Qt::DBus Qt::Multimedia Qt::Svg Qt::QuickWidgets Qt::MultimediaWidgets libcontemporary libtdesktopenvironment) target_compile_definitions(libthedesk PRIVATE LIBTHEDESK_LIBRARY) IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CMAKECONFIG_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/libthedesk.framework/Resources/CMake) set(HEADER_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}) set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/libthedesk.framework/Headers) set(LIBRARY_INSTALL_DIR ../) ELSE() set(CMAKECONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/libthedesk) set(HEADER_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}/libthedesk) set(INCLUDE_INSTALL_DIR ${HEADER_INSTALL_DIR}) set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}) ENDIF() target_sources(libthedesk PRIVATE ${SOURCES} ${HEADERS} ${PRIVATE_HEADERS}) configure_package_config_file(libthedeskConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libthedeskConfig.cmake INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} PATH_VARS HEADER_INSTALL_DIR LIBRARY_INSTALL_DIR) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libthedeskConfig.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) install(EXPORT libthedeskTargets FILE libthedeskTargets.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) install(TARGETS libthedesk EXPORT libthedeskTargets PUBLIC_HEADER DESTINATION ${HEADER_INSTALL_DIR} INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR}) cntp_mark_support_library_directory() ================================================ FILE: libthedesk/actionquickwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "actionquickwidget.h" #include "ui_actionquickwidget.h" #include #include #include #include "private/quickwidgetcontainer.h" #include "chunk.h" struct ActionQuickWidgetPrivate { Chunk* parentChunk = nullptr; QuickWidgetContainer* parentQuickWidget = nullptr; QMap buttons; }; ActionQuickWidget::ActionQuickWidget(Chunk* parent) : QWidget(parent), ui(new Ui::ActionQuickWidget) { ui->setupUi(this); d = new ActionQuickWidgetPrivate(); d->parentChunk = parent; } ActionQuickWidget::ActionQuickWidget(QuickWidgetContainer* parent) : QWidget(parent), ui(new Ui::ActionQuickWidget) { ui->setupUi(this); d = new ActionQuickWidgetPrivate(); d->parentQuickWidget = parent; } ActionQuickWidget::~ActionQuickWidget() { delete ui; delete d; } void ActionQuickWidget::addAction(QAction* action) { QWidget::addAction(action); } QAction* ActionQuickWidget::addAction(QString text, std::function triggered) { QAction* action = new QAction(text, this); connect(action, &QAction::triggered, this, triggered); QWidget::addAction(action); return action; } QAction* ActionQuickWidget::addAction(QIcon icon, QString text, std::function triggered) { QAction* action = new QAction(icon, text, this); connect(action, &QAction::triggered, this, triggered); QWidget::addAction(action); return action; } bool ActionQuickWidget::event(QEvent* event) { QActionEvent* e = static_cast(event); switch (event->type()) { case QEvent::ActionAdded: { QAction* action = e->action(); QPushButton* button = new QPushButton(); button->setText(action->text()); button->setIcon(action->icon()); button->setEnabled(action->isEnabled()); button->setVisible(action->isVisible()); connect(button, &QPushButton::clicked, this, [ = ] { if (d->parentChunk) { d->parentChunk->hideQuickWidget(); } else { d->parentQuickWidget->hideContainer(); } action->trigger(); }); connect(action, &QAction::changed, this, [ = ] { button->setText(action->text()); button->setIcon(action->icon()); button->setEnabled(action->isEnabled()); button->setVisible(action->isVisible()); }); d->buttons.insert(action, button); ui->actionsLayout->addWidget(button); break; } case QEvent::ActionChanged: break; case QEvent::ActionRemoved: { QWidget* button = d->buttons.value(e->action()); ui->actionsLayout->removeWidget(button); button->deleteLater(); d->buttons.remove(e->action()); break; } default: break; } return QWidget::event(event); } ================================================ FILE: libthedesk/actionquickwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ACTIONQUICKWIDGET_H #define ACTIONQUICKWIDGET_H #include #include namespace Ui { class ActionQuickWidget; } class Chunk; class QuickWidgetContainer; struct ActionQuickWidgetPrivate; class ActionQuickWidget : public QWidget { Q_OBJECT public: explicit ActionQuickWidget(Chunk* parent = nullptr); explicit ActionQuickWidget(QuickWidgetContainer* parent = nullptr); ~ActionQuickWidget(); void addAction(QAction* action); QAction* addAction(QString text, std::function triggered); QAction* addAction(QIcon icon, QString text, std::function triggered); private: Ui::ActionQuickWidget* ui; ActionQuickWidgetPrivate* d; bool event(QEvent* event); }; #endif // ACTIONQUICKWIDGET_H ================================================ FILE: libthedesk/actionquickwidget.ui ================================================ ActionQuickWidget 0 0 295 192 Form 0 0 0 0 0 ================================================ FILE: libthedesk/barmanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "barmanager.h" #include struct BarManagerPrivate { QList chunks; int barHeight; int locks = 0; }; BarManager::BarManager(QObject* parent) : QObject(parent) { d = new BarManagerPrivate(); } BarManager::~BarManager() { delete d; } void BarManager::addChunk(Chunk* chunk) { if (!d->chunks.contains(chunk)) { d->chunks.append(chunk); emit chunkAdded(chunk); } } void BarManager::removeChunk(Chunk* chunk) { if (d->chunks.contains(chunk)) { d->chunks.removeOne(chunk); emit chunkRemoved(chunk); } } bool BarManager::isChunkRegistered(Chunk* chunk) { return d->chunks.contains(chunk); } bool BarManager::isBarLocked() { return d->locks != 0; } BarManager::BarLockPtr BarManager::acquireLock() { return BarLockPtr(new BarLock()); } int BarManager::barHeight() { return d->barHeight; } QList BarManager::chunks() { return d->chunks; } void BarManager::setBarHeight(int barHeight) { d->barHeight = barHeight; emit barHeightChanged(barHeight); } BarManager::BarLock::BarLock() { isLocked = true; StateManager::barManager()->d->locks++; //Lock the bar emit StateManager::barManager()->barLockedChanged(true); } BarManager::BarLock::~BarLock() { unlock(); } void BarManager::BarLock::unlock() { if (isLocked) { isLocked = false; int locks = --StateManager::barManager()->d->locks; if (locks == 0) { //Unlock the bar emit StateManager::barManager()->barLockedChanged(false); } } } ================================================ FILE: libthedesk/barmanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BARMANAGER_H #define BARMANAGER_H #include #include class Chunk; class ChunkContainer; class BarWindow; struct BarManagerPrivate; class BarManager : public QObject { Q_OBJECT public: class BarLock { public: ~BarLock(); void unlock(); protected: friend BarManager; BarLock(); bool isLocked = false; }; typedef QSharedPointer BarLockPtr; explicit BarManager(QObject* parent = nullptr); ~BarManager(); void addChunk(Chunk* chunk); void removeChunk(Chunk* chunk); bool isChunkRegistered(Chunk* chunk); bool isBarLocked(); BarLockPtr acquireLock(); int barHeight(); protected: friend ChunkContainer; friend BarWindow; QList chunks(); void setBarHeight(int barHeight); signals: void chunkAdded(Chunk* chunk); void chunkRemoved(Chunk* chunk); void barHeightTransitioning(qreal percentage); void barHeightChanged(int height); void barLockedChanged(bool isBarLocked); protected: BarManagerPrivate* d; }; #endif // BARMANAGER_H ================================================ FILE: libthedesk/chunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "chunk.h" #include #include #include #include "private/quickwidgetcontainer.h" struct ChunkPrivate { QuickWidgetContainer* quickWidgetContainer; }; Chunk::Chunk() : QWidget(nullptr) { d = new ChunkPrivate(); d->quickWidgetContainer = new QuickWidgetContainer(this); } Chunk::~Chunk() { delete d; } bool Chunk::chunkRegistered() { return StateManager::instance()->barManager()->isChunkRegistered(this); } void Chunk::performStatusBarTransition(qreal percentage) { Q_UNUSED(percentage); //noop } void Chunk::showQuickWidget() { if (quickWidget()) { //Show the quick widget d->quickWidgetContainer->showContainer(); } } void Chunk::hideQuickWidget() { d->quickWidgetContainer->hideContainer(); } void Chunk::mousePressEvent(QMouseEvent* event) { event->accept(); } void Chunk::mouseReleaseEvent(QMouseEvent* event) { if (event->pos().x() < this->width() && event->pos().x() > 0 && event->pos().y() < this->height() && event->pos().y() > 0) { emit clicked(); } } QWidget* Chunk::quickWidget() { return nullptr; } ================================================ FILE: libthedesk/chunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CHUNK_H #define CHUNK_H #include class QuickWidgetContainer; struct ChunkPrivate; class Chunk : public QWidget { Q_OBJECT public: explicit Chunk(); ~Chunk(); virtual QString name() = 0; bool chunkRegistered(); virtual int expandedHeight() = 0; virtual int statusBarHeight() = 0; void performStatusBarTransition(qreal percentage); void showQuickWidget(); void hideQuickWidget(); signals: void statusBarHeightChanged(); void expandedHeightChanged(); void clicked(); protected: friend QuickWidgetContainer; virtual QWidget* quickWidget(); private: ChunkPrivate* d; void mousePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); }; #endif // CHUNK_H ================================================ FILE: libthedesk/common.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "common.h" int Common::getInsertionIndex(QStringList preferredOrder, QStringList currentItems, QString item) { //First, check to see if there is a preferred order for this item if (!preferredOrder.contains(item)) { //No preferred order so just add it at the end return -1; } //Find where this item is supposed to go int beforeIndex = preferredOrder.indexOf(item) - 1; if (beforeIndex == -1) { //Add this item at the beginning return 0; } //Iterate over the currently loaded items and insert the item at the correct place QStringList itemsBefore = preferredOrder.mid(0, beforeIndex + 1); for (int i = currentItems.count() - 1; i >= 0; i--) { if (itemsBefore.contains(currentItems.at(i))) { return i + 1; } } //None of the other items were found so just add it at the beginning return 0; } ================================================ FILE: libthedesk/common.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef COMMON_H #define COMMON_H #include namespace Common { /** * Given a list of items, find the correct index to insert this item into * * @param preferredOrder The preferred order of items * @param currentItems The items that are currently in the layout * @param item The name of the current item * @return An index, or -1 to add to the end of the layout */ int getInsertionIndex(QStringList preferredOrder, QStringList currentItems, QString item); } #endif // COMMON_H ================================================ FILE: libthedesk/gatewaymanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "gatewaymanager.h" struct GatewayManagerPrivate { QList providers; int gatewayWidth = 0; }; GatewayManager::GatewayManager(QObject* parent) : QObject(parent) { d = new GatewayManagerPrivate(); } GatewayManager::~GatewayManager() { delete d; } void GatewayManager::registerSearchProvider(GatewaySearchProvider* provider) { if (!d->providers.contains(provider)) { d->providers.append(provider); emit searchProviderRegistered(provider); } } void GatewayManager::deregisterSearchProvider(GatewaySearchProvider* provider) { if (d->providers.contains(provider)) { d->providers.removeOne(provider); emit searchProviderDeregistered(provider); } } bool GatewayManager::isSearchProviderRegistered(GatewaySearchProvider* provider) { return d->providers.contains(provider); } QList GatewayManager::searchProviders() { return d->providers; } int GatewayManager::gatewayWidth() { return d->gatewayWidth; } void GatewayManager::setGatewayWidth(int width) { d->gatewayWidth = width; emit gatewayWidthChanged(width); } ================================================ FILE: libthedesk/gatewaymanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef GATEWAYMANAGER_H #define GATEWAYMANAGER_H #include class Gateway; class GatewaySearchProvider; struct GatewayManagerPrivate; class GatewayManager : public QObject { Q_OBJECT public: explicit GatewayManager(QObject* parent = nullptr); ~GatewayManager(); void registerSearchProvider(GatewaySearchProvider* provider); void deregisterSearchProvider(GatewaySearchProvider* provider); bool isSearchProviderRegistered(GatewaySearchProvider* provider); QList searchProviders(); int gatewayWidth(); signals: void searchProviderRegistered(GatewaySearchProvider* provider); void searchProviderDeregistered(GatewaySearchProvider* provider); void gatewayWidthChanged(int width); protected: friend Gateway; void setGatewayWidth(int width); private: GatewayManagerPrivate* d; }; #endif // GATEWAYMANAGER_H ================================================ FILE: libthedesk/gatewaysearchprovider.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "gatewaysearchprovider.h" #include #include GatewaySearchProvider::GatewaySearchProvider(QObject* parent) : QObject(parent) { } GatewaySearchProvider::~GatewaySearchProvider() { if (StateManager::gatewayManager()->isSearchProviderRegistered(this)) StateManager::gatewayManager()->deregisterSearchProvider(this); } ================================================ FILE: libthedesk/gatewaysearchprovider.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef GATEWAYSEARCHPROVIDER_H #define GATEWAYSEARCHPROVIDER_H #include #include #include class GatewaySearchProvider : public QObject { Q_OBJECT public: explicit GatewaySearchProvider(QObject* parent = nullptr); ~GatewaySearchProvider(); virtual tPromise>* searchResults(QString query) = 0; virtual void launch(QVariantMap data) = 0; virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QVariantMap data) const = 0; virtual QSize sizeHint(const QStyleOptionViewItem& option, const QVariantMap data) const = 0; signals: }; #endif // GATEWAYSEARCHPROVIDER_H ================================================ FILE: libthedesk/hudmanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "hudmanager.h" HudManager::HudManager(QObject* parent) : QObject(parent) { } void HudManager::showHud(QVariantMap parameters) { emit requestHud(parameters); } void HudManager::hideHud() { emit requestHideHud(); } ================================================ FILE: libthedesk/hudmanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef HUDMANAGER_H #define HUDMANAGER_H #include #include class HudManager : public QObject { Q_OBJECT public: explicit HudManager(QObject* parent = nullptr); void showHud(QVariantMap parameters); void hideHud(); signals: void requestHud(QVariantMap parameters); void requestHideHud(); }; #endif // HUDMANAGER_H ================================================ FILE: libthedesk/icontextchunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "icontextchunk.h" #include "ui_icontextchunk.h" #include "barmanager.h" #include "statemanager.h" #include #include struct IconTextChunkPrivate { QString name; QWidget* quickWidget = nullptr; }; IconTextChunk::IconTextChunk(QString name) : Chunk(), ui(new Ui::IconTextChunk) { ui->setupUi(this); d = new IconTextChunkPrivate(); d->name = name; connect(StateManager::barManager(), &BarManager::barHeightTransitioning, this, [=](qreal percentage) { int padding = 3 + 6 * percentage; this->layout()->setContentsMargins(6, padding, 6, padding); if (qFuzzyCompare(percentage, 1)) { ui->textLabel->setFixedWidth(QWIDGETSIZE_MAX); } else { ui->textLabel->setFixedWidth(ui->textLabel->sizeHint().width() * percentage); } }); connect(this, &IconTextChunk::clicked, this, [=] { showQuickWidget(); }); } IconTextChunk::~IconTextChunk() { delete d; delete ui; } void IconTextChunk::setIcon(QIcon icon) { ui->iconLabel->setPixmap(icon.pixmap(SC_DPI_T(QSize(16, 16), QSize))); } void IconTextChunk::setText(QString text) { ui->textLabel->setText(text); } void IconTextChunk::setQuickWidget(QWidget* widget) { d->quickWidget = widget; } void IconTextChunk::deleteLater() { Chunk::deleteLater(); } QString IconTextChunk::name() { return d->name; } int IconTextChunk::expandedHeight() { return qMax(SC_DPI(16), this->fontMetrics().height()) + 18; } int IconTextChunk::statusBarHeight() { return qMax(SC_DPI(16), this->fontMetrics().height()) + 6; } QWidget* IconTextChunk::quickWidget() { return d->quickWidget; } ================================================ FILE: libthedesk/icontextchunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ICONTEXTCHUNK_H #define ICONTEXTCHUNK_H #include #include "chunk.h" namespace Ui { class IconTextChunk; } struct IconTextChunkPrivate; class IconTextChunk : public Chunk { Q_OBJECT public: explicit IconTextChunk(QString name); ~IconTextChunk(); void setIcon(QIcon icon); void setText(QString text); void setQuickWidget(QWidget* widget); void deleteLater(); private: Ui::IconTextChunk* ui; IconTextChunkPrivate* d; // Chunk interface public: QString name(); int expandedHeight(); int statusBarHeight(); protected: virtual QWidget* quickWidget(); }; #endif // ICONTEXTCHUNK_H ================================================ FILE: libthedesk/icontextchunk.ui ================================================ IconTextChunk 0 0 124 35 Form 0 0 TextLabel TextLabel ================================================ FILE: libthedesk/keygrab.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "keygrab.h" #include #include #include #include struct KeyGrabPrivate { QKeySequence seq; quint64 grabId; bool isPaused = true; }; KeyGrab::KeyGrab(QKeySequence seq, QObject* parent) : QObject(parent) { d = new KeyGrabPrivate(); d->seq = seq; init(); } KeyGrab::KeyGrab(QKeySequence defaultSeq, QString settingName, QObject* parent) : QObject(parent) { d = new KeyGrabPrivate(); d->seq = defaultSeq; //TODO init(); } KeyGrab::~KeyGrab() { if (!d->isPaused) this->pause(); delete d; } void KeyGrab::pause() { DesktopWm::ungrabKey(d->grabId); d->isPaused = true; } void KeyGrab::resume() { //Before we grab the key, if KGlobalAccel is running, ask it to quit if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kglobalaccel").value()) { QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kglobalaccel", "/MainApplication", "org.qtproject.Qt.QCoreApplication", "quit"); QDBusConnection::sessionBus().call(message); } Qt::Key key = static_cast(static_cast(d->seq[0]) & ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)); Qt::KeyboardModifiers mod = static_cast(static_cast(d->seq[0]) & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)); d->grabId = DesktopWm::grabKey(key, mod); d->isPaused = false; } void KeyGrab::init() { connect(DesktopWm::instance(), &DesktopWm::grabbedKeyPressed, this, [ = ](quint64 grabId) { if (d->grabId == grabId) emit activated(); }); resume(); } ================================================ FILE: libthedesk/keygrab.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYGRAB_H #define KEYGRAB_H #include struct KeyGrabPrivate; class KeyGrab : public QObject { Q_OBJECT public: explicit KeyGrab(QKeySequence seq, QObject* parent = nullptr); explicit KeyGrab(QKeySequence defaultSeq, QString settingName, QObject* parent = nullptr); ~KeyGrab(); void pause(); void resume(); signals: void activated(); private: KeyGrabPrivate* d; void init(); }; #endif // KEYGRAB_H ================================================ FILE: libthedesk/libthedesk.pro ================================================ QT += widgets thelib tdesktopenvironment dbus multimedia multimediawidgets quickwidgets svg TEMPLATE = lib DEFINES += LIBTHEDESK_LIBRARY TARGET = thedesk CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) include(/usr/share/the-libs/pri/varset.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ actionquickwidget.cpp \ barmanager.cpp \ chunk.cpp \ common.cpp \ gatewaymanager.cpp \ gatewaysearchprovider.cpp \ hudmanager.cpp \ icontextchunk.cpp \ keygrab.cpp \ localemanager.cpp \ onboarding/onboarding.cpp \ onboarding/onboardingbar.cpp \ onboarding/onboardingcontroller.cpp \ onboarding/onboardingfinal.cpp \ onboarding/onboardingstepper.cpp \ onboarding/onboardingvideo.cpp \ onboarding/onboardingwelcome.cpp \ onboardingmanager.cpp \ onboardingpage.cpp \ plugins/pluginmanager.cpp \ powermanager.cpp \ private/keyboardlayoutmodel.cpp \ private/keyboardlayoutselector.cpp \ private/localeselector.cpp \ private/quickwidgetcontainer.cpp \ quickswitch.cpp \ quietmodemanager.cpp \ server/sessionserver.cpp \ statemanager.cpp \ statuscentermanager.cpp \ statuscenterpane.cpp \ transparentdialog.cpp HEADERS += \ actionquickwidget.h \ barmanager.h \ chunk.h \ common.h \ gatewaymanager.h \ gatewaysearchprovider.h \ hudmanager.h \ icontextchunk.h \ keygrab.h \ libthedesk_global.h \ localemanager.h \ onboarding/onboarding.h \ onboarding/onboardingbar.h \ onboarding/onboardingcontroller.h \ onboarding/onboardingfinal.h \ onboarding/onboardingstepper.h \ onboarding/onboardingvideo.h \ onboarding/onboardingwelcome.h \ onboardingmanager.h \ onboardingpage.h \ plugins/pluginmanager.h \ plugins/plugininterface.h \ powermanager.h \ private/keyboardlayoutmodel.h \ private/keyboardlayoutselector.h \ private/localeselector.h \ private/onboardingmanager_p.h \ private/quickwidgetcontainer.h \ quickswitch.h \ quietmodemanager.h \ server/sessionserver.h \ statemanager.h \ statuscentermanager.h \ statuscenterpane.h \ transparentdialog.h # Default rules for deployment. unix { target.path = $$THELIBS_INSTALL_LIB headers.files = *.h headers.path = $$[QT_INSTALL_HEADERS]/libthedesk/ pluginheaders.files = plugins/plugininterface.h pluginheaders.path = $$[QT_INSTALL_HEADERS]/thedesk/ pluginmanagerheaders.files = plugins/pluginmanager.h pluginmanagerheaders.path = $$[QT_INSTALL_HEADERS]/libthedesk/plugins onboardingheaders.files = onboarding/onboardingcontroller.h onboardingheaders.path = $$[QT_INSTALL_HEADERS]/libthedesk/onboarding translations.files = translations/*.qm translations.path = /usr/share/thedesk/libthedesk/translations INSTALLS += target translations headers pluginheaders onboardingheaders pluginmanagerheaders } DEFINES += SYSTEM_LIBRARY_DIRECTORY=\\\"$$THELIBS_INSTALL_LIB\\\" FORMS += \ actionquickwidget.ui \ icontextchunk.ui \ onboarding/onboarding.ui \ onboarding/onboardingbar.ui \ onboarding/onboardingfinal.ui \ onboarding/onboardingvideo.ui \ onboarding/onboardingwelcome.ui \ private/keyboardlayoutselector.ui \ private/localeselector.ui \ private/quickwidgetcontainer.ui \ transparentdialog.ui DISTFILES += \ onboarding/OnboardingVideoForm.qml RESOURCES += \ libthedesk_resources.qrc ================================================ FILE: libthedesk/libthedeskConfig.cmake.in ================================================ set(libthebranch_VERSION 1.0.0) @PACKAGE_INIT@ include("${CMAKE_CURRENT_LIST_DIR}/libthedeskTargets.cmake") find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia DBus Svg QuickWidgets MultimediaWidgets) check_required_components(libthedesk) ================================================ FILE: libthedesk/libthedesk_global.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef LIBTHEDESK_GLOBAL_H #define LIBTHEDESK_GLOBAL_H #include #if defined(LIBTHEDESK_LIBRARY) # define LIBTHEDESK_EXPORT Q_DECL_EXPORT #else # define LIBTHEDESK_EXPORT Q_DECL_IMPORT #endif #endif // LIBTHEDESK_GLOBAL_H ================================================ FILE: libthedesk/libthedesk_resources.qrc ================================================ onboarding/OnboardingVideoForm.qml images/splash-background.svg ================================================ FILE: libthedesk/localemanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "localemanager.h" #include "private/keyboardlayoutselector.h" #include "private/localeselector.h" #include #include #include #include #include #include #include struct LocaleManagerPrivate { QMap translators; QMap searchPaths; tSettings settings; QStringList preferredLocales; QString formats; int current = 0; }; LocaleManager::LocaleManager(QObject* parent) : QObject(parent) { d = new LocaleManagerPrivate(); d->preferredLocales = d->settings.delimitedList("Locale/locales"); if (d->preferredLocales.count() == 1 && d->preferredLocales.first() == "") d->preferredLocales = QStringList({"C"}); d->formats = d->settings.value("Locale/formats").toString(); this->updateLocales(); this->addTranslationSet({QDir::cleanPath(qApp->applicationDirPath() + "/../libthedesk/translations"), "/usr/share/thedesk/libthedesk/translations"}); connect(&d->settings, &tSettings::settingChanged, this, [=](QString key, QVariant value) { if (key == "Locale/locales") { d->preferredLocales = d->settings.delimitedList("Locale/locales"); if (d->preferredLocales.count() == 1 && d->preferredLocales.first() == "") d->preferredLocales = QStringList({"C"}); this->updateLocales(); emit localesChanged(); } else if (key == "Locale/formats") { d->formats = value.toString(); this->updateLocales(); emit formatCountryChanged(); } }); } LocaleManager::~LocaleManager() { delete d; } int LocaleManager::addTranslationSet(QStringList searchPaths) { int id = d->current; d->current++; QTranslator* translator = new QTranslator(this); qApp->installTranslator(translator); d->translators.insert(id, translator); d->searchPaths.insert(id, searchPaths); updateTranslator(id); return id; } void LocaleManager::removeTranslationSet(int translationSet) { if (!d->translators.contains(translationSet)) return; QTranslator* translator = d->translators.value(translationSet); qApp->removeTranslator(translator); translator->deleteLater(); d->translators.remove(translationSet); d->searchPaths.remove(translationSet); } QLocale LocaleManager::showLocaleSelector(QWidget* parent, bool* ok) { if (ok) *ok = true; tPromiseResults results = TPROMISE_CREATE_SAME_THREAD(QLocale, { bool* stillValid = new bool(true); LocaleSelector* selector = new LocaleSelector(); tPopover* popover = new tPopover(selector); popover->setPopoverWidth(SC_DPI(500)); connect(selector, &LocaleSelector::rejected, this, [=] { rej(""); *stillValid = false; popover->dismiss(); }); connect(selector, &LocaleSelector::accepted, this, [=](QLocale locale) { res(locale); *stillValid = false; popover->dismiss(); }); connect(popover, &tPopover::dismissed, this, [=] { if (*stillValid) rej(""); popover->deleteLater(); selector->deleteLater(); delete stillValid; }); popover->show(parent); })->await(); if (!results.error.isEmpty() && ok) *ok = false; return results.result; } void LocaleManager::addLocale(QLocale locale) { if (!d->preferredLocales.contains(locale.bcp47Name())) { d->preferredLocales.append(locale.bcp47Name()); if (d->preferredLocales.contains("C")) d->preferredLocales.removeAll("C"); d->settings.setDelimitedList("Locale/locales", d->preferredLocales); } } void LocaleManager::prependLocale(QLocale locale) { if (!d->preferredLocales.contains(locale.bcp47Name())) { d->preferredLocales.prepend(locale.bcp47Name()); if (d->preferredLocales.contains("C")) d->preferredLocales.removeAll("C"); d->settings.setDelimitedList("Locale/locales", d->preferredLocales); } } void LocaleManager::removeLocale(QLocale locale) { d->preferredLocales.removeAll(locale.bcp47Name()); d->settings.setDelimitedList("Locale/locales", d->preferredLocales); } void LocaleManager::moveLocaleUp(QLocale locale) { int index = d->preferredLocales.indexOf(locale.bcp47Name()); if (index != 0) { d->preferredLocales.removeAt(index); d->preferredLocales.insert(index - 1, locale.bcp47Name()); d->settings.setDelimitedList("Locale/locales", d->preferredLocales); } } void LocaleManager::moveLocaleDown(QLocale locale) { int index = d->preferredLocales.indexOf(locale.bcp47Name()); if (index != d->preferredLocales.count() - 1) { d->preferredLocales.removeAt(index); d->preferredLocales.insert(index + 1, locale.bcp47Name()); d->settings.setDelimitedList("Locale/locales", d->preferredLocales); } } QList LocaleManager::locales() { QList locales; for (QString locale : d->preferredLocales) { locales.append(QLocale(locale)); } return locales; } QLocale::Country LocaleManager::formatCountry() { return QLocale(d->formats).country(); } void LocaleManager::setFormatCountry(QLocale::Country country) { // Choose the first locale QList locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, country); if (locales.isEmpty()) locales.append(QLocale()); d->settings.setValue("Locale/formats", locales.first().name()); } QString LocaleManager::showKeyboardLayoutSelector(QWidget* parent, bool* ok) { if (ok) *ok = true; tPromiseResults results = TPROMISE_CREATE_SAME_THREAD(QString, { bool* stillValid = new bool(true); KeyboardLayoutSelector* selector = new KeyboardLayoutSelector(); tPopover* popover = new tPopover(selector); popover->setPopoverWidth(SC_DPI(500)); connect(selector, &KeyboardLayoutSelector::rejected, this, [=] { rej(""); *stillValid = false; popover->dismiss(); }); connect(selector, &KeyboardLayoutSelector::accepted, this, [=](QString locale) { res(locale); *stillValid = false; popover->dismiss(); }); connect(popover, &tPopover::dismissed, this, [=] { if (*stillValid) rej(""); popover->deleteLater(); selector->deleteLater(); delete stillValid; }); popover->show(parent); })->await(); if (!results.error.isEmpty() && ok) *ok = false; return results.result; } QLocale LocaleManager::formatLocale() { QLocale locale(d->preferredLocales.first()); QLocale formatsTryLocale(d->formats); QLocale formatsLocale(locale.language(), formatsTryLocale.country()); if (formatsLocale.country() != formatsTryLocale.country()) formatsLocale = formatsTryLocale; return formatsLocale; } void LocaleManager::updateTranslator(int id) { QTranslator* translator = d->translators.value(id); QStringList searchPaths = d->searchPaths.value(id); for (QString path : searchPaths) { if (translator->load(QLocale(), "", "", path, ".qm")) return; // Success! } } void LocaleManager::updateLocales() { if (d->preferredLocales.isEmpty()) d->preferredLocales.append("C"); QLocale locale(d->preferredLocales.first()); QLocale::setDefault(locale); QLocale formatsLocale = this->formatLocale(); QByteArray mainLocale = glibName(locale).toUtf8(); QByteArray formatsLocaleStr = glibName(formatsLocale).toUtf8(); qputenv("LANG", mainLocale); qputenv("LC_CTYPE", mainLocale); qputenv("LC_COLLATE", mainLocale); qputenv("LC_TIME", formatsLocaleStr); qputenv("LC_NUMERIC", formatsLocaleStr); qputenv("LC_MONETARY", formatsLocaleStr); qputenv("LC_MESSAGES", mainLocale); qputenv("LC_PAPER", formatsLocaleStr); qputenv("LC_MEASUREMENT", formatsLocaleStr); qputenv("LC_NAME", formatsLocaleStr); qputenv("LC_ADDRESS", formatsLocaleStr); qputenv("LC_TELEPHONE", formatsLocaleStr); // qputenv("LC_ALL", glibName(locale).toUtf8()); QStringList languages; for (QString locale : d->preferredLocales) { languages.append(glibName(QLocale(locale))); } qputenv("LANGUAGE", languages.join(":").toUtf8()); // Update all the translators for (int id : d->translators.keys()) { updateTranslator(id); } static_cast(tApplication::instance())->installTranslators(); } QString LocaleManager::glibName(QLocale locale, QString encoding) { return locale.name() + "." + encoding; } ================================================ FILE: libthedesk/localemanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef LOCALEMANAGER_H #define LOCALEMANAGER_H #include struct LocaleManagerPrivate; class LocaleManager : public QObject { Q_OBJECT public: explicit LocaleManager(QObject* parent = nullptr); ~LocaleManager(); int addTranslationSet(QStringList searchPaths); void removeTranslationSet(int translationSet); QLocale showLocaleSelector(QWidget* parent, bool* ok = nullptr); void addLocale(QLocale locale); void prependLocale(QLocale locale); void removeLocale(QLocale locale); void moveLocaleUp(QLocale locale); void moveLocaleDown(QLocale locale); QList locales(); QLocale::Country formatCountry(); void setFormatCountry(QLocale::Country country); QString showKeyboardLayoutSelector(QWidget* parent, bool* ok = nullptr); QLocale formatLocale(); signals: void formatCountryChanged(); void localesChanged(); private: LocaleManagerPrivate* d; void updateTranslator(int id); void updateLocales(); QString glibName(QLocale locale, QString encoding = "UTF-8"); }; #endif // LOCALEMANAGER_H ================================================ FILE: libthedesk/onboarding/OnboardingVideoForm.qml ================================================ import QtQuick 2.0 import QtMultimedia 6.4 Item { VideoOutput { id: video x: 0 y: 0 width: parent.width height: parent.height // flushMode: VideoOutput.LastFrame fillMode: VideoOutput.PreserveAspectCrop // source: sourceVideo } } ================================================ FILE: libthedesk/onboarding/onboarding.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboarding.h" #include "ui_onboarding.h" #include "onboardingbar.h" #include "onboardingstepper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct OnboardingPrivate { QStringList preferredOnboardingOrder; QList> steps; QList> steppers; QByteArray singleAudioData; QByteArray loopAudioData; QAudioSink* audioOutput = nullptr; QIODevice* audioOutputDevice; int audioPointer = 0; bool audioEnabled = true; OnboardingBar* bar; bool barVisible = false; tVariantAnimation* contentAnim; tVariantAnimation* barAnim; tVariantAnimation* fadeAnim; bool onboardingStarted = false; tSettings settings; }; Onboarding::Onboarding(QWidget* parent) : QDialog(parent), ui(new Ui::Onboarding) { ui->setupUi(this); Q_INIT_RESOURCE(libthedesk_resources); this->setWindowFlag(Qt::WindowStaysOnTopHint); this->setWindowFlag(Qt::FramelessWindowHint); this->setCursor(QCursor(Qt::BlankCursor)); d = new OnboardingPrivate(); d->preferredOnboardingOrder = d->settings.delimitedList("Onboarding/order"); ui->stepperFrame->setFixedSize(SC_DPI_T(QSize(200, 600), QSize)); ui->stackedWidget->setFixedSize(SC_DPI_T(QSize(800, 600), QSize)); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); ui->contentWrapper->setFixedHeight(0); ui->contentWrapper->setVisible(false); OnboardingManager* manager = StateManager::onboardingManager(); manager->d->onboardingRunning = true; connect(manager, &OnboardingManager::nextStep, this, [=] { if (ui->stackedWidget->count() == ui->stackedWidget->currentIndex() + 1) { completeOnboarding(); } else { ui->stackedWidget->setCurrentIndex(ui->stackedWidget->currentIndex() + 1); } }); connect(manager, &OnboardingManager::previousStep, this, [=] { ui->stackedWidget->setCurrentIndex(ui->stackedWidget->currentIndex() - 1); }); // Populate the stacked widget with all the onboarding items QStringList currentItems; for (OnboardingPage* step : qAsConst(manager->d->steps)) { OnboardingStepper* stepper = new OnboardingStepper(this); stepper->setText(step->displayName()); connect(ui->stackedWidget, &tStackedWidget::switchingFrame, this, [=](int step) { stepper->setCurrentStep(step + 1); }); int index = Common::getInsertionIndex(d->preferredOnboardingOrder, currentItems, step->name()); // Make sure this pane is actually configured to be in the onboarding if (index != -1) { // Add this pane at the correct index ui->stackedWidget->insertWidget(index, step); currentItems.insert(index, step->name()); d->steps.insert(index, {step->name(), step}); ui->stepperLayout->insertWidget(index, stepper); d->steppers.insert(index, {stepper, step}); } else { // Hide the stepper so it doesn't show up in the background stepper->setVisible(false); } } for (int i = 0; i < d->steppers.count(); i++) { d->steppers.at(i).first->setStep(i + 1); if (i == d->steppers.count() - 1) d->steppers.at(i).first->setIsFinal(true); } d->bar = new OnboardingBar(this); d->bar->setParent(this); connect(d->bar, &OnboardingBar::muteToggled, this, [=](bool mute) { if (d->audioOutput) d->audioOutput->setVolume(mute ? 0 : 100); }); connect(d->bar, &OnboardingBar::closeClicked, this, [=] { StateManager::instance()->powerManager()->showPowerOffConfirmation(); }); d->bar->setVisible(false); d->bar->installEventFilter(this); d->contentAnim = new tVariantAnimation(this); d->contentAnim->setEasingCurve(QEasingCurve::OutCubic); d->contentAnim->setDuration(500); connect(d->contentAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { ui->contentWrapper->setFixedHeight(value.toInt()); }); d->barAnim = new tVariantAnimation(this); d->barAnim->setEasingCurve(QEasingCurve::OutCubic); d->barAnim->setDuration(500); connect(d->barAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { d->bar->move(0, value.toInt()); }); d->fadeAnim = new tVariantAnimation(this); d->fadeAnim->setStartValue(0); d->fadeAnim->setEndValue(255); d->fadeAnim->setEasingCurve(QEasingCurve::OutCubic); d->fadeAnim->setDuration(500); connect(d->fadeAnim, &tVariantAnimation::valueChanged, this, [=] { this->update(); }); if (d->settings.value("Onboarding/onboardingAudio").toBool()) { auto format = QMediaDevices::defaultAudioOutput().preferredFormat(); QEventLoop* loop = new QEventLoop(); for (int i = 0; i < 2; i++) { QByteArray* array = (i == 0 ? &d->singleAudioData : &d->loopAudioData); QString setting = (i == 0 ? "Onboarding/audio.start" : "Onboarding/audio.loop"); auto file = QUrl::fromLocalFile(d->settings.value(setting).toString()); QEventLoopLocker* locker = new QEventLoopLocker(loop); QAudioDecoder* audioDecoder = new QAudioDecoder(); audioDecoder->setSource(file); audioDecoder->setAudioFormat(format); connect(audioDecoder, &QAudioDecoder::bufferReady, this, [=] { QAudioBuffer buf = audioDecoder->read(); array->append(buf.constData(), buf.byteCount()); }); connect(audioDecoder, &QAudioDecoder::finished, this, [=] { delete locker; audioDecoder->deleteLater(); }); connect(audioDecoder, QOverload::of(&QAudioDecoder::error), this, [=](QAudioDecoder::Error error) { delete locker; audioDecoder->deleteLater(); }); audioDecoder->start(); } loop->exec(); loop->deleteLater(); d->audioOutput = new QAudioSink(format); d->audioOutput->setBufferSize(176400); d->audioOutputDevice = d->audioOutput->start(); QTimer* audioTimer = new QTimer(d->audioOutput); audioTimer->setInterval(100); connect(audioTimer, &QTimer::timeout, this, &Onboarding::writeAudio); audioTimer->start(); writeAudio(); } if (d->settings.value("Onboarding/onboardingVideo").toBool()) { this->setAttribute(Qt::WA_TranslucentBackground); } else { this->startOnboarding(); } auto* terminalShortcut = new QShortcut(QKeySequence(Qt::ControlModifier | Qt::AltModifier | Qt::Key_T), this); connect(terminalShortcut, &QShortcut::activated, this, [this] { this->hide(); auto env = QProcessEnvironment::systemEnvironment(); env.remove("LD_LIBRARY_PATH"); auto* proc = new QProcess(this); proc->setProgram("theterminal"); proc->setArguments({"-e", "/bin/bash"}); proc->setWorkingDirectory(QDir::rootPath()); proc->setProcessEnvironment(env); proc->start(); connect(proc, &QProcess::finished, this, [proc, this] { proc->deleteLater(); this->show(); }); }); } Onboarding::~Onboarding() { if (d->audioOutput) { d->audioOutput->stop(); d->audioOutput->deleteLater(); } delete d; delete ui; } void Onboarding::on_stackedWidget_currentChanged(int arg1) { if (d->steps.count() > arg1) d->steps.at(arg1).second->pageActivated(); } void Onboarding::on_bar_closeClicked() { StateManager::instance()->powerManager()->showPowerOffConfirmation(); } void Onboarding::resizeEvent(QResizeEvent* event) { if (this->geometry().width() <= SC_DPI(800)) { ui->contentWrapper->setFrameShape(QFrame::NoFrame); ui->stepperFrame->setVisible(false); ui->line->setVisible(false); } else if (this->geometry().width() < SC_DPI(1000)) { ui->contentWrapper->setFrameShape(QFrame::StyledPanel); ui->stepperFrame->setVisible(false); ui->line->setVisible(false); } else { ui->contentWrapper->setFrameShape(QFrame::StyledPanel); ui->stepperFrame->setVisible(true); ui->line->setVisible(true); } updateBarVisiblity(); } void Onboarding::paintEvent(QPaintEvent* event) { QPainter painter(this); QLinearGradient grad; grad.setStart(0, 0); grad.setFinalStop(0, d->bar->height() * 2); grad.setColorAt(0, QColor(0, 0, 0, 127)); grad.setColorAt(1, QColor(0, 0, 0, 0)); painter.setPen(Qt::transparent); painter.setBrush(grad); painter.drawRect(0, 0, this->width(), this->height()); int opacity = d->fadeAnim->currentValue().toInt(); if (opacity > 0) { QColor col = this->palette().color(QPalette::Window); col.setAlpha(opacity); painter.setBrush(col); painter.drawRect(0, 0, this->width(), this->height()); } } void Onboarding::startOnboarding() { if (ui->contentWrapper->isVisible()) return; this->setCursor(QCursor(Qt::ArrowCursor)); d->contentAnim->setStartValue(0); d->contentAnim->setEndValue(ui->contentWrapper->sizeHint().height()); QMetaObject::Connection* c = new QMetaObject::Connection(); *c = connect(d->contentAnim, &tVariantAnimation::finished, this, [=] { disconnect(*c); delete c; // Animate in the bar if (this->geometry().height() >= SC_DPI(600) + 2 * d->bar->height()) { QMetaObject::Connection* c = new QMetaObject::Connection(); *c = connect(d->barAnim, &tVariantAnimation::finished, this, [=] { disconnect(*c); delete c; d->onboardingStarted = true; updateBarVisiblity(); }); showBar(); } else { d->onboardingStarted = true; d->barVisible = true; updateBarVisiblity(); } d->bar->setVisible(true); }); d->contentAnim->start(); ui->contentWrapper->setVisible(true); } void Onboarding::writeAudio() { if (!d->audioEnabled) return; if (!d->audioOutputDevice) return; int bytesFree = d->audioOutput->bytesFree(); if (d->audioPointer < d->singleAudioData.length()) { QByteArray chunk = d->singleAudioData.mid(d->audioPointer, bytesFree); d->audioPointer += chunk.length(); bytesFree -= chunk.length(); d->audioOutputDevice->write(chunk); } // Prevent ourselves from locking up in this loop QDeadlineTimer lockTimer(50); while (bytesFree != 0 && d->audioPointer >= d->singleAudioData.length() && !lockTimer.hasExpired()) { if (d->audioPointer >= d->singleAudioData.length() + d->loopAudioData.length()) d->audioPointer -= d->loopAudioData.length(); QByteArray chunk = d->loopAudioData.mid(d->audioPointer - d->singleAudioData.length(), bytesFree); d->audioPointer += chunk.length(); bytesFree -= chunk.length(); d->audioOutputDevice->write(chunk); } // Disable the audio if (lockTimer.hasExpired()) { d->audioEnabled = false; } } void Onboarding::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); for (QPair stepper : d->steppers) { stepper.first->setText(stepper.second->displayName()); } } } void Onboarding::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Space) { if (!ui->contentWrapper->isVisible()) { // Skip the intro sequence startOnboarding(); event->accept(); } } else if (event->key() == Qt::Key_Escape) { StateManager::instance()->powerManager()->showPowerOffConfirmation(); event->accept(); } } bool Onboarding::eventFilter(QObject* watched, QEvent* event) { if (watched == d->bar) { if (event->type() == QEvent::Enter || event->type() == QEvent::Leave) { updateBarVisiblity(); } } return false; } void Onboarding::completeOnboarding() { d->contentAnim->setStartValue(ui->contentWrapper->sizeHint().height()); d->contentAnim->setEndValue(0); d->contentAnim->start(); // Animate out the bar QMetaObject::Connection* c = new QMetaObject::Connection(); *c = connect(d->barAnim, &tVariantAnimation::finished, this, [=] { disconnect(*c); delete c; StateManager::onboardingManager()->d->onboardingRunning = false; emit onboardingCompleted(true); this->accept(); }); hideBar(); // Fade out the music if (d->audioOutput) { tVariantAnimation* volAnim = new tVariantAnimation(this); volAnim->setStartValue(d->audioOutput->volume()); volAnim->setEndValue(0); volAnim->setEasingCurve(QEasingCurve::OutCubic); volAnim->setDuration(500); connect(volAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { d->audioOutput->setVolume(value.toInt()); }); connect(volAnim, &tVariantAnimation::finished, this, [=] { volAnim->deleteLater(); }); volAnim->start(); } // Fade out the background d->fadeAnim->start(); } void Onboarding::showBar() { if (d->barVisible) return; d->barAnim->setStartValue(-d->bar->height()); d->barAnim->setEndValue(0); d->barAnim->start(); d->barVisible = true; } void Onboarding::hideBar() { if (!d->barVisible) return; d->barAnim->setStartValue(0); d->barAnim->setEndValue(-d->bar->height()); d->barAnim->start(); d->barVisible = false; } void Onboarding::updateBarVisiblity() { if (d->onboardingStarted) { if (this->geometry().height() < SC_DPI(600) + 2 * d->bar->height()) { if (d->bar->underMouse()) { d->bar->move(0, d->barAnim->currentValue().toInt()); } else { d->bar->move(0, -d->bar->height() + 1); } d->bar->setAutoFillBackground(true); tScrim::scrimForWidget(this)->setBlurEnabled(true); } else { d->bar->move(0, d->barAnim->currentValue().toInt()); d->bar->setAutoFillBackground(false); tScrim::scrimForWidget(this)->setBlurEnabled(false); } } else { d->bar->move(0, -d->bar->height()); } d->bar->setFixedWidth(this->width()); d->bar->setFixedHeight(d->bar->height()); } ================================================ FILE: libthedesk/onboarding/onboarding.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDING_H #define ONBOARDING_H #include namespace Ui { class Onboarding; } struct OnboardingPrivate; class Onboarding : public QDialog { Q_OBJECT public: explicit Onboarding(QWidget* parent = nullptr); ~Onboarding(); void startOnboarding(); void writeAudio(); signals: void onboardingCompleted(bool complete); private slots: void on_stackedWidget_currentChanged(int arg1); void on_bar_closeClicked(); private: Ui::Onboarding* ui; OnboardingPrivate* d; void resizeEvent(QResizeEvent* event); void paintEvent(QPaintEvent* event); void changeEvent(QEvent* event); void keyPressEvent(QKeyEvent* event); bool eventFilter(QObject* watched, QEvent* event); void completeOnboarding(); void showBar(); void hideBar(); void updateBarVisiblity(); }; #endif // ONBOARDING_H ================================================ FILE: libthedesk/onboarding/onboarding.ui ================================================ Onboarding 0 0 723 519 Dialog 0 0 0 0 0 Qt::Vertical 20 40 true QFrame::StyledPanel 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 Qt::Vertical 20 40 1 16777215 Qt::Vertical Qt::Vertical 20 40 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
================================================ FILE: libthedesk/onboarding/onboardingbar.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingbar.h" #include "ui_onboardingbar.h" #include #include #include #include #include struct OnboardingBarPrivate { QGraphicsOpacityEffect* dateOpacity; }; OnboardingBar::OnboardingBar(QWidget* parent) : QWidget(parent), ui(new Ui::OnboardingBar) { ui->setupUi(this); d = new OnboardingBarPrivate(); d->dateOpacity = new QGraphicsOpacityEffect(); d->dateOpacity->setOpacity(StateManager::onboardingManager()->dateVisible() ? 1.0 : 0.0); ui->dateWidget->setGraphicsEffect(d->dateOpacity); QPalette pal = this->palette(); pal.setColor(QPalette::WindowText, Qt::white); this->setPalette(pal); DesktopTimeDate::makeTimeLabel(ui->clock, DesktopTimeDate::Time); DesktopTimeDate::makeTimeLabel(ui->date, DesktopTimeDate::StandardDate); connect(StateManager::onboardingManager(), &OnboardingManager::dateVisibleChanged, this, [ = ](bool dateVisible) { tVariantAnimation* anim = new tVariantAnimation(); anim->setStartValue(d->dateOpacity->opacity()); anim->setEndValue(dateVisible ? 1.0 : 0.0); anim->setDuration(500); anim->setEasingCurve(QEasingCurve::OutCubic); connect(anim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { d->dateOpacity->setOpacity(value.toReal()); }); connect(anim, &tVariantAnimation::finished, anim, &tVariantAnimation::deleteLater); anim->start(); }); } OnboardingBar::~OnboardingBar() { delete ui; } void OnboardingBar::on_closeButton_clicked() { emit closeClicked(); } void OnboardingBar::on_muteButton_toggled(bool checked) { emit muteToggled(checked); } ================================================ FILE: libthedesk/onboarding/onboardingbar.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGBAR_H #define ONBOARDINGBAR_H #include namespace Ui { class OnboardingBar; } struct OnboardingBarPrivate; class OnboardingBar : public QWidget { Q_OBJECT public: explicit OnboardingBar(QWidget* parent = nullptr); ~OnboardingBar(); private slots: void on_closeButton_clicked(); void on_muteButton_toggled(bool checked); signals: void closeClicked(); void muteToggled(bool mute); private: Ui::OnboardingBar* ui; OnboardingBarPrivate* d; }; #endif // ONBOARDINGBAR_H ================================================ FILE: libthedesk/onboarding/onboardingbar.ui ================================================ OnboardingBar 0 0 625 42 Form 0 0 0 0 0 0 0 0 0 0 6 9 9 9 9 15 75 true Clock Date Qt::Horizontal 516 20 0 0 .. true true 0 0 .. true ================================================ FILE: libthedesk/onboarding/onboardingbetathankyou.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingbetathankyou.h" #include "ui_onboardingbetathankyou.h" #include #include OnboardingBetaThankYou::OnboardingBetaThankYou(QWidget* parent) : OnboardingPage(parent), ui(new Ui::OnboardingBetaThankYou) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); } OnboardingBetaThankYou::~OnboardingBetaThankYou() { delete ui; } void OnboardingBetaThankYou::on_titleLabel_backButtonClicked() { StateManager::onboardingManager()->previousStep(); } QString OnboardingBetaThankYou::name() { return "OnboardingBetaThankYou"; } QString OnboardingBetaThankYou::displayName() { return tr("A Message"); } void OnboardingBetaThankYou::on_nextButton_clicked() { StateManager::onboardingManager()->nextStep(); } ================================================ FILE: libthedesk/onboarding/onboardingbetathankyou.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGBETATHANKYOU_H #define ONBOARDINGBETATHANKYOU_H #include namespace Ui { class OnboardingBetaThankYou; } class OnboardingBetaThankYou : public OnboardingPage { Q_OBJECT public: explicit OnboardingBetaThankYou(QWidget* parent = nullptr); ~OnboardingBetaThankYou(); private slots: void on_titleLabel_backButtonClicked(); void on_nextButton_clicked(); private: Ui::OnboardingBetaThankYou* ui; // OnboardingPage interface public: QString name(); QString displayName(); }; #endif // ONBOARDINGBETATHANKYOU_H ================================================ FILE: libthedesk/onboarding/onboardingbetathankyou.ui ================================================ OnboardingBetaThankYou 0 0 400 300 Form 0 0 0 0 0 Thank you! Welcome to theDesk Beta 4! Before we continue, please bear in mind that this is a beta. Not everything will be working correctly, and you may experience some strange behaviour in some parts. As always, feedback is appreciated! If you've got any ideas for me, or if something seems a little strange, please let me know! Once again, thanks for giving theDesk a go! - Victor :) true 9 Qt::Vertical 20 40 16777215 1 Qt::Horizontal 6 9 9 9 9 Qt::Horizontal 40 20 Next .. tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: libthedesk/onboarding/onboardingcontroller.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingcontroller.h" #include "onboarding.h" #include "server/sessionserver.h" #include #include #include #include #include #include "onboardingfinal.h" #include "onboardingvideo.h" #include "onboardingwelcome.h" OnboardingController::OnboardingController(QObject* parent) : QObject(parent) { } bool OnboardingController::performOnboarding(bool isSystemOnboarding) { tSettings settings; if (settings.value("Onboarding/lastOnboarding").toInt() < 1) { OnboardingManager* manager = StateManager::onboardingManager(); manager->setIsSystemOnboarding(isSystemOnboarding); manager->addOnboardingStep(new OnboardingWelcome); manager->addOnboardingStep(new OnboardingFinal); emit manager->onboardingRequired(); Onboarding o; QList videoScreens; if (settings.value("Onboarding/onboardingVideo").toBool()) { for (QScreen* screen : qApp->screens()) { OnboardingVideo* video = new OnboardingVideo(); video->setGeometry(screen->geometry()); video->showFullScreen(); videoScreens.append(video); } } o.setGeometry(qApp->primaryScreen()->geometry()); o.showFullScreen(); if (videoScreens.count() > 0) { connect(videoScreens.first(), &OnboardingVideo::startOnboarding, &o, &Onboarding::startOnboarding); connect(videoScreens.first(), &OnboardingVideo::playAudio, &o, &Onboarding::writeAudio); } // Hide the splashes if needed SessionServer::instance()->hideSplashes(); auto result = QCoro::waitFor(qCoro(&o, &Onboarding::onboardingCompleted)); for (OnboardingVideo* video : videoScreens) { video->close(); video->deleteLater(); } if (result) { // Show the splashes again SessionServer::instance()->showSplashes(); // Set the onboarding flag settings.setValue("Onboarding/lastOnboarding", 1); settings.sync(); return true; } else { return false; } } return true; } ================================================ FILE: libthedesk/onboarding/onboardingcontroller.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGCONTROLLER_H #define ONBOARDINGCONTROLLER_H #include class OnboardingController : public QObject { Q_OBJECT public: explicit OnboardingController(QObject* parent = nullptr); static bool performOnboarding(bool isSystemOnboarding); signals: }; #endif // ONBOARDINGCONTROLLER_H ================================================ FILE: libthedesk/onboarding/onboardingfinal.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingfinal.h" #include "ui_onboardingfinal.h" #include #include OnboardingFinal::OnboardingFinal(QWidget* parent) : OnboardingPage(parent), ui(new Ui::OnboardingFinal) { ui->setupUi(this); } OnboardingFinal::~OnboardingFinal() { delete ui; } void OnboardingFinal::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } QString OnboardingFinal::name() { return "OnboardingFinal"; } QString OnboardingFinal::displayName() { return tr("Done"); } void OnboardingFinal::on_finishButton_clicked() { StateManager::onboardingManager()->nextStep(); } ================================================ FILE: libthedesk/onboarding/onboardingfinal.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGFINAL_H #define ONBOARDINGFINAL_H #include namespace Ui { class OnboardingFinal; } class OnboardingFinal : public OnboardingPage { Q_OBJECT public: explicit OnboardingFinal(QWidget* parent = nullptr); ~OnboardingFinal(); private: Ui::OnboardingFinal* ui; void changeEvent(QEvent* event); // OnboardingPage interface public: QString name(); QString displayName(); private slots: void on_finishButton_clicked(); }; #endif // ONBOARDINGFINAL_H ================================================ FILE: libthedesk/onboarding/onboardingfinal.ui ================================================ OnboardingFinal 0 0 642 439 Form 0 0 0 0 Qt::Vertical 20 40 15 That's everything! Qt::AlignCenter :/thedesk/desktop/icons/cactus.svg Qt::AlignCenter We hope you enjoy using theDesk! Qt::AlignCenter Qt::Horizontal 40 20 Get Started Qt::Horizontal 40 20 Qt::Vertical 20 40 ================================================ FILE: libthedesk/onboarding/onboardingstepper.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingstepper.h" #include #include #include struct OnboardingStepperPrivate { QString text; int step = 1; int currentStep = 1; bool isFinal = false; }; OnboardingStepper::OnboardingStepper(QWidget* parent) : QWidget(parent) { d = new OnboardingStepperPrivate(); QFont fnt = this->font(); fnt.setPointSize(13); this->setFont(fnt); } OnboardingStepper::~OnboardingStepper() { delete d; } void OnboardingStepper::setText(QString text) { d->text = text; this->update(); } void OnboardingStepper::setStep(int step) { d->step = step; this->update(); } void OnboardingStepper::setCurrentStep(int step) { d->currentStep = step; this->update(); } void OnboardingStepper::setIsFinal(bool isFinal) { d->isFinal = isFinal; this->update(); } QSize OnboardingStepper::sizeHint() const { return QSize(300, this->fontMetrics().height() + 18); } void OnboardingStepper::paintEvent(QPaintEvent* event) { QPainter* painter = new QPainter(this); painter->setRenderHint(QPainter::Antialiasing); tPaintCalculator calculator; calculator.setPainter(painter); calculator.setDrawBounds(this->size()); calculator.setLayoutDirection(this->layoutDirection()); QPalette::ColorGroup group = d->currentStep < d->step ? QPalette::Disabled : QPalette::Normal; int radius = this->height() - SC_DPI(5); QRect circleRect; circleRect.setSize(QSize(radius, radius)); circleRect.moveLeft(SC_DPI(9)); circleRect.moveTop(this->height() / 2 - radius / 2); calculator.addRect(circleRect, [=](QRectF drawBounds) { painter->setPen(Qt::transparent); painter->setBrush(this->palette().color(group, QPalette::WindowText)); painter->drawEllipse(drawBounds); painter->setPen(this->palette().color(group, QPalette::Window)); painter->drawText(drawBounds, Qt::AlignCenter, QLocale().toString(d->step)); }); QRect textRect; textRect.setWidth(this->fontMetrics().horizontalAdvance(d->text)); textRect.setHeight(this->fontMetrics().height()); textRect.moveLeft(circleRect.right() + SC_DPI(9)); textRect.moveTop(this->height() / 2 - textRect.height() / 2); calculator.addRect(textRect, [=](QRectF drawBounds) { painter->setPen(this->palette().color(group, QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeft, d->text); }); if (d->step != 1) { calculator.addRect(circleRect, [=](QRectF drawBounds) { painter->drawLine(drawBounds.center().x(), 0, drawBounds.center().x(), drawBounds.top()); }); } if (!d->isFinal) { calculator.addRect(circleRect, [=](QRectF drawBounds) { painter->drawLine(drawBounds.center().x(), drawBounds.bottom(), drawBounds.center().x(), this->height()); }); } calculator.performPaint(); delete painter; } ================================================ FILE: libthedesk/onboarding/onboardingstepper.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGSTEPPER_H #define ONBOARDINGSTEPPER_H #include struct OnboardingStepperPrivate; class OnboardingStepper : public QWidget { Q_OBJECT public: explicit OnboardingStepper(QWidget* parent = nullptr); ~OnboardingStepper(); void setText(QString text); void setStep(int step); void setCurrentStep(int step); void setIsFinal(bool isFinal); QSize sizeHint() const; signals: private: OnboardingStepperPrivate* d; void paintEvent(QPaintEvent* event); }; #endif // ONBOARDINGSTEPPER_H ================================================ FILE: libthedesk/onboarding/onboardingvideo.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingvideo.h" #include "ui_onboardingvideo.h" #include #include #include #include #include #include #include struct OnboardingVideoPrivate { QMediaPlayer* videoPlayer; QPixmap pixmap; }; OnboardingVideo::OnboardingVideo(QWidget* parent) : QDialog(parent), ui(new Ui::OnboardingVideo) { ui->setupUi(this); d = new OnboardingVideoPrivate(); this->setCursor(QCursor(Qt::BlankCursor)); this->setWindowFlag(Qt::FramelessWindowHint); this->setWindowFlag(Qt::WindowStaysOnBottomHint); ui->videoWidget->setAspectRatioMode(Qt::KeepAspectRatioByExpanding); tSettings settings; auto startPlayer = mediaPlayerForFile(settings.value("Onboarding/videos.start").toString()); auto middlePlayer = mediaPlayerForFile(settings.value("Onboarding/videos.middle").toString()); auto loopPlayer = mediaPlayerForFile(settings.value("Onboarding/videos.loop").toString()); startPlayer->setVideoOutput(ui->videoWidget); connect(startPlayer, &QMediaPlayer::mediaStatusChanged, this, [this, middlePlayer](QMediaPlayer::MediaStatus state) { if (state == QMediaPlayer::BufferedMedia || state == QMediaPlayer::BufferingMedia) { emit playAudio(); } else if (state == QMediaPlayer::EndOfMedia) { middlePlayer->play(); middlePlayer->setVideoOutput(ui->videoWidget); QTimer::singleShot(0, this, &OnboardingVideo::startOnboarding); } }); connect(middlePlayer, &QMediaPlayer::mediaStatusChanged, this, [this, loopPlayer](QMediaPlayer::MediaStatus state) { if (state == QMediaPlayer::EndOfMedia) { loopPlayer->play(); loopPlayer->setVideoOutput(ui->videoWidget); } }); loopPlayer->setLoops(QMediaPlayer::Infinite); QVideoFrame::PaintOptions framePaintOptions; framePaintOptions.aspectRatioMode = Qt::KeepAspectRatioByExpanding; framePaintOptions.backgroundColor = Qt::black; startPlayer->play(); } OnboardingVideo::~OnboardingVideo() { delete d; delete ui; } QMediaPlayer* OnboardingVideo::mediaObject() const { return d->videoPlayer; } QMediaPlayer* OnboardingVideo::mediaPlayerForFile(QString file) { auto player = new QMediaPlayer(this); player->setSource(QUrl::fromLocalFile(file)); return player; } ================================================ FILE: libthedesk/onboarding/onboardingvideo.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGVIDEO_H #define ONBOARDINGVIDEO_H #include #include namespace Ui { class OnboardingVideo; } struct OnboardingVideoPrivate; class OnboardingVideo : public QDialog { Q_OBJECT Q_PROPERTY(QMediaPlayer* mediaObject READ mediaObject NOTIFY mediaObjectChanged) public: explicit OnboardingVideo(QWidget* parent = nullptr); ~OnboardingVideo(); QMediaPlayer* mediaObject() const; signals: void startOnboarding(); void mediaObjectChanged(); void playAudio(); private: Ui::OnboardingVideo* ui; OnboardingVideoPrivate* d; QMediaPlayer* mediaPlayerForFile(QString file); }; #endif // ONBOARDINGVIDEO_H ================================================ FILE: libthedesk/onboarding/onboardingvideo.ui ================================================ OnboardingVideo 0 0 400 300 Dialog 0 0 0 0 0 QVideoWidget QWidget
qvideowidget.h
1
================================================ FILE: libthedesk/onboarding/onboardingwelcome.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingwelcome.h" #include "ui_onboardingwelcome.h" #include #include #include #include #include #include #include #include struct OnboardingWelcomePrivate { tSettings settings; QSvgRenderer backgroundRenderer; QDBusInterface* hostnamed; }; OnboardingWelcome::OnboardingWelcome(QWidget* parent) : OnboardingPage(parent), ui(new Ui::OnboardingWelcome) { ui->setupUi(this); d = new OnboardingWelcomePrivate(); d->backgroundRenderer.load(d->settings.value("Onboarding/welcomeGraphic").toString()); ui->emergencyButton->setVisible(false); connect(DesktopWm::instance(), &DesktopWm::currentKeyboardLayoutChanged, this, [ = ] { ui->keyboardButton->setText(DesktopWm::currentKeyboardLayout()); }); ui->keyboardButton->setText(DesktopWm::currentKeyboardLayout()); d->hostnamed = new QDBusInterface("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", QDBusConnection::systemBus(), this); if (StateManager::onboardingManager()->isSystemOnboarding()) { ui->titleLabel->setText(tr("Welcome to %1!").arg(d->hostnamed->property("OperatingSystemPrettyName").toString())); ui->descriptionLabel->setText(tr("You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running.")); } else { ui->titleLabel->setText(tr("Welcome to %1!").arg(QApplication::applicationName())); ui->descriptionLabel->setText(tr("Just a bit of important setup to do before you get started. This won't take long!")); } QPalette pal = this->palette(); pal.setColor(QPalette::WindowText, Qt::white); this->setPalette(pal); } OnboardingWelcome::~OnboardingWelcome() { delete d; delete ui; } void OnboardingWelcome::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } QString OnboardingWelcome::name() { return "OnboardingWelcome"; } QString OnboardingWelcome::displayName() { return tr("Welcome"); } void OnboardingWelcome::on_nextButton_clicked() { StateManager::onboardingManager()->nextStep(); } void OnboardingWelcome::on_languageButton_clicked() { LocaleManager* manager = StateManager::localeManager(); bool ok; QLocale locale = manager->showLocaleSelector(this->window(), &ok); if (ok) { if (manager->locales().contains(locale)) manager->removeLocale(locale); manager->prependLocale(locale); } } void OnboardingWelcome::on_keyboardButton_clicked() { bool ok; QString newLayout = StateManager::localeManager()->showKeyboardLayoutSelector(this->window(), &ok); if (!ok) return; QStringList layouts = d->settings.delimitedList("Input/keyboard.layouts"); if (!layouts.contains(newLayout)) { layouts.append(newLayout); layouts.removeAll(""); d->settings.setDelimitedList("Input/keyboard.layouts", layouts); } DesktopWm::setCurrentKeyboardLayout(newLayout); } void OnboardingWelcome::paintEvent(QPaintEvent* event) { QPainter painter(this); d->backgroundRenderer.render(&painter); } ================================================ FILE: libthedesk/onboarding/onboardingwelcome.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGWELCOME_H #define ONBOARDINGWELCOME_H #include namespace Ui { class OnboardingWelcome; } struct OnboardingWelcomePrivate; class OnboardingWelcome : public OnboardingPage { Q_OBJECT public: explicit OnboardingWelcome(QWidget* parent = nullptr); ~OnboardingWelcome(); private: Ui::OnboardingWelcome* ui; OnboardingWelcomePrivate* d; void changeEvent(QEvent* event); // OnboardingPage interface public: QString name(); QString displayName(); private slots: void on_nextButton_clicked(); void on_languageButton_clicked(); void on_keyboardButton_clicked(); // QWidget interface protected: void paintEvent(QPaintEvent* event); }; #endif // ONBOARDINGWELCOME_H ================================================ FILE: libthedesk/onboarding/onboardingwelcome.ui ================================================ OnboardingWelcome 0 0 771 518 Form 340 20 20 20 20 Welcome! true Let's get you up and running! true Qt::Vertical 20 129 15 Let's go! .. 32 32 Qt::Horizontal 40 20 Qt::Vertical 20 40 true OTHER OPTIONS Language .. 32 32 Qt::ToolButtonTextUnderIcon true Keyboard 32 32 Qt::ToolButtonTextUnderIcon true false Emergency .. 32 32 Qt::ToolButtonTextUnderIcon true Qt::Horizontal 40 20 ================================================ FILE: libthedesk/onboardingmanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingmanager.h" #include "private/onboardingmanager_p.h" OnboardingManager::OnboardingManager(QObject* parent) : QObject(parent) { d = new OnboardingManagerPrivate(); } OnboardingManager::~OnboardingManager() { delete d; } void OnboardingManager::addOnboardingStep(OnboardingPage* onboardingStep) { d->steps.append(onboardingStep); } bool OnboardingManager::isOnboardingRunning() { return d->onboardingRunning; } void OnboardingManager::setDateVisible(bool dateVisible) { d->dateVisible = dateVisible; emit dateVisibleChanged(dateVisible); } bool OnboardingManager::dateVisible() { return d->dateVisible; } bool OnboardingManager::isSystemOnboarding() { return d->isSystemOnboarding; } QList OnboardingManager::onboardingSteps() { return d->steps; } void OnboardingManager::setIsSystemOnboarding(bool isSystemOnboarding) { d->isSystemOnboarding = isSystemOnboarding; } ================================================ FILE: libthedesk/onboardingmanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGMANAGER_H #define ONBOARDINGMANAGER_H #include class Onboarding; class OnboardingController; class OnboardingPage; struct OnboardingManagerPrivate; class OnboardingManager : public QObject { Q_OBJECT public: explicit OnboardingManager(QObject* parent = nullptr); ~OnboardingManager(); void addOnboardingStep(OnboardingPage* onboardingStep); bool isOnboardingRunning(); void setDateVisible(bool dateVisible); bool dateVisible(); bool isSystemOnboarding(); signals: void onboardingRequired(); //Call these functions to step forwards/backwards in the onboarding void nextStep(); void previousStep(); void dateVisibleChanged(bool dateVisible); protected: friend Onboarding; friend OnboardingController; OnboardingManagerPrivate* d; QList onboardingSteps(); void setIsSystemOnboarding(bool isSystemOnboarding); }; #endif // ONBOARDINGMANAGER_H ================================================ FILE: libthedesk/onboardingpage.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingpage.h" OnboardingPage::OnboardingPage(QWidget* parent) : QWidget(parent) { } void OnboardingPage::pageActivated() { //noop } ================================================ FILE: libthedesk/onboardingpage.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGPAGE_H #define ONBOARDINGPAGE_H #include class OnboardingPage : public QWidget { Q_OBJECT public: explicit OnboardingPage(QWidget* parent = nullptr); virtual QString name() = 0; virtual QString displayName() = 0; virtual void pageActivated(); signals: }; #endif // ONBOARDINGPAGE_H ================================================ FILE: libthedesk/plugins/plugininterface.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGININTERFACE_H #define PLUGININTERFACE_H #include class PluginInterface { public: virtual ~PluginInterface() {} virtual void activate() = 0; virtual void deactivate() = 0; }; #define PluginInterface_iid "com.vicr123.thedesk.PluginInterface/1.0" Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid); #endif // PLUGININTERFACE_H ================================================ FILE: libthedesk/plugins/pluginmanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "pluginmanager.h" #include #include #include #include #include #include #include #include #include "plugininterface.h" typedef QSharedPointer QPluginLoaderPtr; struct PluginManagerPrivate { PluginManager* instance = nullptr; QList loadedPlugins; QList erroredPlugins; QMap foundPlugins; tSettings* settings; QList blacklistedPlugins; bool safeMode = false; }; PluginManagerPrivate* PluginManager::d = new PluginManagerPrivate(); PluginManager* PluginManager::instance() { if (!d->instance) d->instance = new PluginManager(); return d->instance; } void PluginManager::setSafeMode(bool safeMode) { d->safeMode = safeMode; } bool PluginManager::isSafeMode() { return d->safeMode; } void PluginManager::scanPlugins() { //Load all available plugins QStringList searchPaths = { QDir::cleanPath(qApp->applicationDirPath() + "/../plugins"), QString(SYSTEM_LIBRARY_DIRECTORY).append("/thedesk/plugins") }; QStringList seenUuids; for (QString searchPath : searchPaths) { QDirIterator iterator(searchPath, {"*.so"}, QDir::NoFilter, QDirIterator::Subdirectories); while (iterator.hasNext()) { QPluginLoaderPtr loader(new QPluginLoader(iterator.next())); QJsonObject metadata = loader->metaData().value("MetaData").toObject(); if (metadata.isEmpty()) continue; QUuid uuid = QUuid::fromString(metadata.value("uuid").toString()); if (d->foundPlugins.contains(uuid)) continue; //Register this plugin d->foundPlugins.insert(uuid, loader); if (!d->safeMode) { //Load this plugin this->activatePlugin(uuid); } } } } void PluginManager::activatePlugin(QUuid uuid) { if (!d->foundPlugins.contains(uuid)) return; if (d->blacklistedPlugins.contains(uuid)) return; QPluginLoaderPtr loader = d->foundPlugins.value(uuid); d->erroredPlugins.removeAll(uuid); if (!loader->load()) { //Error! d->erroredPlugins.append(uuid); emit pluginsChanged(); return; } PluginInterface* instance = qobject_cast(loader->instance()); if (!instance) { //Error! loader->unload(); emit pluginsChanged(); return; } instance->activate(); d->loadedPlugins.append(uuid); emit pluginsChanged(); } void PluginManager::deactivatePlugin(QUuid uuid) { if (!d->loadedPlugins.contains(uuid)) return; QPluginLoaderPtr loader = d->foundPlugins.value(uuid); PluginInterface* instance = qobject_cast(loader->instance()); instance->deactivate(); loader->unload(); d->loadedPlugins.removeOne(uuid); emit pluginsChanged(); } void PluginManager::blacklistPlugin(QUuid uuid) { if (d->blacklistedPlugins.contains(uuid)) return; d->blacklistedPlugins.append(uuid); QStringList blacklisted; for (QUuid uuid : d->blacklistedPlugins) { blacklisted.append(uuid.toString()); } d->settings->setDelimitedList("Plugins/blacklist", blacklisted); d->settings->sync(); //Deactivate the plugin after we add it to the blacklist in case the plugin is having problems deactivating //At least if we crash, the plugin will be deactivated if (d->loadedPlugins.contains(uuid)) deactivatePlugin(uuid); } void PluginManager::removeBlacklistPlugin(QUuid uuid) { if (!d->blacklistedPlugins.contains(uuid)) return; d->blacklistedPlugins.removeAll(uuid); QStringList blacklisted; for (QUuid uuid : d->blacklistedPlugins) { blacklisted.append(uuid.toString()); } d->settings->setDelimitedList("Plugins/blacklist", blacklisted); d->settings->sync(); } QList PluginManager::availablePlugins() { return d->foundPlugins.keys(); } QList PluginManager::loadedPlugins() { return d->loadedPlugins; } QList PluginManager::erroredPlugins() { return d->erroredPlugins; } QList PluginManager::blacklistedPlugins() { return d->blacklistedPlugins; } QJsonValue PluginManager::pluginMetadata(QUuid plugin, QString key) { QPluginLoaderPtr loader = d->foundPlugins.value(plugin); QJsonObject metadata = loader->metaData().value("MetaData").toObject(); QLocale locale; QStringList languages = locale.uiLanguages(); languages.append(""); for (QString language : languages) { QJsonValue root = metadata; if (!language.isEmpty()) { root = metadata.value(language); } bool success = true; QStringList parts = key.split("."); for (QString part : parts) { if (root.isObject()) { root = root.toObject().value(part); } else { success = false; } } if (success) return root; } return QJsonValue(); } QString PluginManager::pluginErrorReason(QUuid plugin) { QPluginLoaderPtr loader = d->foundPlugins.value(plugin); return loader->errorString(); } PluginManager::PluginManager(QObject* parent) : QObject(parent) { d->settings = new tSettings(); //Find out which plugins are blacklisted connect(d->settings, &tSettings::settingChanged, this, [ = ](QString key) { if (key == "Plugins/blacklist") updateBlacklistedPlugins(); }); updateBlacklistedPlugins(); } void PluginManager::updateBlacklistedPlugins() { d->blacklistedPlugins.clear(); for (QString plugin : d->settings->delimitedList("Plugins/blacklist")) { d->blacklistedPlugins.append(QUuid::fromString(plugin)); } emit pluginsChanged(); } ================================================ FILE: libthedesk/plugins/pluginmanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGINMANAGER_H #define PLUGINMANAGER_H #include struct PluginManagerPrivate; class PluginManager : public QObject { Q_OBJECT public: static PluginManager* instance(); void setSafeMode(bool safeMode); bool isSafeMode(); void scanPlugins(); void activatePlugin(QUuid uuid); void deactivatePlugin(QUuid uuid); void blacklistPlugin(QUuid uuid); void removeBlacklistPlugin(QUuid uuid); QList availablePlugins(); QList loadedPlugins(); QList erroredPlugins(); QList blacklistedPlugins(); QJsonValue pluginMetadata(QUuid plugin, QString key); QString pluginErrorReason(QUuid plugin); signals: void pluginsChanged(); private: explicit PluginManager(QObject* parent = nullptr); static PluginManagerPrivate* d; void updateBlacklistedPlugins(); }; #endif // PLUGINMANAGER_H ================================================ FILE: libthedesk/powermanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "powermanager.h" #include #include #include #include #include #include #include "keygrab.h" #include #include #include #include "onboardingmanager.h" #include "statemanager.h" struct PowerManagerPrivate { QPointer lockScreenProcess; QDBusInterface* logindInterface; }; PowerManager::PowerManager(QObject* parent) : QObject(parent) { d = new PowerManagerPrivate(); connect(new KeyGrab(QKeySequence(Qt::Key_L | Qt::MetaModifier), "lockScreen"), &KeyGrab::activated, this, [=] { this->performPowerOperation(PowerManager::Lock); }); // Find this session ID d->logindInterface = new QDBusInterface("org.freedesktop.login1", "/org/freedesktop/login1/session/self", "org.freedesktop.login1.Session", QDBusConnection::systemBus(), this); QString id = d->logindInterface->property("Id").toString(); if (!id.isEmpty()) { QDBusMessage sessionRequest = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "GetSession"); sessionRequest.setArguments({id}); QDBusMessage sessionReply = QDBusConnection::systemBus().call(sessionRequest); if (sessionReply.type() == QDBusMessage::ReplyMessage) { // Register event handlers for logind QDBusObjectPath path = sessionReply.arguments().first().value(); QDBusConnection::systemBus().connect("org.freedesktop.login1", path.path(), "org.freedesktop.login1.Session", "Lock", this, SLOT(logindRequestLock())); QDBusConnection::systemBus().connect("org.freedesktop.login1", path.path(), "org.freedesktop.login1.Session", "Unlock", this, SLOT(logindRequestUnlock())); } } } PowerManager::~PowerManager() { delete d; } tPromise* PowerManager::showPowerOffConfirmation(PowerManager::PowerOperation operation, QString message, QStringList flags) { return tPromise::runOnSameThread([=](tPromiseFunctions::SuccessFunction res, tPromiseFunctions::FailureFunction rej) { Q_UNUSED(rej) emit powerOffConfirmationRequested(operation, message, flags, res); }); } void PowerManager::logindRequestLock() { this->performPowerOperation(Lock); } void PowerManager::logindRequestUnlock() { if (d->lockScreenProcess) d->lockScreenProcess->terminate(); // Process will be automatically deleted } void PowerManager::performPowerOperation(PowerManager::PowerOperation operation, QStringList flags) { emit powerOffOperationCommencing(operation); switch (operation) { case PowerManager::PowerOff: case PowerManager::Reboot: case PowerManager::Suspend: case PowerManager::Hibernate: { QMap methods = { {PowerManager::PowerOff, "PowerOff" }, {PowerManager::Reboot, "Reboot" }, {PowerManager::Suspend, "Suspend" }, {PowerManager::Hibernate, "Hibernate"} }; if (flags.contains("update")) { // Ask PackageKit to prepare for updates QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.PackageKit", "/org/freedesktop/PackageKit", "org.freedesktop.PackageKit.Offline", "Trigger"); message.setArguments({operation == PowerManager::Reboot ? "reboot" : "shutdown"}); QDBusMessage msg = QDBusConnection::systemBus().call(message); // Fall through } if (flags.contains("setup")) { QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "SetRebootToFirmwareSetup"); message.setArguments({true}); QDBusMessage msg = QDBusConnection::systemBus().call(message); // Fall through } QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", methods.value(operation)); message.setArguments({true}); QDBusConnection::systemBus().call(message); break; } case PowerManager::LogOut: // Quit theDesk qApp->exit(); break; case PowerManager::Lock: // Lock the screen if (d->lockScreenProcess) return; // Screen is already locked if (StateManager::onboardingManager()->isOnboardingRunning()) return; // Onboarding is currently running d->lockScreenProcess = new QProcess(); connect(d->lockScreenProcess, QOverload::of(&QProcess::finished), this, [this] { // Tell logind that we're not locked d->logindInterface->asyncCall("SetLockedHint", false); d->lockScreenProcess->deleteLater(); }); connect(d->lockScreenProcess, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) { if (error == QProcess::FailedToStart) { // Send a notification auto notification = new tNotification(); notification->setSummary(tr("Unable to lock screen")); notification->setText(tr("Sorry, the screen lock was unable to be started.")); notification->post(); // Tell logind that we're not locked d->logindInterface->asyncCall("SetLockedHint", false); d->lockScreenProcess->deleteLater(); } }); // TODO: Don't hardcode! d->lockScreenProcess->start("/usr/lib/td-locker", QStringList()); // Lock Screen // Tell logind that we're locked d->logindInterface->asyncCall("SetLockedHint", true); break; case PowerManager::SwitchUsers: { QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.DisplayManager", qEnvironmentVariable("XDG_SEAT_PATH"), "org.freedesktop.DisplayManager.Seat", "SwitchToGreeter"); QDBusConnection::systemBus().call(message); break; } case PowerManager::TurnOffScreen: DesktopWm::setScreenOff(true); break; case PowerManager::All: // Doesn't make sense ??? break; } } ================================================ FILE: libthedesk/powermanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef POWERMANAGER_H #define POWERMANAGER_H #include #include class EndSession; class EventHandler; class SleepMonitor; struct PowerManagerPrivate; class PowerManager : public QObject { Q_OBJECT public: enum PowerOperation { PowerOff, Reboot, LogOut, Suspend, Lock, TurnOffScreen, SwitchUsers, Hibernate, All }; explicit PowerManager(QObject* parent = nullptr); ~PowerManager(); tPromise* showPowerOffConfirmation(PowerOperation operation = All, QString message = "", QStringList flags = {}); private slots: void logindRequestLock(); void logindRequestUnlock(); signals: void powerOffConfirmationRequested(PowerOperation operation, QString message, QStringList flags, tPromiseFunctions::SuccessFunction cb); void powerOffOperationCommencing(PowerOperation operation); protected: friend EndSession; friend EventHandler; friend SleepMonitor; void performPowerOperation(PowerOperation operation, QStringList flags = {}); private: PowerManagerPrivate* d; }; #endif // POWERMANAGER_H ================================================ FILE: libthedesk/private/keyboardlayoutmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "keyboardlayoutmodel.h" #include struct KeyboardLayoutModelPrivate { QStringList layouts; }; KeyboardLayoutModel::KeyboardLayoutModel(QObject* parent) : QAbstractListModel(parent) { d = new KeyboardLayoutModelPrivate(); d->layouts = DesktopWm::availableKeyboardLayouts(); std::sort(d->layouts.begin(), d->layouts.end(), [ = ](const QString & first, const QString & second) { return DesktopWm::keyboardLayoutDescription(first).localeAwareCompare(DesktopWm::keyboardLayoutDescription(second)) < 0; }); } KeyboardLayoutModel::~KeyboardLayoutModel() { delete d; } int KeyboardLayoutModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return d->layouts.length(); } QVariant KeyboardLayoutModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); QString layout = d->layouts.at(index.row()); switch (role) { case Qt::DisplayRole: return DesktopWm::keyboardLayoutDescription(layout); case Qt::UserRole: return layout; } return QVariant(); } ================================================ FILE: libthedesk/private/keyboardlayoutmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYBOARDLAYOUTMODEL_H #define KEYBOARDLAYOUTMODEL_H #include struct KeyboardLayoutModelPrivate; class KeyboardLayoutModel : public QAbstractListModel { Q_OBJECT public: explicit KeyboardLayoutModel(QObject* parent = nullptr); ~KeyboardLayoutModel(); // Basic functionality: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; private: KeyboardLayoutModelPrivate* d; }; #endif // KEYBOARDLAYOUTMODEL_H ================================================ FILE: libthedesk/private/keyboardlayoutselector.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "keyboardlayoutselector.h" #include "ui_keyboardlayoutselector.h" #include "keyboardlayoutmodel.h" struct KeyboardLayoutSelectorPrivate { KeyboardLayoutModel* model; }; KeyboardLayoutSelector::KeyboardLayoutSelector(QWidget* parent) : QWidget(parent), ui(new Ui::KeyboardLayoutSelector) { ui->setupUi(this); d = new KeyboardLayoutSelectorPrivate(); ui->titleLabel->setBackButtonShown(true); d->model = new KeyboardLayoutModel(this); ui->keyboardLayoutSelection->setModel(d->model); } KeyboardLayoutSelector::~KeyboardLayoutSelector() { delete ui; delete d; } void KeyboardLayoutSelector::on_keyboardLayoutSelection_activated(const QModelIndex& index) { emit accepted(index.data(Qt::UserRole).toString()); } void KeyboardLayoutSelector::on_titleLabel_backButtonClicked() { emit rejected(); } ================================================ FILE: libthedesk/private/keyboardlayoutselector.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYBOARDLAYOUTSELECTOR_H #define KEYBOARDLAYOUTSELECTOR_H #include namespace Ui { class KeyboardLayoutSelector; } struct KeyboardLayoutSelectorPrivate; class KeyboardLayoutSelector : public QWidget { Q_OBJECT public: explicit KeyboardLayoutSelector(QWidget* parent = nullptr); ~KeyboardLayoutSelector(); signals: void rejected(); void accepted(QString layout); private slots: void on_keyboardLayoutSelection_activated(const QModelIndex& index); void on_titleLabel_backButtonClicked(); private: Ui::KeyboardLayoutSelector* ui; KeyboardLayoutSelectorPrivate* d; }; #endif // KEYBOARDLAYOUTSELECTOR_H ================================================ FILE: libthedesk/private/keyboardlayoutselector.ui ================================================ KeyboardLayoutSelector 0 0 400 300 Form 0 0 0 0 0 Select a keyboard layout QFrame::NoFrame tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: libthedesk/private/localeselector.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "localeselector.h" #include "ui_localeselector.h" struct LocaleSelectorPrivate { QLocale::Language currentLanguage; }; LocaleSelector::LocaleSelector(QWidget* parent) : QWidget(parent), ui(new Ui::LocaleSelector) { ui->setupUi(this); d = new LocaleSelectorPrivate(); ui->titleLabel->setBackButtonShown(true); ui->languageTitle->setBackButtonShown(true); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); QList languages; for (int i = QLocale::C + 1; i < QLocale::LastLanguage; i++) { #if !QT_VERSION_CHECK(5, 15, 0) if (i == QLocale::UncodedLanguages) continue; #endif QLocale locale(static_cast(i)); if (locale.language() != i) continue; if (!locale.nativeLanguageName().isEmpty()) { QString text; QString native = locale.nativeLanguageName(); if (locale.language() == QLocale::English) { text = "English"; //Do not localise } else if (native.isEmpty()) { text = QLocale::languageToString(locale.language()); } else { text = QStringLiteral("%1 (%2)").arg(native).arg(QLocale::languageToString(locale.language())); } QListWidgetItem* item = new QListWidgetItem(); item->setText(text); item->setData(Qt::UserRole, i); languages.append(item); } } std::sort(languages.begin(), languages.end(), [ = ](const QListWidgetItem * first, const QListWidgetItem * second) { return first->text().localeAwareCompare(second->text()) < 0; }); for (QListWidgetItem* item : languages) { ui->languageSelection->addItem(item); } } LocaleSelector::~LocaleSelector() { delete d; delete ui; } void LocaleSelector::on_titleLabel_backButtonClicked() { emit rejected(); } void LocaleSelector::on_languageSelection_itemActivated(QListWidgetItem* item) { QLocale::Language lang = static_cast(item->data(Qt::UserRole).toInt()); d->currentLanguage = lang; QList countries = QLocale::countriesForLanguage(lang); if (countries.count() == 1) { emit accepted(QLocale(lang, countries.first())); } else { ui->localeSelection->clear(); for (QLocale::Country country : countries) { QLocale locale(lang, country); QListWidgetItem* item = new QListWidgetItem(); item->setText(QStringLiteral("%1 (%2)").arg(QLocale::countryToString(country)).arg(locale.nativeCountryName())); item->setData(Qt::UserRole, country); ui->localeSelection->addItem(item); } ui->languageTitle->setText(QLocale::languageToString(lang)); ui->stackedWidget->setCurrentWidget(ui->localePage); } } void LocaleSelector::on_localeSelection_itemActivated(QListWidgetItem* item) { QLocale::Country country = static_cast(item->data(Qt::UserRole).toInt()); emit accepted(QLocale(d->currentLanguage, country)); } void LocaleSelector::on_languageTitle_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->languagePage); } ================================================ FILE: libthedesk/private/localeselector.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef LOCALESELECTOR_H #define LOCALESELECTOR_H #include #include #include namespace Ui { class LocaleSelector; } struct LocaleSelectorPrivate; class LocaleSelector : public QWidget { Q_OBJECT public: explicit LocaleSelector(QWidget* parent = nullptr); ~LocaleSelector(); signals: void rejected(); void accepted(QLocale locale); private slots: void on_titleLabel_backButtonClicked(); void on_languageSelection_itemActivated(QListWidgetItem* item); void on_localeSelection_itemActivated(QListWidgetItem* item); void on_languageTitle_backButtonClicked(); private: Ui::LocaleSelector* ui; LocaleSelectorPrivate* d; }; #endif // LOCALESELECTOR_H ================================================ FILE: libthedesk/private/localeselector.ui ================================================ LocaleSelector 0 0 503 381 Form 0 0 0 0 0 0 0 0 0 0 0 Select a locale QFrame::NoFrame 0 0 0 0 0 Language Name QFrame::NoFrame tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
================================================ FILE: libthedesk/private/onboardingmanager_p.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGMANAGER_P_H #define ONBOARDINGMANAGER_P_H #include class OnboardingPage; struct OnboardingManagerPrivate { QList steps; bool onboardingRunning = false; bool dateVisible = true; bool isSystemOnboarding = false; }; #endif // ONBOARDINGMANAGER_P_H ================================================ FILE: libthedesk/private/quickwidgetcontainer.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "quickwidgetcontainer.h" #include "ui_quickwidgetcontainer.h" #include "chunk.h" #include #include #include #include #include #include #include #include #include struct QuickWidgetContainerPrivate { QWidget* parentChunk; QWidget* quickWidget; int pointX = 0; tVariantAnimation* yAnim; tVariantAnimation* opacityAnim; bool isShowing = false; BarManager::BarLockPtr barLock; }; QuickWidgetContainer::QuickWidgetContainer(QWidget* parent) : QWidget(parent), ui(new Ui::QuickWidgetContainer) { ui->setupUi(this); // this->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Popup); this->setWindowFlags(Qt::Popup); this->setAttribute(Qt::WA_TranslucentBackground); d = new QuickWidgetContainerPrivate(); d->parentChunk = parent; d->yAnim = new tVariantAnimation(this); d->yAnim->setEasingCurve(QEasingCurve::OutCubic); d->yAnim->setDuration(100); connect(d->yAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { this->move(this->x(), value.toInt()); }); d->opacityAnim = new tVariantAnimation(this); d->opacityAnim->setStartValue(0.0); d->opacityAnim->setEndValue(1.0); d->opacityAnim->setEasingCurve(QEasingCurve::OutCubic); d->opacityAnim->setDuration(100); connect(d->opacityAnim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { this->setWindowOpacity(value.toDouble()); }); connect(d->opacityAnim, &tVariantAnimation::finished, this, [=] { if (d->opacityAnim->direction() == tVariantAnimation::Backward) this->hide(); }); this->setWindowOpacity(0); this->setContentsMargins(1, 6, 1, 1); ui->chunkContainerLayout->installEventFilter(this); } QuickWidgetContainer::~QuickWidgetContainer() { delete ui; delete d; } QSize QuickWidgetContainer::sizeHint() const { QSize sizeHint; Chunk* chunk = qobject_cast(d->parentChunk); if (chunk) { sizeHint = chunk->quickWidget()->sizeHint(); } else { sizeHint = d->quickWidget->sizeHint(); } return sizeHint.grownBy(this->contentsMargins()); } void QuickWidgetContainer::showContainer() { Chunk* chunk = qobject_cast(d->parentChunk); if (chunk) { ui->chunkContainerLayout->addWidget(chunk->quickWidget()); chunk->quickWidget()->installEventFilter(this); } else { ui->chunkContainerLayout->addWidget(d->quickWidget); d->quickWidget->installEventFilter(this); } calculatePosition(); d->isShowing = true; this->show(); DesktopWm::setSystemWindow(this, DesktopWm::SystemWindowTypeSkipTaskbarOnly); this->activateWindow(); calculatePosition(); d->yAnim->setDirection(tVariantAnimation::Forward); d->opacityAnim->setDirection(tVariantAnimation::Forward); d->yAnim->start(); d->opacityAnim->start(); d->barLock = StateManager::barManager()->acquireLock(); emit showing(); } void QuickWidgetContainer::hideContainer() { d->yAnim->setDirection(tVariantAnimation::Backward); d->opacityAnim->setDirection(tVariantAnimation::Backward); d->yAnim->start(); d->opacityAnim->start(); d->isShowing = false; d->barLock->unlock(); emit hiding(); } bool QuickWidgetContainer::isShowing() { return d->isShowing; } void QuickWidgetContainer::setQuickWidget(QWidget* widget) { d->quickWidget = widget; } void QuickWidgetContainer::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.setPen(this->palette().color(QPalette::WindowText)); painter.setBrush(this->palette().color(QPalette::Window)); QPolygon poly; int topEdge = 5; int leftPoint = qMax(0, d->pointX - 5); int rightPoint = qMin(this->width() - 1, d->pointX + 5); poly.append(QPoint(0, topEdge)); poly.append(QPoint(leftPoint, topEdge)); poly.append(QPoint(d->pointX, 0)); poly.append(QPoint(rightPoint, topEdge)); poly.append(QPoint(this->width() - 1, topEdge)); poly.append(QPoint(this->width() - 1, this->height() - 1)); poly.append(QPoint(0, this->height() - 1)); poly.append(QPoint(0, topEdge)); painter.drawPolygon(poly); } void QuickWidgetContainer::changeEvent(QEvent* event) { QWidget::changeEvent(event); switch (event->type()) { case QEvent::ActivationChange: if (!this->isActiveWindow()) this->hideContainer(); break; default: break; } } void QuickWidgetContainer::calculatePosition() { this->setFixedSize(this->sizeHint()); QPoint midpoint = d->parentChunk->mapToGlobal(QPoint(d->parentChunk->width() / 2, d->parentChunk->height())); QRect screenGeometry = qApp->screenAt(midpoint)->geometry(); QRect geom = this->geometry(); geom.setSize(this->sizeHint()); geom.moveLeft(midpoint.x() - geom.width() / 2); if (geom.left() < screenGeometry.left() + 9) geom.moveLeft(screenGeometry.left() + 9); if (geom.right() > screenGeometry.right() - 9) geom.moveRight(screenGeometry.right() - 9); this->setGeometry(geom); d->pointX = this->mapFromGlobal(midpoint).x(); d->yAnim->setStartValue(midpoint.y() - 50); d->yAnim->setEndValue(midpoint.y()); } bool QuickWidgetContainer::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Resize || event->type() == QEvent::LayoutRequest) { QTimer::singleShot(0, this, &QuickWidgetContainer::calculatePosition); } return false; } void QuickWidgetContainer::hideEvent(QHideEvent* event) { if (d->isShowing) this->hideContainer(); } ================================================ FILE: libthedesk/private/quickwidgetcontainer.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef QUICKWIDGETCONTAINER_H #define QUICKWIDGETCONTAINER_H #include namespace Ui { class QuickWidgetContainer; } class Chunk; class CurrentAppWidget; class TaskbarApplicationWidget; struct QuickWidgetContainerPrivate; class QuickWidgetContainer : public QWidget { Q_OBJECT public: explicit QuickWidgetContainer(QWidget* parent = nullptr); ~QuickWidgetContainer(); QSize sizeHint() const; void showContainer(); void hideContainer(); bool isShowing(); signals: void showing(); void hiding(); protected: friend CurrentAppWidget; friend TaskbarApplicationWidget; void setQuickWidget(QWidget* widget); private: Ui::QuickWidgetContainer* ui; QuickWidgetContainerPrivate* d; void paintEvent(QPaintEvent* event); void changeEvent(QEvent* event); bool eventFilter(QObject* watched, QEvent* event); void calculatePosition(); // QWidget interface protected: void hideEvent(QHideEvent *event); }; #endif // QUICKWIDGETCONTAINER_H ================================================ FILE: libthedesk/private/quickwidgetcontainer.ui ================================================ QuickWidgetContainer 0 0 242 268 Form 0 0 0 0 0 ================================================ FILE: libthedesk/quickswitch.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "quickswitch.h" #include #include struct QuickSwitchPrivate { QString name; QString title; bool checked = false; QPointer s; }; QuickSwitch::QuickSwitch(QString name, QObject* parent) : QObject(parent) { d = new QuickSwitchPrivate(); d->name = name; } QuickSwitch::~QuickSwitch() { delete d; } QString QuickSwitch::name() { return d->name; } void QuickSwitch::setTitle(QString title) { if (d->title == title) return; d->title = title; emit titleChanged(title); } QString QuickSwitch::title() { return d->title; } void QuickSwitch::setChecked(bool isChecked) { if (d->checked == isChecked) return; d->checked = isChecked; emit toggled(isChecked); if (d->s) d->s->setChecked(isChecked); } bool QuickSwitch::isChecked() { return d->checked; } void QuickSwitch::setSwitch(tSwitch* s) { d->s = s; } ================================================ FILE: libthedesk/quickswitch.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BARSWITCH_H #define BARSWITCH_H #include struct QuickSwitchPrivate; class tSwitch; class QuickSwitch : public QObject { Q_OBJECT public: explicit QuickSwitch(QString name, QObject* parent = nullptr); ~QuickSwitch(); QString name(); void setTitle(QString title); QString title(); void setChecked(bool isChecked); bool isChecked(); void setSwitch(tSwitch* s); signals: void titleChanged(QString title); void toggled(bool checked); private: QuickSwitchPrivate* d; }; #endif // BARSWITCH_H ================================================ FILE: libthedesk/quietmodemanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "quietmodemanager.h" #include "statemanager.h" #include "onboardingmanager.h" struct QuietModeManagerPrivate { QuietModeManagerTd::QuietMode quietMode = QuietModeManagerTd::Sound; }; QuietModeManagerTd::QuietModeManagerTd(QObject* parent) : QObject(parent) { d = new QuietModeManagerPrivate(); } QuietModeManagerTd::~QuietModeManagerTd() { delete d; } void QuietModeManagerTd::setQuietMode(QuietModeManagerTd::QuietMode quietMode) { QuietModeManagerTd::QuietMode oldMode = d->quietMode; d->quietMode = quietMode; emit quietModeChanged(quietMode, oldMode); } QuietModeManagerTd::QuietMode QuietModeManagerTd::currentMode() { return d->quietMode; } QuietModeManagerTd::QuietMode QuietModeManagerTd::nextQuietMode() const { switch (d->quietMode) { case QuietModeManagerTd::Sound: //If we're in onboarding, mute the audio if the user hits mute return StateManager::onboardingManager()->isOnboardingRunning() ? Mute : CriticalOnly; case QuietModeManagerTd::CriticalOnly: //If we're in onboarding, mute the audio if the user hits mute return StateManager::onboardingManager()->isOnboardingRunning() ? Mute : NoNotifications; case QuietModeManagerTd::NoNotifications: return Mute; case QuietModeManagerTd::Mute: return Sound; default: return QuietModeManagerTd::Sound; } } QString QuietModeManagerTd::name(QuietModeManagerTd::QuietMode quietMode) { switch (quietMode) { case QuietModeManagerTd::Sound: return tr("Sound"); case QuietModeManagerTd::CriticalOnly: return tr("Critical Only"); case QuietModeManagerTd::NoNotifications: return tr("No Notifications"); case QuietModeManagerTd::Mute: return tr("Mute"); default: return ""; } } QString QuietModeManagerTd::description(QuietModeManagerTd::QuietMode quietMode) { switch (quietMode) { case QuietModeManagerTd::Sound: return tr("Allows all sounds"); case QuietModeManagerTd::CriticalOnly: return tr("Hides non-critical notifications"); case QuietModeManagerTd::NoNotifications: return tr("Hides all notifications"); case QuietModeManagerTd::Mute: return tr("Mutes all sound altogether"); default: return ""; } } QString QuietModeManagerTd::icon(QuietModeManagerTd::QuietMode quietMode) { switch (quietMode) { case QuietModeManagerTd::Sound: return "audio-volume-high"; case QuietModeManagerTd::CriticalOnly: return "quiet-mode-critical-only"; case QuietModeManagerTd::NoNotifications: return "quiet-mode"; case QuietModeManagerTd::Mute: return "audio-volume-muted"; default: return ""; } } QList QuietModeManagerTd::availableQuietModes() const { QList modes; for (QuietMode mode = Sound; mode != LastQuietMode; mode = static_cast(mode + 1)) { modes.append(mode); } return modes; } ================================================ FILE: libthedesk/quietmodemanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef QUIETMODEMANAGER_H #define QUIETMODEMANAGER_H #include struct QuietModeManagerPrivate; class QuietModeManagerTd : public QObject { Q_OBJECT public: enum QuietMode { Sound = 0, CriticalOnly, NoNotifications, Mute, LastQuietMode }; explicit QuietModeManagerTd(QObject* parent = nullptr); ~QuietModeManagerTd(); void setQuietMode(QuietMode quietMode); QuietMode currentMode(); QuietMode nextQuietMode() const; static QString name(QuietMode quietMode); static QString description(QuietMode quietMode); static QString icon(QuietMode quietMode); QList availableQuietModes() const; signals: void quietModeChanged(QuietMode newQuietMode, QuietMode oldQuietMode); private: QuietModeManagerPrivate* d; }; #endif // QUIETMODEMANAGER_H ================================================ FILE: libthedesk/server/sessionserver.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "sessionserver.h" #include #include #include #include #include struct SessionServerPrivate { QLocalSocket* socket; SessionServer* instance = nullptr; bool available = false; bool havePendingQuestion = false; tPromiseFunctions::SuccessFunction questionRes; }; SessionServerPrivate* SessionServer::d = new SessionServerPrivate(); SessionServer* SessionServer::instance() { if (!d->instance) d->instance = new SessionServer(); return d->instance; } void SessionServer::setServerPath(QString serverPath) { d->socket->connectToServer(serverPath); //Wait until connection so we can send messages d->socket->waitForConnected(); } void SessionServer::hideSplashes() { if (!d->available) return; d->socket->write(QJsonDocument(QJsonObject({ {"type", "hideSplash"} })).toJson()); d->socket->flush(); } void SessionServer::showSplashes() { if (!d->available) return; d->socket->write(QJsonDocument(QJsonObject({ {"type", "showSplash"} })).toJson()); d->socket->flush(); } void SessionServer::performAutostart() { if (!d->available) return; d->socket->write(QJsonDocument(QJsonObject({ {"type", "autoStart"} })).toJson()); d->socket->flush(); } tPromise* SessionServer::askQuestion(QString title, QString question) { return tPromise::runOnSameThread([ = ](tPromiseFunctions::SuccessFunction res, tPromiseFunctions::FailureFunction rej) { if (!d->available) { bool answer = QMessageBox::question(nullptr, title, question, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; res(answer); } else { d->questionRes = [ = ](bool result) { d->havePendingQuestion = false; res(result); }; d->havePendingQuestion = true; d->socket->write(QJsonDocument(QJsonObject({ {"type", "question"}, {"title", title}, {"question", question} })).toJson()); d->socket->flush(); } }); } SessionServer::SessionServer(QObject* parent) : QObject(parent) { d->socket = new QLocalSocket(); connect(d->socket, &QLocalSocket::connected, this, [ = ] { d->available = true; }); connect(d->socket, &QLocalSocket::disconnected, this, [ = ] { d->available = false; }); connect(d->socket, &QLocalSocket::readyRead, this, &SessionServer::readData); } void SessionServer::readData() { QByteArray data = d->socket->readAll(); QJsonDocument doc = QJsonDocument::fromJson(data); if (doc.isObject()) { QJsonObject obj = doc.object(); if (obj.contains("type")) { QString type = obj.value("type").toString(); if (type == "questionResponse" && d->havePendingQuestion) { d->questionRes(obj.value("response").toBool()); } } } } ================================================ FILE: libthedesk/server/sessionserver.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SESSIONSERVER_H #define SESSIONSERVER_H #include #include struct SessionServerPrivate; class SessionServer : public QObject { Q_OBJECT public: static SessionServer* instance(); void setServerPath(QString serverPath); void hideSplashes(); void showSplashes(); void performAutostart(); tPromise* askQuestion(QString title, QString question); signals: private: explicit SessionServer(QObject* parent = nullptr); static SessionServerPrivate* d; void readData(); }; #endif // SESSIONSERVER_H ================================================ FILE: libthedesk/statemanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "statemanager.h" #include "barmanager.h" #include "powermanager.h" #include "statuscentermanager.h" #include "localemanager.h" #include "hudmanager.h" #include "gatewaymanager.h" #include "onboardingmanager.h" #include "quietmodemanager.h" struct StateManagerPrivate { StateManager* instance = nullptr; BarManager* barManager; GatewayManager* gatewayManager; StatusCenterManager* statusCenterManager; PowerManager* powerManager; LocaleManager* localeManager; HudManager* hudManager; OnboardingManager* onboardingManager; QuietModeManagerTd* quietModeManager; }; StateManagerPrivate* StateManager::d = new StateManagerPrivate(); StateManager::StateManager() : QObject(nullptr) { d->barManager = new BarManager(this); d->gatewayManager = new GatewayManager(this); d->statusCenterManager = new StatusCenterManager(this); d->powerManager = new PowerManager(this); d->localeManager = new LocaleManager(this); d->hudManager = new HudManager(this); d->onboardingManager = new OnboardingManager(this); d->quietModeManager = new QuietModeManagerTd(this); } StateManager* StateManager::instance() { if (d->instance == nullptr) d->instance = new StateManager(); return d->instance; } BarManager* StateManager::barManager() { return d->barManager; } GatewayManager* StateManager::gatewayManager() { return d->gatewayManager; } PowerManager* StateManager::powerManager() { return d->powerManager; } StatusCenterManager* StateManager::statusCenterManager() { return d->statusCenterManager; } LocaleManager* StateManager::localeManager() { return d->localeManager; } HudManager* StateManager::hudManager() { return d->hudManager; } OnboardingManager* StateManager::onboardingManager() { return d->onboardingManager; } QuietModeManagerTd* StateManager::quietModeManager() { return d->quietModeManager; } ================================================ FILE: libthedesk/statemanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef STATEMANAGER_H #define STATEMANAGER_H #include "libthedesk_global.h" #include class BarManager; class GatewayManager; class PowerManager; class StatusCenterManager; class LocaleManager; class HudManager; class OnboardingManager; class QuietModeManagerTd; struct StateManagerPrivate; class LIBTHEDESK_EXPORT StateManager : public QObject { Q_OBJECT public: static StateManager* instance(); static BarManager* barManager(); static GatewayManager* gatewayManager(); static PowerManager* powerManager(); static StatusCenterManager* statusCenterManager(); static LocaleManager* localeManager(); static HudManager* hudManager(); static OnboardingManager* onboardingManager(); static QuietModeManagerTd* quietModeManager(); private: explicit StateManager(); static StateManagerPrivate* d; }; #endif // STATEMANAGER_H ================================================ FILE: libthedesk/statuscentermanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "statuscentermanager.h" #include #include struct StatusCenterManagerPrivate { bool isShowing = false; bool hamburgerMenuRequired = false; QList panes; QMap paneTypes; QList switches; }; StatusCenterManager::StatusCenterManager(QObject* parent) : QObject(parent) { d = new StatusCenterManagerPrivate(); } StatusCenterManager::~StatusCenterManager() { delete d; } void StatusCenterManager::show() { emit showStatusCenter(); } void StatusCenterManager::hide() { emit hideStatusCenter(); } bool StatusCenterManager::isShowingStatusCenter() { return d->isShowing; } bool StatusCenterManager::isHamburgerMenuRequired() { return d->hamburgerMenuRequired; } void StatusCenterManager::showStatusCenterHamburgerMenu() { emit showHamburgerMenu(); } void StatusCenterManager::hideStatusCenterHamburgerMenu() { emit hideHamburgerMenu(); } void StatusCenterManager::returnToRootMenu() { emit rootMenu(); } void StatusCenterManager::addPane(StatusCenterPane* pane, StatusCenterManager::PaneType type) { if (!d->panes.contains(pane)) { d->paneTypes.insert(pane, type); d->panes.append(pane); emit paneAdded(pane, type); } } void StatusCenterManager::removePane(StatusCenterPane* pane) { if (d->panes.contains(pane)) { d->paneTypes.remove(pane); d->panes.removeOne(pane); emit paneRemoved(pane); } } void StatusCenterManager::setPane(QString pane) { emit paneRequest(pane); } void StatusCenterManager::setPane(StatusCenterPane* pane) { emit paneRequest(pane); } void StatusCenterManager::showWithPane(QString pane) { setPane(pane); emit showStatusCenter(); } void StatusCenterManager::showWithPane(StatusCenterPane* pane) { setPane(pane); emit showStatusCenter(); } void StatusCenterManager::addSwitch(QuickSwitch* sw) { if (!d->switches.contains(sw)) { d->switches.append(sw); emit switchAdded(sw); } } void StatusCenterManager::removeSwitch(QuickSwitch* sw) { if (d->switches.contains(sw)) { d->switches.removeOne(sw); emit switchRemoved(sw); } } bool StatusCenterManager::isSwitchRegistered(QuickSwitch* sw) { return d->switches.contains(sw); } int StatusCenterManager::preferredContentWidth() { return SC_DPI(600); } QList StatusCenterManager::panes() { return d->panes; } QList StatusCenterManager::switches() { return d->switches; } StatusCenterManager::PaneType StatusCenterManager::paneType(StatusCenterPane* pane) { return d->paneTypes.value(pane); } void StatusCenterManager::setIsShowingStatusCenter(bool isShowing) { d->isShowing = isShowing; } void StatusCenterManager::setIsHamburgerMenuRequired(bool isRequired) { d->hamburgerMenuRequired = isRequired; emit isHamburgerMenuRequiredChanged(isRequired); } ================================================ FILE: libthedesk/statuscentermanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef STATUSCENTERMANAGER_H #define STATUSCENTERMANAGER_H #include class BarWindow; class StatusCenterPane; class StatusCenter; class SystemSettings; class QuickSwitch; struct StatusCenterManagerPrivate; class StatusCenterManager : public QObject { Q_OBJECT public: enum PaneType { Informational, SystemSettings }; explicit StatusCenterManager(QObject* parent = nullptr); ~StatusCenterManager(); void show(); void hide(); bool isShowingStatusCenter(); bool isHamburgerMenuRequired(); void showStatusCenterHamburgerMenu(); void hideStatusCenterHamburgerMenu(); void returnToRootMenu(); void addPane(StatusCenterPane* pane, PaneType type = Informational); void removePane(StatusCenterPane* pane); void setPane(QString pane); void setPane(StatusCenterPane* pane); void showWithPane(QString pane); void showWithPane(StatusCenterPane* pane); void addSwitch(QuickSwitch* sw); void removeSwitch(QuickSwitch* sw); bool isSwitchRegistered(QuickSwitch* sw); int preferredContentWidth(); signals: void showStatusCenter(); void hideStatusCenter(); void showHamburgerMenu(); void hideHamburgerMenu(); void rootMenu(); void requestLogout(); void paneAdded(StatusCenterPane* pane, StatusCenterManager::PaneType type); void paneRemoved(StatusCenterPane* pane); void switchAdded(QuickSwitch* sw); void switchRemoved(QuickSwitch* sw); void paneRequest(QString pane); void paneRequest(StatusCenterPane* pane); void isHamburgerMenuRequiredChanged(bool isHamburgerMenuRequired); protected: friend BarWindow; friend StatusCenter; friend class SystemSettings; void setIsShowingStatusCenter(bool isShowing); void setIsHamburgerMenuRequired(bool isRequired); QList panes(); QList switches(); PaneType paneType(StatusCenterPane* pane); private: StatusCenterManagerPrivate* d; }; #endif // STATUSCENTERMANAGER_H ================================================ FILE: libthedesk/statuscenterpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "statuscenterpane.h" StatusCenterPane::StatusCenterPane() : QWidget(nullptr) { } ================================================ FILE: libthedesk/statuscenterpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef STATUSCENTERPANE_H #define STATUSCENTERPANE_H #include class StatusCenterPane : public QWidget { Q_OBJECT public: enum PaneType { Informational, SystemSettings }; explicit StatusCenterPane(); virtual QString name() = 0; virtual QString displayName() = 0; virtual QIcon icon() = 0; virtual QWidget* leftPane() = 0; signals: void displayNameChanged(); void iconChanged(); }; #endif // STATUSCENTERPANE_H ================================================ FILE: libthedesk/translations/ar_SA.ts ================================================ KeyboardLayoutSelector Select a keyboard layout حدد تخطيط لوحة المفاتيح LocaleSelector Select a locale حدد لغة OnboardingFinal That's everything! هذا كل شئ! We hope you enjoy using theDesk! نأمل أن تستمتع باستخدام theDesk! Get Started ابدء Done تم OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language الغة Emergency طوارئ Let's go! هيا نذهب! Welcome مرحبا Welcome to %1! مرحباً بك في %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. لقد وصلت! سننتقل سريعًا إلى بعض الإعدادات المهمة مثل إعداد الحسابات والاتصال بالإنترنت ، وبعد ذلك ستكون جاهزاين للعمل. Just a bit of important setup to do before you get started. This won't take long! مجرد القليل من الإعداد المهم الذي يجب القيام به قبل العمل. هذا لن يأخذ وقت طويل! OTHER OPTIONS خيارات الأخرى QuietModeManagerTd Sound الصوت Critical Only المهمه فقط No Notifications لا توجد اي إشعارات Mute كتم الصوت Allows all sounds يسمح بكل الأصوات Hides non-critical notifications يخفي الإنظارات غير المهمه Hides all notifications يخفي كل الإنظارات Mutes all sound altogether يكتم كل الأصوات تمامًا ================================================ FILE: libthedesk/translations/au_AU.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/cs_CZ.ts ================================================  KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/cy.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/da.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/de.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/en_GB.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale Select a locale OnboardingFinal That's everything! That's everything! We hope you enjoy using theDesk! We hope you enjoy using theDesk! Get Started Get Started Done Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Language Emergency Emergency Let's go! Let's go! Welcome Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Sound Critical Only Critical Only No Notifications No Notifications Mute Mute Allows all sounds Allows all sounds Hides non-critical notifications Hides non-critical notifications Hides all notifications Hides all notifications Mutes all sound altogether Mutes all sound altogether ================================================ FILE: libthedesk/translations/en_US.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale Choose a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/es.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! Eso es todo! We hope you enjoy using theDesk! Te esperamos disfrutar usando theDesk! Get Started Done Hecho OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Idioma Emergency Emergencia Let's go! Vamos! Welcome Bienvenido Welcome to %1! Bienvenido a %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS OTRAS OPCIONES QuietModeManagerTd Sound Sonido Critical Only No Notifications No Notificaciones Mute Silencio Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/es_VE.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/id.ts ================================================ KeyboardLayoutSelector Select a keyboard layout Pilihlah susunan keyboard yang sesuai LocaleSelector Select a locale Pilih bahasa yang diinginkan OnboardingFinal That's everything! Selesai! We hope you enjoy using theDesk! Kami harap Anda dapat menikmati theDesk! Get Started Mulai Done Selesai OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Bahasa Emergency Darurat Let's go! Mari kita mulai! Welcome Selamat Datang Welcome to %1! Selamat datang di %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/nl.ts ================================================ KeyboardLayoutSelector Select a keyboard layout Selecteer een toetsenbordindeling LocaleSelector Select a locale Selecteer een taal OnboardingFinal That's everything! Dat was het! We hope you enjoy using theDesk! We hopen dat je theDesk goed vindt! Get Started Beginnen Done Klaar OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Taal Emergency Noodgeval Let's go! Laten we gaan! Welcome Welkom Welcome to %1! Welkom bij %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Je hebt het gehaald! We zullen snel wat belangrijke instellingen doornemen zoals accounts instellen en met het Internet verbinden en daarna is alles klaar. Just a bit of important setup to do before you get started. This won't take long! Een paar belangrijke instellingen voordat je kunt beginnen. Dit duurt niet lang! OTHER OPTIONS ANDERE OPTIES QuietModeManagerTd Sound Geluid Critical Only Alleen Belangrijk No Notifications Geen Meldingen Mute Stil Allows all sounds Alle geluiden toestaan Hides non-critical notifications Verbergt niet-belangrijke meldingen Hides all notifications Verbergt alle meldingen Mutes all sound altogether Zet geluid helemaal uit ================================================ FILE: libthedesk/translations/pl_PL.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale Wybierz widownie OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/pt_BR.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/ro_RO.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale Selectați limba și regiunea dumneavoastră OnboardingFinal That's everything! Asta e tot! We hope you enjoy using theDesk! Sperăm că veți folosi cu plăcere theDesk! Get Started Să începem Done Gata OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Limbă Emergency Urgență Let's go! Să începem! Welcome Bine ați venit Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Sunet Critical Only Doar critice No Notifications Notificări dezactivate Mute Mut Allows all sounds Permite toate sunetele Hides non-critical notifications Ascunde toate notificările care nu sunt critice Hides all notifications Ascunde toate notificările Mutes all sound altogether Dezactivează toate sunetele ================================================ FILE: libthedesk/translations/sl_SI.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale izberite lokacijo OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/sv.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Critical Only No Notifications Mute Allows all sounds Hides non-critical notifications Hides all notifications Mutes all sound altogether ================================================ FILE: libthedesk/translations/tr_TR.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale Bir yerel ayar seçin OnboardingFinal That's everything! Biz bittik! We hope you enjoy using theDesk! theDesk kullanmaktan keyif alacağınızı umuyoruz! Get Started Başlamak Done Bitti OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Dil Emergency Acil Durum Let's go! Gidelim! Welcome Hoş geldin Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound Ses Critical Only Yalnızca Kritik No Notifications Bildirim Yok Mute Sessiz Allows all sounds Tüm seslere izin verir Hides non-critical notifications Kritik olmayan bildirimleri gizler Hides all notifications Tüm bildirimleri gizler Mutes all sound altogether Tüm sesleri tamamen kapatır ================================================ FILE: libthedesk/translations/vi_VN.ts ================================================ KeyboardLayoutSelector Select a keyboard layout Chọn bố trí bàn phím LocaleSelector Select a locale Chọn một ngôn ngữ OnboardingFinal That's everything! Đó là tất cả! We hope you enjoy using theDesk! Chúng tôi hy vọng bạn thích sử dụng theDesk! Get Started Bắt đầu Done Hoàn thành OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Ngôn ngữ Emergency Khẩn cấp Let's go! Bắt đầu! Welcome Chào mừng Welcome to %1! Chào mừng bạn với %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Bạn đã đến! Chúng tôi sẽ thực hiện một số thiết lập quan trọng, ví dụ thiết lập tài khoản và kết nối Internet, sau đó bạn sẵn sàng sử dụng thiết bị của bạn. Just a bit of important setup to do before you get started. This won't take long! Chỉ có một chút thiết lập quan trọng chúng tôi cần thực hiện trước khi bạn bắt đầu được. Điều này sẽ không mất nhiều thời gian! OTHER OPTIONS TÙY CHỌN KHÁC QuietModeManagerTd Sound Âm thanh Critical Only Chỉ quan trọng No Notifications Không có thông báo Mute Im lặng Allows all sounds Phát các âm thanh Hides non-critical notifications Ẩn thông báo không quan trọng Hides all notifications Ẩn các thông báo Mutes all sound altogether Tắt âm hoàn toàn ================================================ FILE: libthedesk/translations/zh_CN.ts ================================================ KeyboardLayoutSelector Select a keyboard layout LocaleSelector Select a locale 选择地区 OnboardingFinal That's everything! We hope you enjoy using theDesk! Get Started Done OnboardingVideo qrc:/libthedesk/onboarding/OnboardingVideoForm.qml OnboardingWelcome Language Emergency Let's go! Welcome Welcome to %1! You've made it! We'll quickly go through some important setup like setting up accounts and connecting to the Internet, and then you'll be up and running. Just a bit of important setup to do before you get started. This won't take long! OTHER OPTIONS QuietModeManagerTd Sound 声音 Critical Only 限紧急 No Notifications 无通知 Mute 静音 Allows all sounds 允许所有的声音 Hides non-critical notifications 隐藏不重要的通知 Hides all notifications 隐藏所有通知 Mutes all sound altogether 开启全局静音 ================================================ FILE: libthedesk/transparentdialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "transparentdialog.h" #include "ui_transparentdialog.h" #include #include TransparentDialog::TransparentDialog(QWidget* parent) : QDialog(parent), ui(new Ui::TransparentDialog) { ui->setupUi(this); // this->setWindowFlag(Qt::FramelessWindowHint); this->setWindowFlag(Qt::WindowStaysOnTopHint); this->setAttribute(Qt::WA_TranslucentBackground); tScrim::scrimForWidget(this)->setBlurEnabled(false); } TransparentDialog::~TransparentDialog() { delete ui; } void TransparentDialog::showEvent(QShowEvent *event) { DesktopWm::setSystemWindow(this, DesktopWm::SystemWindowTypeLockScreen); } ================================================ FILE: libthedesk/transparentdialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef TRANSPARENTDIALOG_H #define TRANSPARENTDIALOG_H #include namespace Ui { class TransparentDialog; } class TransparentDialog : public QDialog { Q_OBJECT public: explicit TransparentDialog(QWidget* parent = nullptr); ~TransparentDialog(); private: Ui::TransparentDialog* ui; // QWidget interface protected: void showEvent(QShowEvent *event); }; #endif // TRANSPARENTDIALOG_H ================================================ FILE: libthedesk/transparentdialog.ui ================================================ TransparentDialog 0 0 400 300 Dialog ================================================ FILE: locker/CMakeLists.txt ================================================ add_subdirectory(locker-common) add_subdirectory(locker-ui) add_subdirectory(locker-checker) ================================================ FILE: locker/locker-checker/CMakeLists.txt ================================================ project(locker VERSION 1.0.0 LANGUAGES CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) set(SOURCES main.cpp ) add_executable(locker-checker ${SOURCES} ${HEADERS}) cntp_target_name(locker-checker "td-locker-checker") target_link_libraries(locker-checker Qt::Core crypt) install(TARGETS locker-checker PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE SETUID RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} BUNDLE DESTINATION /Applications) ================================================ FILE: locker/locker-checker/main.cpp ================================================ #include #include #include #include #include #include int main(int argc, char* argv[]) { QCoreApplication::setSetuidAllowed(true); QCoreApplication a(argc, argv); QCommandLineParser parser; parser.addHelpOption(); parser.addPositionalArgument("username", "Username to check the password of", ""); parser.process(a); QFile shadow("/etc/shadow"); shadow.open(QFile::ReadOnly); if (!shadow.isReadable()) { QTextStream(stderr) << "Can't read the shadow file.\n"; QTextStream(stderr) << "This command needs to be run as root.\n"; return 2; } if (parser.positionalArguments().count() < 1) { QTextStream(stderr) << "Not enough arguments\n"; return 2; } // TODO: THIS IS BAD. // We should not be reading the shadow file directly. // Consider invoking PAM QStringList shadowFile(QString(shadow.readAll()).split("\n")); for (const QString& user : shadowFile) { auto parts = user.split(":"); if (parts.length() < 2) continue; if (parts.constFirst() == parser.positionalArguments().at(0)) { QString hashedPassword = parts.at(1); QStringList passwordParts = hashedPassword.split("$"); if (passwordParts.count() == 1) { QTextStream(stdout) << "No password.\n"; return 0; } else if (passwordParts.count() != 4) { QTextStream(stdout) << "Unable to parse shadow file\n"; return 2; } else { QTextStream in(stdin, QIODevice::ReadOnly); // Turn off echo struct termios term; tcgetattr(fileno(stdin), &term); term.c_lflag &= ~ECHO; tcsetattr(fileno(stdin), 0, &term); QTextStream(stderr) << "Password: "; const char* characters = (crypt(in.readLine().toUtf8().data(), QString("$" + passwordParts.at(1) + "$" + passwordParts.at(2)).toStdString().c_str())); QString encryptedPass(characters); QTextStream(stderr) << "\n"; if (encryptedPass.split("$").at(3) == passwordParts.at(3)) { QTextStream(stdout) << "Password correct\n"; return 0; } else { QTextStream(stderr) << "Password incorrect\n"; return 1; } } } } QTextStream(stderr) << "Unable to find user in shadow file\n"; return 2; } ================================================ FILE: locker/locker-common/CMakeLists.txt ================================================ project(locker VERSION 1.0.0 LANGUAGES CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) find_package(libcontemporary REQUIRED) cntp_find_pkgconfig(X11 x11) set(SOURCES lockergrabs.cpp ) set(HEADERS lockergrabs.h ) add_library(locker-common STATIC ${SOURCES} ${HEADERS}) target_link_libraries(locker-common Qt::Core libcontemporary) IF(${X11_FOUND}) target_link_libraries(locker-common PkgConfig::X11) target_compile_definitions(locker-common PRIVATE HAVE_X11) ENDIF() ================================================ FILE: locker/locker-common/lockergrabs.cpp ================================================ #include "lockergrabs.h" #ifdef HAVE_X11 #include #include #endif void LockerGrabs::establishGrab() { #ifdef HAVE_X11 if (tX11Info::isPlatformX11()) { XGrabKeyboard(tX11Info::display(), tX11Info::appRootWindow(), True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(tX11Info::display(), tX11Info::appRootWindow(), True, None, GrabModeAsync, GrabModeAsync, tX11Info::appRootWindow(), None, CurrentTime); } #endif } void LockerGrabs::releaseGrab() { #ifdef HAVE_X11 if (tX11Info::isPlatformX11()) { XUngrabKeyboard(tX11Info::display(), CurrentTime); XUngrabPointer(tX11Info::display(), CurrentTime); } #endif } ================================================ FILE: locker/locker-common/lockergrabs.h ================================================ #ifndef LOCKERGRABS_H #define LOCKERGRABS_H namespace LockerGrabs { void establishGrab(); void releaseGrab(); }; // namespace LockerGrabs #endif // LOCKERGRABS_H ================================================ FILE: locker/locker-ui/CMakeLists.txt ================================================ project(locker VERSION 1.0.0 LANGUAGES CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets DBus Sql PrintSupport) find_package(libcontemporary REQUIRED) find_package(libtdesktopenvironment REQUIRED) cntp_find_pkgconfig(X11 x11) set(SOURCES main.cpp mainwindow.cpp mainwindow.ui underlineanimation.cpp lockmanager.cpp ) set(HEADERS mainwindow.h underlineanimation.h lockmanager.h ) add_executable(locker-ui ${SOURCES} ${HEADERS}) set_target_properties(locker-ui PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in MACOSX_BUNDLE_GUI_IDENTIFIER com.vicr123.locker WIN32_EXECUTABLE TRUE CNTP_DATA_SUBDIR locker) cntp_init(locker-ui 20) cntp_translate(locker-ui) cntp_target_name(locker-ui "td-locker") target_link_libraries(locker-ui Qt::Widgets Qt::DBus Qt::Sql Qt::PrintSupport libcontemporary libtdesktopenvironment libthedesk locker-common) target_include_directories(locker-ui PUBLIC ../locker-common/) install(TARGETS locker-ui RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} BUNDLE DESTINATION /Applications) ================================================ FILE: locker/locker-ui/lockmanager.cpp ================================================ #include "lockmanager.h" #include "mainwindow.h" #include #include #include #include #include struct LockManagerPrivate { QList openWindows; QTimer* grabTimer; bool debugMode = false; }; LockManager* LockManager::instance() { static auto manager = new LockManager(); return manager; } void LockManager::setDebug(bool debugMode) { d->debugMode = debugMode; if (debugMode) { LockerGrabs::releaseGrab(); } this->openLockWindows(); } void LockManager::openLockWindows() { for (auto window : d->openWindows) { window->close(); window->deleteLater(); } d->openWindows.clear(); if (d->debugMode) { auto* w = new MainWindow(); w->show(); d->openWindows.append(w); } else { for (auto screen : ScreenDaemon::instance()->screens()) { auto* w = new MainWindow(); w->setWindowFlags(Qt::WindowStaysOnTopHint); w->show(); w->setGeometry(screen->geometry()); w->showFullScreen(); d->openWindows.append(w); } } } void LockManager::establishGrab() { if (d->debugMode) return; LockerGrabs::establishGrab(); } void LockManager::raiseAll() { for (auto w : d->openWindows) { w->raise(); } } LockManager::LockManager(QObject* parent) : QObject{parent} { d = new LockManagerPrivate(); connect(ScreenDaemon::instance(), &ScreenDaemon::screensUpdated, this, &LockManager::openLockWindows); openLockWindows(); d->grabTimer = new QTimer(); d->grabTimer->setInterval(5000); connect(d->grabTimer, &QTimer::timeout, this, &LockManager::establishGrab); connect(d->grabTimer, &QTimer::timeout, this, &LockManager::raiseAll); d->grabTimer->start(); establishGrab(); } ================================================ FILE: locker/locker-ui/lockmanager.h ================================================ #ifndef LOCKMANAGER_H #define LOCKMANAGER_H #include struct LockManagerPrivate; class LockManager : public QObject { Q_OBJECT public: static LockManager* instance(); void setDebug(bool debugMode); void openLockWindows(); void establishGrab(); void raiseAll(); signals: private: explicit LockManager(QObject* parent = nullptr); LockManagerPrivate* d; }; #endif // LOCKMANAGER_H ================================================ FILE: locker/locker-ui/main.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "lockmanager.h" #include #include int main(int argc, char* argv[]) { tApplication a(argc, argv); a.setApplicationShareDir("thedesk/locker"); a.installTranslators(); QCommandLineParser parser; parser.addHelpOption(); parser.addOption({ {"d", "debug"}, "Enable Debug Mode" }); parser.process(a); a.setApplicationVersion("4.0"); a.setGenericName(QApplication::translate("main", "Screen Locker")); a.setApplicationLicense(tApplication::Gpl3OrLater); a.setCopyrightHolder("Victor Tran"); a.setCopyrightYear("2022"); a.setOrganizationName("theSuite"); a.setApplicationName(T_APPMETA_READABLE_NAME); a.setDesktopFileName(T_APPMETA_DESKTOP_ID); a.registerCrashTrap(); LockManager::instance()->setDebug(parser.isSet("debug")); int retval = a.exec(); return retval; } ================================================ FILE: locker/locker-ui/mainwindow.cpp ================================================ #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include struct MainWindowPrivate { QString lockCheckProcess; SystemSlide* slide; }; MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); d = new MainWindowPrivate(); d->slide = new SystemSlide(this); d->slide->setBackgroundMode(SystemSlide::LockScreenBackground); d->slide->setAction(tr("Unlock"), tr("Resume your session, continuing where you left off")); d->slide->setActionIcon(QIcon::fromTheme("go-up")); d->slide->setDragResultWidget(this->centralWidget()); if (qEnvironmentVariableIsSet("TD_LOCK_CHECKER")) { d->lockCheckProcess = qEnvironmentVariable("TD_LOCK_CHECKER"); } else { d->lockCheckProcess = "/usr/lib/td-locker-checker"; // TODO: Don't hardcode } ui->usernameLabel->setText(DesktopWm::userDisplayName()); ui->capsLockOn->setVisible(false); connect(d->slide, &SystemSlide::deactivated, this, [this] { if (this->checkPassword("")) { QApplication::exit(0); return; } ui->password->setFocus(); QTimer::singleShot(100, this, [this] { ui->PasswordUnderline->startAnimation(); }); }); } MainWindow::~MainWindow() { delete d; delete ui; } void MainWindow::on_titleLabel_backButtonClicked() { d->slide->activate(); } bool MainWindow::checkPassword(QString password) { QString name = qgetenv("USER"); if (name.isEmpty()) { name = qgetenv("USERNAME"); } QProcess checker; checker.start(d->lockCheckProcess, {name}); checker.write(password.toUtf8()); checker.write("\n"); checker.closeWriteChannel(); checker.waitForFinished(); return checker.exitCode() == 0; } void MainWindow::on_unlockButton_clicked() { this->setEnabled(false); if (checkPassword(ui->password->text())) { QApplication::exit(0); return; } this->setEnabled(true); ui->password->setText(""); ui->password->setFocus(); tErrorFlash::flashError(ui->password); } void MainWindow::on_password_returnPressed() { ui->unlockButton->click(); } void MainWindow::changeEvent(QEvent* event) { if (event->type() == QEvent::ActivationChange) { LockManager::instance()->raiseAll(); } } void MainWindow::showEvent(QShowEvent* event) { DesktopWm::instance()->setSystemWindow(this, DesktopWm::SystemWindowTypeLockScreen); } ================================================ FILE: locker/locker-ui/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include namespace Ui { class MainWindow; } struct MainWindowPrivate; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget* parent = nullptr); ~MainWindow(); private slots: void on_titleLabel_backButtonClicked(); void on_unlockButton_clicked(); void on_password_returnPressed(); private: Ui::MainWindow* ui; MainWindowPrivate* d; bool checkPassword(QString password); // QWidget interface protected: void changeEvent(QEvent* event); // QWidget interface protected: void showEvent(QShowEvent *event); }; #endif // MAINWINDOW_H ================================================ FILE: locker/locker-ui/mainwindow.ui ================================================ MainWindow 0 0 800 600 MainWindow 0 0 0 0 0 Unlock Session 9 9 9 9 Qt::Horizontal 40 20 Qt::Vertical 20 40 Qt::Vertical 20 40 500 0 false QFrame::NoFrame QFrame::Plain 0 15 Username 20 Please enter your password Qt::Vertical QSizePolicy::Fixed 20 40 0 0 0 30 true false QLineEdit::Password Qt::AlignCenter false Caps Lock is on Caps Lock is on 0 0 false true Qt::Horizontal 40 20 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
UnderlineAnimation QWidget
underlineanimation.h
1
================================================ FILE: locker/locker-ui/translations/en_US.ts ================================================ MainWindow MainWindow Unlock Session Please enter your password Caps Lock is on Unlock Resume your session, continuing where you left off main Screen Locker ================================================ FILE: locker/locker-ui/underlineanimation.cpp ================================================ #include "underlineanimation.h" UnderlineAnimation::UnderlineAnimation(QWidget *parent) : QWidget(parent) { anim1 = new tVariantAnimation(); anim1->setStartValue(0); anim1->setEndValue(this->width() / 2); anim1->setDuration(500); anim1->setEasingCurve(QEasingCurve::OutCubic); connect(anim1, &tVariantAnimation::valueChanged, [=](QVariant value) { this->repaint(); }); QColor col = this->palette().color(QPalette::WindowText).toRgb(); anim2 = new tVariantAnimation(); anim2->setStartValue(col); col.setAlpha(0); anim2->setEndValue(col); anim2->setDuration(500); anim2->setEasingCurve(QEasingCurve::OutCubic); } QSize UnderlineAnimation::sizeHint() const { return QSize(20, 1); } void UnderlineAnimation::startAnimation() { anim1->setEndValue(this->width() / 2); anim1->start(); anim2->setCurrentTime(0); //QTimer::singleShot(500, [=] { anim2->start(); //}); } void UnderlineAnimation::paintEvent(QPaintEvent *event) { QPainter p(this); p.setPen(Qt::transparent); p.setBrush(anim2->currentValue().value()); int mid = this->width() / 2; p.drawRect(mid - anim1->currentValue().toInt(), 0, anim1->currentValue().toInt() * 2, this->height()); } ================================================ FILE: locker/locker-ui/underlineanimation.h ================================================ #ifndef UNDERLINEANIMATION_H #define UNDERLINEANIMATION_H #include #include #include #include #include class UnderlineAnimation : public QWidget { Q_OBJECT public: explicit UnderlineAnimation(QWidget *parent = nullptr); QSize sizeHint() const; signals: public slots: void startAnimation(); private: void paintEvent(QPaintEvent* event); tVariantAnimation *anim1, *anim2; }; #endif // UNDERLINEANIMATION_H ================================================ FILE: platform/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) cntp_define_build_dirs() set(SOURCES cursorhandler.cpp fontformat.cpp iconloaderengine.cpp messagedialog/messagedialog.cpp messagedialog/messagedialogcontroller.cpp messagedialog/messagedialoghelper.cpp paletteformat.cpp platformtheme.cpp plugin.cpp messagedialog/messagedialog.ui thedesk-platform-resources.qrc ) set(HEADERS cursorhandler.h fontformat.h iconloaderengine.h messagedialog/messagedialog.h messagedialog/messagedialogcontroller.h messagedialog/messagedialoghelper.h paletteformat.h platformtheme.h plugin.h ) add_library(thedesk-platform-plugin SHARED ${SOURCES} ${HEADERS}) target_include_directories(thedesk-platform-plugin PUBLIC ../libthedesk/) set_target_properties(thedesk-platform-plugin PROPERTIES OUTPUT_NAME thedesk-platform FRAMEWORK FALSE CNTP_DATA_SUBDIR thedesk/platform ) cntp_init_plugin(thedesk thedesk-platform-plugin 20 thedesk-platform-plugin) cntp_translate(thedesk-platform-plugin) cntp_defaults_file(thedesk-platform-plugin DEFAULTS_FILE thedesk-platform.conf) target_link_libraries(thedesk-platform-plugin Qt::Widgets Qt::GuiPrivate libcontemporary) target_include_directories(thedesk-platform-plugin PRIVATE ${Qt${QT_VERSION_MAJOR}Gui_PRIVATE_INCLUDE_DIRS}) install(TARGETS thedesk-platform-plugin LIBRARY DESTINATION ${CNTP_INSTALL_PLUGINS}/platformthemes/ RUNTIME DESTINATION ${CNTP_INSTALL_PLUGINS}/platformthemes/) ================================================ FILE: platform/cursorhandler.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "cursorhandler.h" #include #include #include #ifdef HAVE_X11 #include #endif struct CursorHandlerPrivate { tSettings* settings; }; CursorHandler::CursorHandler(QObject* parent) : QObject(parent) { d = new CursorHandlerPrivate(); d->settings = new tSettings("theSuite", "theDesk.platform", this); connect(d->settings, &tSettings::settingChanged, this, [ = ](QString key, QVariant value) { if (key == "Platform/cursor" || key == "Platform/cursorSize") { this->updateApplicationCursor(); } }); this->updateApplicationCursor(); } CursorHandler::~CursorHandler() { delete d; } void CursorHandler::updateApplicationCursor() { #ifdef HAVE_X11 if (QX11Info::isPlatformX11()) { //Load cursor library QLibrary xc(QString(SYSTEM_LIBRARY_DIRECTORY).append("/libXcursor.so")); if (xc.load()) { typedef int (*setThemeFunc) (Display*, const char*); typedef int (*setSizeFunc) (Display*, int); auto XcursorSetTheme = reinterpret_cast(xc.resolve("XcursorSetTheme")); auto XcursorSetDefaultSize = reinterpret_cast(xc.resolve("XcursorSetDefaultSize")); //Set cursors XcursorSetTheme(QX11Info::display(), qPrintable(d->settings->value("Platform/cursor").toString())); XcursorSetDefaultSize(QX11Info::display(), d->settings->value("Platform/cursorSize").toInt()); } else { tDebug("CursorHandler") << "Could not load XCursor library: " + xc.errorString(); } } #endif } ================================================ FILE: platform/cursorhandler.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CURSORHANDLER_H #define CURSORHANDLER_H #include struct CursorHandlerPrivate; class CursorHandler : public QObject { Q_OBJECT public: explicit CursorHandler(QObject* parent = nullptr); ~CursorHandler(); signals: private: CursorHandlerPrivate* d; void updateApplicationCursor(); }; #endif // CURSORHANDLER_H ================================================ FILE: platform/fontformat.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "fontformat.h" #include const QMap fontTypes = { {"system", QPlatformTheme::SystemFont}, {"menu", QPlatformTheme::MenuFont}, {"menubar", QPlatformTheme::MenuBarFont}, {"menuItem", QPlatformTheme::MenuItemFont}, {"messageBox", QPlatformTheme::MessageBoxFont}, {"label", QPlatformTheme::LabelFont}, {"tipLabel", QPlatformTheme::TipLabelFont}, {"statusBar", QPlatformTheme::StatusBarFont}, {"titleBar", QPlatformTheme::TitleBarFont}, {"titleBar.mdi", QPlatformTheme::MdiSubWindowTitleFont}, {"titleBar.dock", QPlatformTheme::DockWidgetTitleFont}, {"button", QPlatformTheme::PushButtonFont}, {"button.tool", QPlatformTheme::ToolButtonFont}, {"button.tab", QPlatformTheme::TabButtonFont}, {"checkbox", QPlatformTheme::CheckBoxFont}, {"radio", QPlatformTheme::RadioButtonFont}, {"view.item", QPlatformTheme::ItemViewFont}, {"view.list", QPlatformTheme::ListViewFont}, {"view.header", QPlatformTheme::HeaderViewFont}, {"combo", QPlatformTheme::ListBoxFont}, {"combo.item", QPlatformTheme::ComboMenuItemFont}, {"combo.edit", QPlatformTheme::ComboLineEditFont}, {"small", QPlatformTheme::SmallFont}, {"mini", QPlatformTheme::MiniFont}, {"groupboxTitle", QPlatformTheme::GroupBoxTitleFont}, {"editor", QPlatformTheme::EditorFont}, {"fixed", QPlatformTheme::FixedFont} }; QPlatformTheme::Font FontFormat::fontForString(QString string) { return fontTypes.value(string); } ================================================ FILE: platform/fontformat.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef FONTFORMAT_H #define FONTFORMAT_H #include namespace FontFormat { QPlatformTheme::Font fontForString(QString string); } #endif // FONTFORMAT_H ================================================ FILE: platform/iconloaderengine.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "iconloaderengine.h" #include struct IconLoaderEnginePrivate { QString iconName; QIconEngine* parentEngine; // QIconEngine* rtlParentEngine; }; IconLoaderEngine::IconLoaderEngine(QString iconName, QIconEngine* parentEngine, QIconEngine* rtlParentEngine) { d = new IconLoaderEnginePrivate(); d->iconName = iconName; d->parentEngine = parentEngine; // d->rtlParentEngine = rtlParentEngine; } IconLoaderEngine::~IconLoaderEngine() { delete d->parentEngine; delete d; } QPixmap IconLoaderEngine::pixmap(const QSize& size, QIcon::Mode mode, QIcon::State state) { QImage image; // if (QApplication::layoutDirection() == Qt::RightToLeft && d->rtlParentEngine->availableSizes(mode, state).length() > 0) { // image = d->rtlParentEngine->pixmap(size, mode, state).toImage(); // } else { image = d->parentEngine->pixmap(size, mode, state).toImage(); // } libContemporaryCommon::tintImage(image, QApplication::palette().color(QPalette::WindowText)); return QPixmap::fromImage(image); } void IconLoaderEngine::paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state) { // if (QApplication::layoutDirection() == Qt::RightToLeft && d->rtlParentEngine->availableSizes(mode, state).length() > 0) { // d->rtlParentEngine->paint(painter, rect, mode, state); // } else { d->parentEngine->paint(painter, rect, mode, state); // } } QSize IconLoaderEngine::actualSize(const QSize& size, QIcon::Mode mode, QIcon::State state) { // if (QApplication::layoutDirection() == Qt::RightToLeft) { // return d->rtlParentEngine->actualSize(size, mode, state); // } else { return d->parentEngine->actualSize(size, mode, state); // } } void IconLoaderEngine::addPixmap(const QPixmap& pixmap, QIcon::Mode mode, QIcon::State state) { d->parentEngine->addPixmap(pixmap, mode, state); // d->rtlParentEngine->addPixmap(pixmap, mode, state); } void IconLoaderEngine::addFile(const QString& fileName, const QSize& size, QIcon::Mode mode, QIcon::State state) { d->parentEngine->addFile(fileName, size, mode, state); // d->rtlParentEngine->addFile(fileName, size, mode, state); } QString IconLoaderEngine::key() const { return d->parentEngine->key(); } QIconEngine* IconLoaderEngine::clone() const { // return new IconLoaderEngine(d->iconName, d->parentEngine->clone(), d->rtlParentEngine->clone()); return new IconLoaderEngine(d->iconName, d->parentEngine->clone(), nullptr); } bool IconLoaderEngine::read(QDataStream& in) { return d->parentEngine->read(in); } bool IconLoaderEngine::write(QDataStream& out) const { return d->parentEngine->write(out); } QList IconLoaderEngine::availableSizes(QIcon::Mode mode, QIcon::State state) { // if (QApplication::layoutDirection() == Qt::RightToLeft) { // return d->rtlParentEngine->availableSizes(mode, state); // } else { return d->parentEngine->availableSizes(mode, state); // } } QString IconLoaderEngine::iconName() { return d->iconName; } void IconLoaderEngine::virtual_hook(int id, void* data) { d->parentEngine->virtual_hook(id, data); } bool IconLoaderEngine::isNull() { return d->parentEngine->isNull(); } QPixmap IconLoaderEngine::scaledPixmap(const QSize& size, QIcon::Mode mode, QIcon::State state, qreal scale) { // if (QApplication::layoutDirection() == Qt::RightToLeft && d->rtlParentEngine->availableSizes(mode, state).length() > 0) { // return d->rtlParentEngine->scaledPixmap(size, mode, state, scale); // } else { return d->parentEngine->scaledPixmap(size, mode, state, scale); // } } ================================================ FILE: platform/iconloaderengine.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ICONLOADERENGINE_H #define ICONLOADERENGINE_H #include struct IconLoaderEnginePrivate; class IconLoaderEngine : public QIconEngine { public: explicit IconLoaderEngine(QString iconName, QIconEngine* parentEngine, QIconEngine* rtlParentEngine); ~IconLoaderEngine(); private: IconLoaderEnginePrivate* d; // QIconEngine interface public: QPixmap pixmap(const QSize& size, QIcon::Mode mode, QIcon::State state); void paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state); QSize actualSize(const QSize& size, QIcon::Mode mode, QIcon::State state); void addPixmap(const QPixmap& pixmap, QIcon::Mode mode, QIcon::State state); void addFile(const QString& fileName, const QSize& size, QIcon::Mode mode, QIcon::State state); QString key() const; QIconEngine* clone() const; bool read(QDataStream& in); bool write(QDataStream& out) const; QList availableSizes(QIcon::Mode mode, QIcon::State state); QString iconName(); void virtual_hook(int id, void* data); bool isNull(); QPixmap scaledPixmap(const QSize& size, QIcon::Mode mode, QIcon::State state, qreal scale); }; #endif // ICONLOADERENGINE_H ================================================ FILE: platform/messagedialog/messagedialog.cpp ================================================ /**************************************** * *INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE *Copyright (C) 2020 Victor Tran * *This program is free software: you can redistribute it and/or modify *it under the terms of the GNU General Public License as published by *the Free Software Foundation, either version 3 of the License, or *(at your option) any later version. * *This program is distributed in the hope that it will be useful, *but WITHOUT ANY WARRANTY; without even the implied warranty of *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *GNU General Public License for more details. * *You should have received a copy of the GNU General Public License *along with this program. If not, see . * * *************************************/ #include "messagedialog.h" #include "ui_messagedialog.h" #include #include #include struct MessageDialogPrivate { QList buttons; QGraphicsOpacityEffect* opacity; bool showingDetails = false; }; MessageDialog::MessageDialog(QWidget* parent) : QWidget(parent), ui(new Ui::MessageDialog) { ui->setupUi(this); d = new MessageDialogPrivate(); // this->setWindowFlags(Qt::Widget); ui->frame->setMinimumWidth(400); d->opacity = new QGraphicsOpacityEffect(this); d->opacity->setEnabled(false); ui->frame->setGraphicsEffect(d->opacity); ui->detailsWidget->setVisible(false); ui->dialogTypeWidget->setFixedWidth(3); } MessageDialog::~MessageDialog() { delete d; delete ui; } void MessageDialog::setOptions(const QSharedPointer& options) { for (QPushButton* btn : d->buttons) { ui->buttonLayout->removeWidget(btn); btn->deleteLater(); } d->buttons.clear(); this->setWindowTitle(options->windowTitle()); ui->titleLabel->setText(options->windowTitle().toUpper()); ui->messageLabel->setText(options->text()); if (options->informativeText().isEmpty()) { ui->informativeTextLabel->setVisible(false); } else { ui->informativeTextLabel->setVisible(true); ui->informativeTextLabel->setText(options->informativeText()); } if (options->detailedText().isEmpty()) { ui->detailsButton->setVisible(false); } else { ui->detailsButton->setVisible(true); ui->detailsLabel->setText(options->detailedText()); } QPalette pal = ui->dialogTypeWidget->palette(); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) switch (options->standardIcon()) { #else switch (options->icon()) { #endif case QMessageDialogOptions::NoIcon: case QMessageDialogOptions::Information: pal.setColor(QPalette::Window, Qt::transparent); break; case QMessageDialogOptions::Question: pal.setColor(QPalette::Window, QColor(0, 150, 255)); break; case QMessageDialogOptions::Warning: pal.setColor(QPalette::Window, QColor(255, 150, 0)); break; case QMessageDialogOptions::Critical: pal.setColor(QPalette::Window, QColor(200, 0, 0)); break; } ui->dialogTypeWidget->setPalette(pal); QVector buttons; if (options->standardButtons() & QPlatformDialogHelper::Ok) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Ok, tr("OK"), QPlatformDialogHelper::AcceptRole)); if (options->standardButtons() & QPlatformDialogHelper::Save) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Save, tr("Save"), QPlatformDialogHelper::AcceptRole)); if (options->standardButtons() & QPlatformDialogHelper::SaveAll) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::SaveAll, tr("Save All"), QPlatformDialogHelper::AcceptRole)); if (options->standardButtons() & QPlatformDialogHelper::Open) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Open, tr("Open"), QPlatformDialogHelper::AcceptRole)); if (options->standardButtons() & QPlatformDialogHelper::Yes) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Yes, tr("Yes"), QPlatformDialogHelper::YesRole)); if (options->standardButtons() & QPlatformDialogHelper::YesToAll) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::YesToAll, tr("Yes to All"), QPlatformDialogHelper::YesRole)); if (options->standardButtons() & QPlatformDialogHelper::No) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::No, tr("No"), QPlatformDialogHelper::NoRole)); if (options->standardButtons() & QPlatformDialogHelper::NoToAll) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::NoToAll, tr("No to All"), QPlatformDialogHelper::NoRole)); if (options->standardButtons() & QPlatformDialogHelper::Abort) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Abort, tr("Abort"), QPlatformDialogHelper::DestructiveRole)); if (options->standardButtons() & QPlatformDialogHelper::Retry) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Retry, tr("Retry"), QPlatformDialogHelper::AcceptRole)); if (options->standardButtons() & QPlatformDialogHelper::Ignore) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Ignore, tr("Ignore"), QPlatformDialogHelper::AcceptRole)); if (options->standardButtons() & QPlatformDialogHelper::Close) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Close, tr("Close"), QPlatformDialogHelper::AcceptRole)); if (options->standardButtons() & QPlatformDialogHelper::Cancel) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Cancel, tr("Cancel"), QPlatformDialogHelper::RejectRole)); if (options->standardButtons() & QPlatformDialogHelper::Discard) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Discard, tr("Discard"), QPlatformDialogHelper::DestructiveRole)); if (options->standardButtons() & QPlatformDialogHelper::Help) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Help, tr("Help"), QPlatformDialogHelper::ActionRole)); if (options->standardButtons() & QPlatformDialogHelper::Apply) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Apply, tr("Apply"), QPlatformDialogHelper::AcceptRole)); if (options->standardButtons() & QPlatformDialogHelper::Reset) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Reset, tr("Reset"), QPlatformDialogHelper::ResetRole)); if (options->standardButtons() & QPlatformDialogHelper::RestoreDefaults) buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::RestoreDefaults, tr("Restore Defaults"), QPlatformDialogHelper::ResetRole)); buttons.append(options->customButtons()); for (int i = 0; i < buttons.length(); i++) { if (buttons.at(i).label == "Show Details...") { buttons.removeAt(i); } } if (buttons.isEmpty()) { // Add a failsafe button buttons.append(QMessageDialogOptions::CustomButton(QPlatformDialogHelper::Ok, tr("OK"), QPlatformDialogHelper::AcceptRole)); } for (const QMessageDialogOptions::CustomButton& btn : buttons) { QPushButton* button = new QPushButton(this); button->setText(btn.label); if (btn.role == QPlatformDialogHelper::DestructiveRole) button->setProperty("type", "destructive"); connect(button, &QPushButton::clicked, this, [=] { emit clicked(static_cast(btn.id), btn.role); }); ui->buttonLayout->addWidget(button); d->buttons.append(button); } if (options->checkBoxLabel().isEmpty()) { ui->checkBox->setVisible(false); } else { ui->checkBox->setVisible(true); ui->checkBox->setText(options->checkBoxLabel()); ui->checkBox->setCheckState(options->checkBoxState()); } } void MessageDialog::setParent(QWidget* parent) { parent->installEventFilter(this); QWidget::setParent(parent); } void MessageDialog::animateIn() { d->opacity->setEnabled(true); d->opacity->setOpacity(0); tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(0.0); anim->setEndValue(1.0); anim->setDuration(400); anim->setEasingCurve(QEasingCurve::OutCubic); connect(anim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { d->opacity->setOpacity(value.toReal()); QRect geometry = frameGeometry(); geometry.moveTop(geometry.top() - 10 * (1.0 - value.toReal())); this->setFixedSize(QSize(0, 0)); this->setFixedSize(geometry.size()); this->setGeometry(geometry); }); connect(anim, &tVariantAnimation::finished, this, [=] { d->opacity->setEnabled(false); anim->deleteLater(); }); anim->start(); } void MessageDialog::animateOut() { d->opacity->setEnabled(true); tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(1.0); anim->setEndValue(0.0); anim->setDuration(400); anim->setEasingCurve(QEasingCurve::OutCubic); connect(anim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { d->opacity->setOpacity(value.toReal()); QRect geometry = frameGeometry(); geometry.moveTop(geometry.top() + 10 * (1.0 - value.toReal())); this->setFixedSize(QSize(0, 0)); this->setFixedSize(geometry.size()); this->setGeometry(geometry); }); connect(anim, &tVariantAnimation::finished, this, [=] { anim->deleteLater(); this->hide(); }); anim->start(); } QRect MessageDialog::frameGeometry() { QRect geometry = this->geometry(); if (d->showingDetails) { if (ui->detailsContents->sizeHint().width() > 400) { geometry.setSize(ui->detailsContents->sizeHint()); } else { geometry.setSize(QSize(400, ui->detailsContents->heightForWidth(400))); } if (this->parentWidget() && geometry.height() > this->parentWidget()->height()) geometry.setHeight(this->parentWidget()->height()); } else { if (ui->frame->sizeHint().width() > 400) { geometry.setSize(ui->frame->sizeHint()); } else { geometry.setSize(QSize(400, ui->frame->heightForWidth(400))); } } if (this->parentWidget()) { geometry.moveCenter(QRect(0, 0, this->parentWidget()->width(), this->parentWidget()->height()).center()); } return geometry; } void MessageDialog::updateGeometry() { QRect geometry = frameGeometry(); this->setFixedSize(geometry.size()); this->setGeometry(geometry); } void MessageDialog::resizeEvent(QResizeEvent* event) { updateGeometry(); } void MessageDialog::on_backButton_clicked() { ui->detailsWidget->setVisible(false); d->showingDetails = false; updateGeometry(); ui->frame->setVisible(true); } void MessageDialog::on_detailsButton_clicked() { ui->frame->setVisible(false); d->showingDetails = true; updateGeometry(); ui->detailsWidget->setVisible(true); } bool MessageDialog::eventFilter(QObject* watched, QEvent* event) { if (watched == this->parentWidget() && event->type() == QEvent::Resize) { updateGeometry(); } return false; } void MessageDialog::on_checkBox_stateChanged(int arg1) { emit checkBoxStateChanged(static_cast(arg1)); } ================================================ FILE: platform/messagedialog/messagedialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MESSAGEDIALOG_H #define MESSAGEDIALOG_H #include #include namespace Ui { class MessageDialog; } struct MessageDialogPrivate; class MessageDialog : public QWidget { Q_OBJECT public: explicit MessageDialog(QWidget* parent = nullptr); ~MessageDialog(); void extracted(QVector& buttons); void setOptions(const QSharedPointer& options); void setParent(QWidget* parent); void animateIn(); void animateOut(); QRect frameGeometry(); void updateGeometry(); signals: void clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role); void checkBoxStateChanged(Qt::CheckState state); private: Ui::MessageDialog* ui; MessageDialogPrivate* d; // QWidget interface protected: void resizeEvent(QResizeEvent* event); private slots: void on_backButton_clicked(); void on_detailsButton_clicked(); // QObject interface void on_checkBox_stateChanged(int arg1); public: bool eventFilter(QObject* watched, QEvent* event); }; #endif // MESSAGEDIALOG_H ================================================ FILE: platform/messagedialog/messagedialog.ui ================================================ MessageDialog 0 0 581 370 Dialog 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 6 0 0 0 0 true 0 0 0 0 0 0 0 0 6 true Title TextLabel true false TextLabel true CheckBox Details... 0 0 0 0 0 QFrame::NoFrame true 0 0 581 247 true true DETAILS TextLabel true Back ================================================ FILE: platform/messagedialog/messagedialogcontroller.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "messagedialogcontroller.h" MessageDialogController::MessageDialogController(QObject *parent) : QObject(parent) { } ================================================ FILE: platform/messagedialog/messagedialogcontroller.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MESSAGEDIALOGCONTROLLER_H #define MESSAGEDIALOGCONTROLLER_H #include struct MessageDialogControllerPrivate; class MessageDialogController : public QObject { Q_OBJECT public: explicit MessageDialogController(QObject *parent = nullptr); signals: private: MessageDialogControllerPrivate* d; }; #endif // MESSAGEDIALOGCONTROLLER_H ================================================ FILE: platform/messagedialog/messagedialoghelper.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "messagedialoghelper.h" #include "messagedialog.h" #include #include #include #include #include #include #include #include #include #include struct MessageDialogHelperPrivate { MessageDialog* dlg; QEventLoop eventLoop; QPointer parent; QPointer parentWidget; QPointer cover2; const int coverOverscan = 50; }; MessageDialogHelper::MessageDialogHelper() : QPlatformMessageDialogHelper() { d = new MessageDialogHelperPrivate(); d->dlg = new MessageDialog(); connect(d->dlg, &MessageDialog::clicked, this, [this] { if (d->eventLoop.isRunning()) d->eventLoop.exit(); this->hide(); }); connect(d->dlg, &MessageDialog::checkBoxStateChanged, this, &MessageDialogHelper::checkBoxStateChanged); connect(d->dlg, &MessageDialog::clicked, this, &MessageDialogHelper::clicked); } MessageDialogHelper::~MessageDialogHelper() { d->dlg->deleteLater(); if (d->cover2) d->cover2->deleteLater(); delete d; } void MessageDialogHelper::updateWindowGeometry() { if (d->parent) { QRect geometry; if (d->parentWidget) { geometry = QRect(-d->coverOverscan, -d->coverOverscan, d->parentWidget->width() + 2 * d->coverOverscan, d->parentWidget->height() + 2 * d->coverOverscan); } else { geometry = QRect(-d->coverOverscan, -d->coverOverscan, d->parent->width() + 2 * d->coverOverscan, d->parent->height() + 2 * d->coverOverscan); } if (d->cover2) d->cover2->setGeometry(geometry); d->dlg->updateGeometry(); } else { d->dlg->setFixedSize(d->dlg->frameGeometry().size()); } } void MessageDialogHelper::exec() { d->dlg->setOptions(this->options()); d->eventLoop.exec(); } bool MessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow* parent) { QWidget* widget = nullptr; if (parent) { for (QWidget* w : QApplication::allWidgets()) { if (w->winId() == parent->winId()) widget = w->window(); } } QMainWindow* mainWindow = qobject_cast(widget); if (mainWindow && tCsdTools::csdsInstalled(mainWindow)) widget = mainWindow->centralWidget(); d->parentWidget = widget; d->dlg->setOptions(this->options()); d->dlg->setWindowFlags(windowFlags); if (d->parent) { d->parent->disconnect(this); } d->parent = parent; connect(parent, &QWindow::widthChanged, this, &MessageDialogHelper::updateWindowGeometry); connect(parent, &QWindow::heightChanged, this, &MessageDialogHelper::updateWindowGeometry); connect(parent, &QWindow::xChanged, this, &MessageDialogHelper::updateWindowGeometry); connect(parent, &QWindow::yChanged, this, &MessageDialogHelper::updateWindowGeometry); if (widget) { tScrim::scrimForWidget(widget)->show(); d->dlg->setParent(widget); d->dlg->show(); d->dlg->raise(); // For some reason, Qt doesn't render this properly on tCsd apps // but it fixes itself if we have a transparent widget on top d->cover2 = new QWidget(); d->cover2->setAttribute(Qt::WA_TransparentForMouseEvents); d->cover2->setParent(widget); d->cover2->show(); d->cover2->raise(); d->dlg->animateIn(); } updateWindowGeometry(); d->dlg->show(); return true; } void MessageDialogHelper::hide() { if (d->parentWidget) { d->dlg->animateOut(); tScrim::scrimForWidget(d->parentWidget)->hide(); if (d->cover2) d->cover2->hide(); } else { d->dlg->hide(); if (d->cover2) d->cover2->hide(); } } void MessageDialogHelper::setOptions(const QSharedPointer& options) { QPlatformMessageDialogHelper::setOptions(options); d->dlg->setOptions(options); } QVariant MessageDialogHelper::styleHint(StyleHint hint) const { if (hint == DialogIsQtWindow) { return true; } return QPlatformMessageDialogHelper::StyleHint(hint); } ================================================ FILE: platform/messagedialog/messagedialoghelper.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MESSAGEDIALOGHELPER_H #define MESSAGEDIALOGHELPER_H #include struct MessageDialogHelperPrivate; class MessageDialogHelper : public QPlatformMessageDialogHelper { Q_OBJECT public: explicit MessageDialogHelper(); ~MessageDialogHelper(); signals: private: MessageDialogHelperPrivate* d; void updateWindowGeometry(); // QPlatformMessageDialogHelper interface public: void exec(); bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow* parent); void hide(); void setOptions(const QSharedPointer& options); // QPlatformDialogHelper interface public: QVariant styleHint(StyleHint hint) const; }; #endif // MESSAGEDIALOGHELPER_H ================================================ FILE: platform/paletteformat.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include #include #include #include const QMap roles = { {"window", QPalette::Window }, {"windowText", QPalette::WindowText }, {"base", QPalette::Base }, {"altBase", QPalette::AlternateBase }, {"alternateBase", QPalette::AlternateBase }, {"text", QPalette::Text }, {"brightText", QPalette::BrightText }, {"button", QPalette::Button }, {"buttonText", QPalette::ButtonText }, {"highlight", QPalette::Highlight }, {"highlightText", QPalette::HighlightedText}, {"highlightedText", QPalette::HighlightedText}, {"link", QPalette::Link }, {"linkVisited", QPalette::LinkVisited }, {"tooltip", QPalette::ToolTipBase }, {"tooltipBase", QPalette::ToolTipBase }, {"tooltipText", QPalette::ToolTipText }, {"placeholderText", QPalette::PlaceholderText}, {"light", QPalette::Light }, {"midLight", QPalette::Midlight }, {"mid", QPalette::Mid }, {"dark", QPalette::Dark }, {"shadow", QPalette::Shadow } }; const QMap groups = { {"normal", QPalette::Normal }, {"inactive", QPalette::Inactive}, {"disabled", QPalette::Disabled} }; QPalette::ColorRole PaletteFormat::roleForString(QString string) { return roles.value(string); } void PaletteFormat::applyColor(QPalette* pal, QString key, QJsonValue value) { QPalette::ColorRole role = PaletteFormat::roleForString(key); if (value.type() == QJsonValue::Object) { QJsonObject obj = value.toObject(); for (auto i = obj.constBegin(); i != obj.constEnd(); i++) { QPalette::ColorGroup group = PaletteFormat::groupForString(i.key()); pal->setColor(group, role, PaletteFormat::colorFromValue(i.value())); } } else { pal->setColor(role, PaletteFormat::colorFromValue(value)); } } QColor PaletteFormat::colorFromValue(QJsonValue value) { switch (value.type()) { case QJsonValue::Double: { // Grayscale value int v = value.toInt(); return QColor(v, v, v); } case QJsonValue::String: // Name color return QColor(value.toString()); case QJsonValue::Array: { // RGB Triplet QJsonArray array = value.toArray(); return QColor(array.at(0).toInt(), array.at(1).toInt(), array.at(2).toInt()); } default: //??? invalid format return QColor(); } } QPalette::ColorGroup PaletteFormat::groupForString(QString string) { return groups.value(string); } ================================================ FILE: platform/paletteformat.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PALETTEFORMAT_H #define PALETTEFORMAT_H #include #include #include namespace PaletteFormat { QPalette::ColorRole roleForString(QString string); QPalette::ColorGroup groupForString(QString string); void applyColor(QPalette* pal, QString key, QJsonValue value); QColor colorFromValue(QJsonValue value); } // namespace PaletteFormat #endif // PALETTEFORMAT_H ================================================ FILE: platform/palettes.json ================================================ { "dark": { "bases": { "window": 40, "windowText": { "normal": "white", "inactive": "white", "disabled": 150 }, "base": 40, "text": "white", "placeholderText": 150, "tooltipText": "white", "alternateBase": 40, "link": [0,200,255] }, "accents": { "blue": { "button": { "normal": [0,50,150], "inactive": [0,50,150], "disabled": [0,30,100] }, "buttonText": { "normal": "white", "inactive": "white", "disabled": 150 }, "highlight": [0,80,170], "highlightText": "white" }, "green": { "button": { "normal": [0,85,0], "inactive": [0,85,0], "disabled": [0,50,0] }, "buttonText": { "normal": "white", "inactive": "white", "disabled": 150 }, "highlight": [0,100,0], "highlightText": "white" }, "orange": { "button": { "normal": [200,50,0], "inactive": [200,50,0], "disabled": [100,25,0] }, "buttonText": { "normal": "white", "inactive": "white", "disabled": 150 }, "highlight": [200,100,0], "highlightText": "white" }, "pink": { "button": { "normal": [150,0,150], "inactive": [150,0,150], "disabled": [100,0,100] }, "buttonText": { "normal": "white", "inactive": "white", "disabled": 150 }, "highlight": [200,0,200], "highlightText": "white" } } }, "light": { "bases": { "window": 210, "windowText": { "normal": "black", "inactive": "black", "disabled": 100 }, "base": 210, "text": "black", "placeholderText": 100, "tooltipText": "black", "alternateBase": 210, "link": [0,100,255] }, "accents": { "blue": { "button": { "normal": [0,200,255], "inactive": [0,200,255], "disabled": [0,150,200] }, "buttonText": { "normal": "black", "inactive": "black", "disabled": 100 }, "highlight": [0,175,200], "highlightText": "black" }, "green": { "button": { "normal": [36,175,62], "inactive": [36,175,62], "disabled": [0,150,200] }, "buttonText": { "normal": "black", "inactive": "black", "disabled": 100 }, "highlight": [45,220,77], "highlightText": "black" }, "orange": { "button": { "normal": [255,100,0], "inactive": [255,100,0], "disabled": [150,50,0] }, "buttonText": { "normal": "black", "inactive": "black", "disabled": 100 }, "highlight": [255,150,50], "highlightText": "black" }, "pink": { "button": { "normal": [255,0,255], "inactive": [255,0,255], "disabled": [100,0,100] }, "buttonText": { "normal": "black", "inactive": "black", "disabled": 150 }, "highlight": [255,0,255], "highlightText": "black" } } } } ================================================ FILE: platform/platform.pro ================================================ QT += gui gui-private widgets thelib TEMPLATE = lib CONFIG += plugin TARGET = thedesk-platform CONFIG += c++11 unix { # Include the-libs build tools equals(THELIBS_BUILDTOOLS_PATH, "") { THELIBS_BUILDTOOLS_PATH = $$[QT_INSTALL_PREFIX]/share/the-libs/pri } include($$THELIBS_BUILDTOOLS_PATH/gentranslations.pri) include($$THELIBS_BUILDTOOLS_PATH/varset.pri) CONFIG += link_pkgconfig packagesExist(x11) { message("Building with X11 support"); PKGCONFIG += x11 DEFINES += HAVE_X11 QT += x11extras } else { message("X11 not found on this system."); } } # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ cursorhandler.cpp \ fontformat.cpp \ iconloaderengine.cpp \ messagedialog/messagedialog.cpp \ messagedialog/messagedialogcontroller.cpp \ messagedialog/messagedialoghelper.cpp \ paletteformat.cpp \ platformtheme.cpp \ plugin.cpp HEADERS += \ cursorhandler.h \ fontformat.h \ iconloaderengine.h \ messagedialog/messagedialog.h \ messagedialog/messagedialogcontroller.h \ messagedialog/messagedialoghelper.h \ paletteformat.h \ platformtheme.h \ plugin.h DISTFILES += \ palettes.json \ platformdefaults.conf \ plugin.json unix { target.path = $$[QT_INSTALL_PLUGINS]/platformthemes/ translations.path = /usr/share/thedesk/thedesk-platform/translations translations.files = translations/* defaults.files = platformdefaults.conf defaults.path = /etc/theSuite/theDesk/ INSTALLS += target translations defaults } DEFINES += SYSTEM_LIBRARY_DIRECTORY=\\\"$$[QT_INSTALL_LIBS]\\\" RESOURCES += \ thedesk-platform-resources.qrc FORMS += \ messagedialog/messagedialog.ui ================================================ FILE: platform/platformtheme.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "platformtheme.h" #include #include #include #include #include "cursorhandler.h" #include "iconloaderengine.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "messagedialog/messagedialoghelper.h" #include "fontformat.h" #include "paletteformat.h" struct PlatformThemePrivate { QObject* parent; tSettings* settings; QPalette pal; CursorHandler* cursorHandler; QMimeDatabase mimeDb; QMap fonts; QPlatformTheme* flatpakPlatformTheme = nullptr; }; PlatformTheme::PlatformTheme() : QPlatformTheme() { // Register settings locations tSettings::registerDefaults("theSuite", "theDesk.platform", "/usr/share/defaults/thedesk-platform.conf"); d = new PlatformThemePrivate(); d->parent = new QObject(); d->settings = new tSettings("theSuite", "theDesk.platform", d->parent); d->cursorHandler = new CursorHandler(d->parent); d->pal.setResolveMask(std::numeric_limits().max()); QObject::connect(d->settings, &tSettings::settingChanged, d->parent, [=](QString key, QVariant value) { // Qt Creator might crash heh... if (QApplication::applicationName() == "QtCreator") return; if (key.startsWith("Fonts/")) { updateFont(); // Update the font in the application if (qobject_cast(QCoreApplication::instance())) { qApp->setFont(*d->fonts.value(SystemFont)); emit qApp->setFont(*d->fonts.value(SystemFont)); } else if (qobject_cast(QCoreApplication::instance())) { qGuiApp->setFont(*d->fonts.value(SystemFont)); } } else if (key.startsWith("Palette/")) { updatePalette(); // Update the palette in the application if (qobject_cast(QCoreApplication::instance())) { qApp->setPalette(d->pal); emit qApp->paletteChanged(d->pal); } else if (qobject_cast(QCoreApplication::instance())) { qGuiApp->setPalette(d->pal); } } else if (key == "Platform/style") { if (qobject_cast(QCoreApplication::instance())) { qApp->setStyle(d->settings->delimitedList(key).first()); } } }); QScrollerProperties scrollerProperties; scrollerProperties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, 0.1); scrollerProperties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, 0.1); QScrollerProperties::setDefaultScrollerProperties(scrollerProperties); this->updateFont(); this->updatePalette(); tDebug("PlatformTheme") << "Using theDesk platform theme"; // Initialise the Flatpak platform theme so that we can use the portal to open files if (!qEnvironmentVariableIsSet("TD_PLATFORM_NO_FLATPAK_FORWARD")) { d->flatpakPlatformTheme = QPlatformThemeFactory::create("flatpak", nullptr); if (d->flatpakPlatformTheme) { tDebug("PlatformTheme") << "Created Flatpak platform theme"; } } } PlatformTheme::~PlatformTheme() { d->parent->deleteLater(); delete d; } QPlatformMenuItem* PlatformTheme::createPlatformMenuItem() const { return QPlatformTheme::createPlatformMenuItem(); } QPlatformMenu* PlatformTheme::createPlatformMenu() const { return QPlatformTheme::createPlatformMenu(); } QPlatformMenuBar* PlatformTheme::createPlatformMenuBar() const { return QPlatformTheme::createPlatformMenuBar(); } void PlatformTheme::showPlatformMenuBar() { QPlatformTheme::showPlatformMenuBar(); } bool PlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const { switch (type) { case QPlatformTheme::ColorDialog: case QPlatformTheme::FontDialog: return false; case QPlatformTheme::MessageDialog: return true; case QPlatformTheme::FileDialog: if (d->flatpakPlatformTheme) return d->flatpakPlatformTheme->usePlatformNativeDialog(type); return false; } } QPlatformDialogHelper* PlatformTheme::createPlatformDialogHelper(QPlatformTheme::DialogType type) const { switch (type) { case QPlatformTheme::MessageDialog: return new MessageDialogHelper(); case QPlatformTheme::FileDialog: if (d->flatpakPlatformTheme && d->flatpakPlatformTheme->usePlatformNativeDialog(type)) return d->flatpakPlatformTheme->createPlatformDialogHelper(type); return QPlatformTheme::createPlatformDialogHelper(type); case QPlatformTheme::ColorDialog: case QPlatformTheme::FontDialog: return QPlatformTheme::createPlatformDialogHelper(type); } } QPlatformSystemTrayIcon* PlatformTheme::createPlatformSystemTrayIcon() const { return QPlatformTheme::createPlatformSystemTrayIcon(); } const QPalette* PlatformTheme::palette(QPlatformTheme::Palette type) const { // if (type == QPlatformTheme::SystemPalette) return d->pal; // return QPlatformTheme::palette(type); return &d->pal; } const QFont* PlatformTheme::font(QPlatformTheme::Font type) const { if (d->fonts.contains(type)) { return d->fonts.value(type); } else { return d->fonts.value(QPlatformTheme::SystemFont); } // return QPlatformTheme::font(type); } QVariant PlatformTheme::themeHint(QPlatformTheme::ThemeHint hint) const { switch (hint) { case QPlatformTheme::SystemIconThemeName: return d->settings->value("Platform/icons"); case QPlatformTheme::SystemIconFallbackThemeName: return d->settings->value("Platform/icons.fallback"); case QPlatformTheme::StyleNames: return d->settings->delimitedList("Platform/style"); case QPlatformTheme::IconThemeSearchPaths: case QPlatformTheme::IconFallbackSearchPaths: return QStringList({QDir::homePath() + "/.local/share/icons/", "/usr/share/icons", "/var/lib/flatpak/exports/share/icons", QDir::homePath() + "/.local/share/flatpak/exports/share/icons"}); case QPlatformTheme::KeyboardScheme: return KdeKeyboardScheme; case QPlatformTheme::SpellCheckUnderlineStyle: return QTextCharFormat::SingleUnderline; case QPlatformTheme::ItemViewActivateItemOnSingleClick: case QPlatformTheme::DialogButtonBoxButtonsHaveIcons: case QPlatformTheme::ShowShortcutsInContextMenus: case QPlatformTheme::UiEffects: return true; case QPlatformTheme::PasswordMaskCharacter: return QChar(0x2022); case QPlatformTheme::CursorFlashTime: case QPlatformTheme::KeyboardInputInterval: case QPlatformTheme::MouseDoubleClickInterval: case QPlatformTheme::StartDragDistance: case QPlatformTheme::StartDragTime: case QPlatformTheme::KeyboardAutoRepeatRate: case QPlatformTheme::PasswordMaskDelay: case QPlatformTheme::StartDragVelocity: case QPlatformTheme::TextCursorWidth: case QPlatformTheme::DropShadow: case QPlatformTheme::MaximumScrollBarDragDistance: case QPlatformTheme::ToolButtonStyle: case QPlatformTheme::ToolBarIconSize: case QPlatformTheme::WindowAutoPlacement: case QPlatformTheme::DialogButtonBoxLayout: case QPlatformTheme::UseFullScreenForPopupMenu: case QPlatformTheme::TabFocusBehavior: case QPlatformTheme::IconPixmapSizes: case QPlatformTheme::DialogSnapToDefaultButton: case QPlatformTheme::ContextMenuOnMouseRelease: case QPlatformTheme::MousePressAndHoldInterval: case QPlatformTheme::MouseDoubleClickDistance: case QPlatformTheme::WheelScrollLines: case QPlatformTheme::TouchDoubleTapDistance: case QPlatformTheme::MouseQuickSelectionThreshold: default: return QPlatformTheme::themeHint(hint); } } QPixmap PlatformTheme::standardPixmap(QPlatformTheme::StandardPixmap sp, const QSizeF& size) const { return QPlatformTheme::standardPixmap(sp, size); } QIcon PlatformTheme::fileIcon(const QFileInfo& fileInfo, QPlatformTheme::IconOptions iconOptions) const { QMimeType mt = d->mimeDb.mimeTypeForFile(fileInfo); return QIcon::fromTheme(mt.iconName(), QIcon::fromTheme("unknown")); } QIconEngine* PlatformTheme::createIconEngine(const QString& iconName) const { auto iconEngine = QPlatformTheme::createIconEngine(iconName); if (iconEngine) { return new IconLoaderEngine(iconName, iconEngine, nullptr); } return nullptr; } QList PlatformTheme::keyBindings(QKeySequence::StandardKey key) const { return QPlatformTheme::keyBindings(key); } QString PlatformTheme::standardButtonText(int button) const { return QPlatformTheme::standardButtonText(button); } QKeySequence PlatformTheme::standardButtonShortcut(int button) const { return QPlatformTheme::standardButtonShortcut(button); } void PlatformTheme::updatePalette() { QString base = d->settings->value("Palette/base").toString(); QString accent = d->settings->value("Palette/accent").toString(); QFile palettesFile(":/thedesk-platform/palettes.json"); palettesFile.open(QFile::ReadOnly); QJsonDocument doc = QJsonDocument::fromJson(palettesFile.readAll()); QJsonObject rootObj = doc.object(); QJsonObject baseDefinitions; QJsonValue definitions; if (rootObj.contains(base)) { QJsonObject baseObject = rootObj.value(base).toObject(); baseDefinitions = baseObject.value("bases").toObject(); if (baseObject.value("accents").toObject().contains(accent)) { definitions = baseObject.value("accents").toObject().value(accent); } } if (definitions.type() != QJsonValue::Null) { QJsonObject accentDefinitions = definitions.toObject(); // Apply the palette for (QJsonObject obj : { baseDefinitions, accentDefinitions}) { for (auto i = obj.constBegin(); i != obj.constEnd(); i++) { PaletteFormat::applyColor(&d->pal, i.key(), i.value()); } } } } void PlatformTheme::updateFont() { QStringList fonts = d->settings->keysInGroup("Fonts"); for (QString fontTypeStr : fonts) { QPlatformTheme::Font fontType = FontFormat::fontForString(fontTypeStr); QStringList parts = d->settings->value("Fonts/" + fontTypeStr).toStringList(); QFont* font; if (d->fonts.contains(fontType)) { font = d->fonts.value(fontType); font->setFamily(parts.at(0)); } else { font = new QFont(parts.at(0)); d->fonts.insert(fontType, font); } font->setPointSizeF(parts.at(1).toDouble()); } } #if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) PlatformTheme::Appearance PlatformTheme::appearance() const { return PlatformTheme::Appearance::Dark; } #else Qt::ColorScheme PlatformTheme::colorScheme() const { return Qt::ColorScheme::Dark; } #endif ================================================ FILE: platform/platformtheme.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLATFORMTHEME_H #define PLATFORMTHEME_H #include struct PlatformThemePrivate; class PlatformTheme : public QPlatformTheme { public: explicit PlatformTheme(); ~PlatformTheme(); // QPlatformTheme interface public: QPlatformMenuItem* createPlatformMenuItem() const override; QPlatformMenu* createPlatformMenu() const override; QPlatformMenuBar* createPlatformMenuBar() const override; void showPlatformMenuBar() override; bool usePlatformNativeDialog(DialogType type) const override; QPlatformDialogHelper* createPlatformDialogHelper(DialogType type) const override; QPlatformSystemTrayIcon* createPlatformSystemTrayIcon() const override; const QPalette* palette(Palette type) const override; const QFont* font(Font type) const override; QVariant themeHint(ThemeHint hint) const override; QPixmap standardPixmap(StandardPixmap sp, const QSizeF& size) const override; QIcon fileIcon(const QFileInfo& fileInfo, QPlatformTheme::IconOptions iconOptions) const override; QIconEngine* createIconEngine(const QString& iconName) const override; QList keyBindings(QKeySequence::StandardKey key) const override; QString standardButtonText(int button) const override; QKeySequence standardButtonShortcut(int button) const override; #if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) Appearance appearance() const override; #else Qt::ColorScheme colorScheme() const; #endif private: PlatformThemePrivate* d; void updatePalette(); void updateFont(); }; #endif // PLATFORMTHEME_H ================================================ FILE: platform/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "platformtheme.h" Plugin::Plugin(QObject* parent) : QPlatformThemePlugin(parent) { } QPlatformTheme* Plugin::create(const QString& key, const QStringList& paramList) { if (key.toLower() == "thedesk-platform") { return new PlatformTheme(); } return nullptr; } ================================================ FILE: platform/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include class Plugin : public QPlatformThemePlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformThemeFactoryInterface.5.1" FILE "plugin.json") public: explicit Plugin(QObject* parent = nullptr); private: QPlatformTheme* create(const QString& key, const QStringList& paramList); }; #endif // PLUGIN_H ================================================ FILE: platform/plugin.json ================================================ { "Keys": [ "thedesk-platform" ] } ================================================ FILE: platform/psAMLQ.json ================================================ ================================================ FILE: platform/thedesk-platform-resources.qrc ================================================ palettes.json ================================================ FILE: platform/thedesk-platform.conf ================================================ [Platform] style=Contemporary icons=contemporary icons.fallback=breeze cursor=contemporary_cursors cursorSize=24 [Palette] base=dark accent=blue [Fonts] system=Contemporary,10 fixed=Hack,10 ================================================ FILE: platform/translations/ar_SA.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/au_AU.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/cy.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/da.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/de.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/en_GB.ts ================================================ MessageDialog OK OK Save Save Save All Save All Open Open Yes Yes Yes to All Yes to All No No No to All No to All Abort Abort Retry Retry Ignore Ignore Close Close Cancel Cancel Discard Discard Help Help Apply Apply Reset Reset Restore Defaults Restore Defaults Details... DETAILS Back ================================================ FILE: platform/translations/en_US.qm ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/es.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All Sí a todo No No No to All No a todo Abort Retry Ignore Close Cancel Cancellar Discard Help Ayudar Apply Reset Restore Defaults ================================================ FILE: platform/translations/es_VE.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/id.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/nl.ts ================================================ MessageDialog Details... Details... DETAILS DETAILS Back Terug OK OK Save Opslaan Save All Alles Opslaan Open OPenen Yes Ja Yes to All Ja voor Alles No Nee No to All Nee voor Alles Abort Onderbreken Retry Opnieuw Proberen Ignore Negeren Close Sluiten Cancel Annuleren Discard Verwijderen Help Hulp Apply Toepassen Reset Herstellen Restore Defaults Standaarden Herstellen ================================================ FILE: platform/translations/pt_BR.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/ro_RO.ts ================================================ MessageDialog OK OK Save Salvați Save All Salvați tot Open Deschide Yes Da Yes to All Da la tot No Nu No to All Nu la tot Abort Anulează Retry Încearcă din nou Ignore Ignoră Close Închide Cancel Anulare Discard Renunță Help Ajutor Apply Aplică Reset Resetează Restore Defaults Revenire la setările inițiale Details... Detalii... DETAILS DETALII Back Înapoi ================================================ FILE: platform/translations/sv.ts ================================================ MessageDialog Details... DETAILS Back OK Save Save All Open Yes Yes to All No No to All Abort Retry Ignore Close Cancel Discard Help Apply Reset Restore Defaults ================================================ FILE: platform/translations/tr_TR.ts ================================================ MessageDialog OK PEKİ Save Kaydet Save All Hepsini Kaydet Open Yes Evet Yes to All Hepsine Evet No Yok No to All Tümüne yok Abort Vazgeç Retry Yeniden dene Ignore Aldırmamak Close Kapat Cancel İptal Discard Kurtulmak Help Yardımcı Apply Uygulamak Reset Reset Restore Defaults Varsayılanları Geri Yükle Details... Ayrıntı... DETAILS DETAYLAR Back Geri ================================================ FILE: platform/translations/vi.ts ================================================ MessageDialog Details... Chi tiết... DETAILS CHI TIẾT Back Lại OK OK Save Lưu Save All Lưu tất cả Open Mở Yes Yes to All Có với tất cả No Không No to All Không với tất cả Abort Bỏ dở Retry Thử lại Ignore Bỏ qua Close Đóng Cancel Hủy Discard Vứt đi Help Trợ giúp Apply Áp dụng Reset Đặt lại Restore Defaults Đặt về mặc định ================================================ FILE: platform/translations/vi_VN.ts ================================================ MessageDialog Details... Chỉ tiết... DETAILS CHI TIẾT Back Lại OK OK Save Lưu Save All Lưu tất cả Open Mở Yes Yes to All Có cho tất cả No Không No to All Không cho tất cả Abort Hủy bỏ Retry Thủ lại Ignore Bỏ qua Close Đóng Cancel Hủy Discard Bỏ Help Trợ giúp Apply Áp dụng Reset Đặt lại Restore Defaults Hoàn lại mặc định ================================================ FILE: plugins/AccessibilityPlugin/AccessibilityPlugin.pro ================================================ QT += gui widgets TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ accessibilitydaemon.cpp \ chunks/stickykeyschunk.cpp \ plugin.cpp \ settings/accessibilitysettingspane.cpp HEADERS += \ accessibilitydaemon.h \ chunks/stickykeyschunk.h \ plugin.h \ settings/accessibilitysettingspane.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/AccessibilityPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/AccessibilityPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ settings/accessibilitysettingspane.ui ================================================ FILE: plugins/AccessibilityPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) set(SOURCES accessibilitydaemon.cpp chunks/stickykeyschunk.cpp plugin.cpp settings/accessibilitysettingspane.cpp settings/accessibilitysettingspane.ui ) set(HEADERS accessibilitydaemon.h chunks/stickykeyschunk.h plugin.h settings/accessibilitysettingspane.h ) set(PLUGIN_NAME accessibility) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-accessibility.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets libcontemporary libthedesk) ================================================ FILE: plugins/AccessibilityPlugin/Plugin.json ================================================ { "name": "Accessibility Management", "icon": "preferences-desktop-accessibility", "uuid": "e248ffb9-7a7c-452c-95c3-c4ef5cc033c4", "vi": { "name": "Quản lý trở năng" } } ================================================ FILE: plugins/AccessibilityPlugin/accessibilitydaemon.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "accessibilitydaemon.h" #include #include #include #include struct AccessibilityDaemonPrivate { tSettings settings; }; AccessibilityDaemon::AccessibilityDaemon(QObject* parent) : QObject(parent) { d = new AccessibilityDaemonPrivate(); connect(&d->settings, &tSettings::settingChanged, this, &AccessibilityDaemon::updateSetting); for (QString setting : { "Accessibility/stickykeys.active", "Accessibility/mousekeys.active" }) { updateSetting(setting, d->settings.value(setting)); } connect(DesktopWm::accessibility(), &DesktopAccessibility::accessibilityOptionEnabledChanged, this, [ = ](DesktopAccessibility::AccessibilityOption option, bool enabled) { switch (option) { case DesktopAccessibility::StickyKeys: d->settings.setValue("Accessibility/stickykeys.active", enabled); break; case DesktopAccessibility::MouseKeys: d->settings.setValue("Accessibility/mousekeys.active", enabled); break; case DesktopAccessibility::LastAccessibilityOption: break; } }); } AccessibilityDaemon::~AccessibilityDaemon() { delete d; } void AccessibilityDaemon::updateSetting(QString key, QVariant value) { if (key == "Accessibility/stickykeys.active") { DesktopWm::accessibility()->setAccessibilityOptionEnabled(DesktopAccessibility::StickyKeys, value.toBool()); } else if (key == "Accessibility/mousekeys.active") { DesktopWm::accessibility()->setAccessibilityOptionEnabled(DesktopAccessibility::MouseKeys, value.toBool()); } } ================================================ FILE: plugins/AccessibilityPlugin/accessibilitydaemon.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ACCESSIBILITYDAEMON_H #define ACCESSIBILITYDAEMON_H #include struct AccessibilityDaemonPrivate; class AccessibilityDaemon : public QObject { Q_OBJECT public: explicit AccessibilityDaemon(QObject* parent = nullptr); ~AccessibilityDaemon(); signals: private: AccessibilityDaemonPrivate* d; void updateSetting(QString key, QVariant value); }; #endif // ACCESSIBILITYDAEMON_H ================================================ FILE: plugins/AccessibilityPlugin/chunks/stickykeyschunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "stickykeyschunk.h" #include #include #include #include #include #include #include #include struct StickyKeysChunkPrivate { Qt::KeyboardModifiers latched; Qt::KeyboardModifiers locked; ActionQuickWidget* quickWidget; tSettings settings; bool registered = false; }; StickyKeysChunk::StickyKeysChunk() : Chunk() { d = new StickyKeysChunkPrivate(); connect(DesktopWm::accessibility(), &DesktopAccessibility::accessibilityOptionEnabledChanged, this, [this](DesktopAccessibility::AccessibilityOption option, bool enabled) { if (option == DesktopAccessibility::StickyKeys) { updateRegistration(enabled); } }); connect(DesktopWm::accessibility(), &DesktopAccessibility::stickyKeysStateChanged, this, [this](Qt::KeyboardModifiers latched, Qt::KeyboardModifiers locked) { d->latched = latched; d->locked = locked; this->update(); }); d->quickWidget = new ActionQuickWidget(this); d->quickWidget->addAction(tr("Disable Sticky Keys"), [=] { d->settings.setValue("Accessibility/stickykeys.active", false); }); updateRegistration(DesktopWm::accessibility()->isAccessibilityOptionEnabled(DesktopAccessibility::StickyKeys)); } StickyKeysChunk::~StickyKeysChunk() { updateRegistration(false); delete d; } QSize StickyKeysChunk::sizeHint() const { return QSize(16, 16); } void StickyKeysChunk::updateRegistration(bool reg) { if (d->registered == reg) return; if (reg) { StateManager::barManager()->addChunk(this); this->setVisible(true); } else { StateManager::barManager()->removeChunk(this); this->setVisible(false); } d->registered = reg; } QString StickyKeysChunk::name() { return "Accessibility-StickyKeys"; } int StickyKeysChunk::expandedHeight() { return 16; } int StickyKeysChunk::statusBarHeight() { return 16; } void StickyKeysChunk::paintEvent(QPaintEvent* event) { QPainter painter(this); QRect rect; rect.setSize(QSize(16, 16)); rect.moveCenter(QPoint(this->width() / 2, this->height() / 2)); QRect shiftRect; shiftRect.setHeight(rect.height() / 2 - 2); shiftRect.setWidth(rect.width() - 6); shiftRect.moveTopLeft(rect.topLeft() + QPoint(2, 2)); QRect ctrlRect; ctrlRect.setHeight(shiftRect.height()); ctrlRect.setWidth(4); ctrlRect.moveTop(shiftRect.bottom() + 1); ctrlRect.moveLeft(shiftRect.left()); QRect superRect = ctrlRect; superRect.moveLeft(ctrlRect.right() + 1); QRect altRect = superRect; altRect.moveLeft(superRect.right() + 1); painter.setPen(this->palette().color(QPalette::WindowText)); painter.setBrush(Qt::transparent); painter.drawRect(shiftRect); painter.drawRect(ctrlRect); painter.drawRect(superRect); painter.drawRect(altRect); painter.setPen(Qt::transparent); painter.setBrush(this->palette().color(QPalette::WindowText)); if (d->locked & Qt::ShiftModifier || d->latched & Qt::ShiftModifier) { painter.drawRect(shiftRect); } if (d->locked & Qt::ControlModifier || d->latched & Qt::ControlModifier) { painter.drawRect(ctrlRect); } if (d->locked & Qt::MetaModifier || d->latched & Qt::MetaModifier) { painter.drawRect(superRect); } if (d->locked & Qt::AltModifier || d->latched & Qt::AltModifier) { painter.drawRect(altRect); } } QWidget* StickyKeysChunk::quickWidget() { return d->quickWidget; } ================================================ FILE: plugins/AccessibilityPlugin/chunks/stickykeyschunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef STICKYKEYSCHUNK_H #define STICKYKEYSCHUNK_H #include struct StickyKeysChunkPrivate; class StickyKeysChunk : public Chunk { Q_OBJECT public: explicit StickyKeysChunk(); ~StickyKeysChunk(); QSize sizeHint() const; signals: private: StickyKeysChunkPrivate* d; void updateRegistration(bool reg); // Chunk interface public: QString name(); int expandedHeight(); int statusBarHeight(); protected: QWidget* quickWidget(); // QWidget interface protected: void paintEvent(QPaintEvent* event); }; #endif // STICKYKEYSCHUNK_H ================================================ FILE: plugins/AccessibilityPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include #include #include #include #include #include #include #include #include #include "accessibilitydaemon.h" #include "chunks/stickykeyschunk.h" #include "settings/accessibilitysettingspane.h" struct PluginPrivate { AccessibilitySettingsPane* settingsPane; AccessibilityDaemon* daemon; StickyKeysChunk* stickyKeysChunk; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/AccessibilityPlugin/thedesk-accessibility.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-accessibility.conf"); d->daemon = new AccessibilityDaemon(); d->stickyKeysChunk = new StickyKeysChunk(); d->settingsPane = new AccessibilitySettingsPane(); StateManager::statusCenterManager()->addPane(d->settingsPane, StatusCenterManager::SystemSettings); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->settingsPane); d->settingsPane->deleteLater(); d->stickyKeysChunk->deleteLater(); d->daemon->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/AccessibilityPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/AccessibilityPlugin/settings/accessibilitysettingspane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "accessibilitysettingspane.h" #include "ui_accessibilitysettingspane.h" #include #include #include #include struct AccessibilitySettingsPanePrivate { tSettings settings; }; AccessibilitySettingsPane::AccessibilitySettingsPane() : StatusCenterPane(), ui(new Ui::AccessibilitySettingsPane) { ui->setupUi(this); d = new AccessibilitySettingsPanePrivate(); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->typingWidget->setFixedWidth(contentWidth); ui->pointingWidget->setFixedWidth(contentWidth); connect(&d->settings, &tSettings::settingChanged, this, &AccessibilitySettingsPane::updateSetting); for (QString setting : { "Accessibility/stickykeys.active", "Accessibility/mousekeys.active" }) { updateSetting(setting, d->settings.value(setting)); } } AccessibilitySettingsPane::~AccessibilitySettingsPane() { delete d; delete ui; } QString AccessibilitySettingsPane::name() { return "AccessibilitySettings"; } QString AccessibilitySettingsPane::displayName() { return tr("Accessibility"); } QIcon AccessibilitySettingsPane::icon() { return QIcon::fromTheme("preferences-desktop-accessibility"); } QWidget* AccessibilitySettingsPane::leftPane() { return nullptr; } void AccessibilitySettingsPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void AccessibilitySettingsPane::on_stickyKeysSwitch_toggled(bool checked) { d->settings.setValue("Accessibility/stickykeys.active", checked); } void AccessibilitySettingsPane::updateSetting(QString key, QVariant value) { if (key == "Accessibility/stickykeys.active") { ui->stickyKeysSwitch->setChecked(value.toBool()); } else if (key == "Accessibility/mousekeys.active") { ui->mouseKeysSwitch->setChecked(value.toBool()); } } void AccessibilitySettingsPane::on_mouseKeysSwitch_toggled(bool checked) { d->settings.setValue("Accessibility/mousekeys.active", checked); } void AccessibilitySettingsPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/AccessibilityPlugin/settings/accessibilitysettingspane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ACCESSIBILITYSETTINGSPANE_H #define ACCESSIBILITYSETTINGSPANE_H #include namespace Ui { class AccessibilitySettingsPane; } struct AccessibilitySettingsPanePrivate; class AccessibilitySettingsPane : public StatusCenterPane { Q_OBJECT public: explicit AccessibilitySettingsPane(); ~AccessibilitySettingsPane(); private slots: void on_titleLabel_backButtonClicked(); void on_stickyKeysSwitch_toggled(bool checked); void on_mouseKeysSwitch_toggled(bool checked); private: Ui::AccessibilitySettingsPane* ui; AccessibilitySettingsPanePrivate* d; void updateSetting(QString key, QVariant value); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // ACCESSIBILITYSETTINGSPANE_H ================================================ FILE: plugins/AccessibilityPlugin/settings/accessibilitysettingspane.ui ================================================ AccessibilitySettingsPane 0 0 781 323 Form 0 0 0 0 0 Accessibility QFrame::NoFrame true 0 0 781 306 0 0 0 0 0 0 0 Sticky Keys StickyKeysSwitch 75 true TYPING false Allows you to press modifier keys sequentially true 16777215 1 Qt::Horizontal 75 true POINTING MouseKeysSwitch Mouse Keys false Allows you to move the cursor using the number pad true Qt::Vertical 20 101 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tSwitch QPushButton
tswitch.h
================================================ FILE: plugins/AccessibilityPlugin/thedesk-accessibility.conf ================================================ [Accessibility] stickykeys.active=false mousekeys.active=false ================================================ FILE: plugins/AccessibilityPlugin/translations/ar_SA.ts ================================================ AccessibilitySettingsPane Accessibility سهولة الأستخدام Sticky Keys مفاتيح الملتصقه TYPING الكابه Allows you to press modifier keys sequentially يسمح لك بالضغط مفاتيح التعديل وره بعد POINTING تحدد إلى Mouse Keys مفاتيح الماوس Allows you to move the cursor using the number pad يسمح لك بتحريك المؤشر باستخدام لوحة الأرقام StickyKeysChunk Disable Sticky Keys ايقاف المفاتيح الملتصقه ================================================ FILE: plugins/AccessibilityPlugin/translations/au_AU.ts ================================================ AccessibilitySettingsPane Accessibility Sticky Keys TYPING Allows you to press modifier keys sequentially POINTING Mouse Keys Allows you to move the cursor using the number pad StickyKeysChunk Disable Sticky Keys ================================================ FILE: plugins/AccessibilityPlugin/translations/cy.ts ================================================ AccessibilitySettingsPane Accessibility Sticky Keys TYPING Allows you to press modifier keys sequentially POINTING Mouse Keys Allows you to move the cursor using the number pad StickyKeysChunk Disable Sticky Keys ================================================ FILE: plugins/AccessibilityPlugin/translations/da.ts ================================================ AccessibilitySettingsPane Accessibility Sticky Keys TYPING Allows you to press modifier keys sequentially POINTING Mouse Keys Allows you to move the cursor using the number pad StickyKeysChunk Disable Sticky Keys ================================================ FILE: plugins/AccessibilityPlugin/translations/de.ts ================================================ AccessibilitySettingsPane Accessibility Barrrierefreiheit Sticky Keys Sticky Keys TYPING TIPPEN Allows you to press modifier keys sequentially Lässt dich mehrere Modifikatortasten hintereinander drücken POINTING MAUSZEIGER Mouse Keys Mouse Keys Allows you to move the cursor using the number pad Lässt dich den Mauscursor mit dem Ziffernblock steuern StickyKeysChunk Disable Sticky Keys Sticky Keys deaktivieren ================================================ FILE: plugins/AccessibilityPlugin/translations/en_US.qm ================================================ AccessibilitySettingsPane Accessibility Sticky Keys TYPING Allows you to press modifier keys sequentially POINTING Mouse Keys Allows you to move the cursor using the number pad StickyKeysChunk Disable Sticky Keys ================================================ FILE: plugins/AccessibilityPlugin/translations/es.ts ================================================ AccessibilitySettingsPane Accessibility Accesibilidad Sticky Keys TYPING Allows you to press modifier keys sequentially POINTING Mouse Keys Allows you to move the cursor using the number pad StickyKeysChunk Disable Sticky Keys ================================================ FILE: plugins/AccessibilityPlugin/translations/es_VE.ts ================================================ AccessibilitySettingsPane Accessibility Accesibilidad Sticky Keys TYPING teclando Allows you to press modifier keys sequentially The permite presar las teclas modificadoras de la forma secuencial POINTING apuntar Mouse Keys teclas del mouse Allows you to move the cursor using the number pad De deja mover su el cursor con el teclado numérico StickyKeysChunk Disable Sticky Keys Deshabilitar las Teclas Adhesivas ================================================ FILE: plugins/AccessibilityPlugin/translations/id.ts ================================================ AccessibilitySettingsPane Accessibility Aksesibilitas Sticky Keys TYPING Allows you to press modifier keys sequentially POINTING Mouse Keys Allows you to move the cursor using the number pad StickyKeysChunk Disable Sticky Keys ================================================ FILE: plugins/AccessibilityPlugin/translations/ja.ts ================================================ AccessibilitySettingsPane Accessibility Sticky Keys TYPING Allows you to press modifier keys sequentially POINTING Mouse Keys Allows you to move the cursor using the number pad StickyKeysChunk Disable Sticky Keys ================================================ FILE: plugins/AccessibilityPlugin/translations/nl.ts ================================================ AccessibilitySettingsPane Accessibility Toegankelijkheid Sticky Keys Plaktoetsen TYPING TYPEN Allows you to press modifier keys sequentially Laat je speciale toetsen achter elkaar indrukken POINTING AANWIJZEN Mouse Keys Muistoetsen Allows you to move the cursor using the number pad Laat je de cursor bewegen met het nummerieke toetsenbord StickyKeysChunk Disable Sticky Keys Plaktoetsen Uitschakelen ================================================ FILE: plugins/AccessibilityPlugin/translations/pt_BR.ts ================================================ AccessibilitySettingsPane Accessibility Acessibilidade Sticky Keys Teclas aderentes TYPING TECLADO Allows you to press modifier keys sequentially Permite apertar teclas modificadores em sequência POINTING MOUSE Mouse Keys Teclas do mouse Allows you to move the cursor using the number pad Permite mover o cursor do mouse usando o teclado numérico StickyKeysChunk Disable Sticky Keys Desativar teclas aderentes ================================================ FILE: plugins/AccessibilityPlugin/translations/ro.ts ================================================ AccessibilitySettingsPane Accessibility Accesibilitate Sticky Keys Taste persistente TYPING TASTARE Allows you to press modifier keys sequentially Vă permite să apăsați secvențial tastele modificator POINTING INDICARE Mouse Keys Mouse din tastatură Allows you to move the cursor using the number pad Vă permite să mutați cursorul cu ajutorul tastaturii numerice StickyKeysChunk Disable Sticky Keys Dezactivați tastele persistente ================================================ FILE: plugins/AccessibilityPlugin/translations/sv.ts ================================================ AccessibilitySettingsPane Accessibility Sticky Keys TYPING Allows you to press modifier keys sequentially POINTING Mouse Keys Allows you to move the cursor using the number pad StickyKeysChunk Disable Sticky Keys ================================================ FILE: plugins/AccessibilityPlugin/translations/tr.ts ================================================ AccessibilitySettingsPane Accessibility Ulaşılabilirlik Sticky Keys Yapışkan Tuşlar TYPING YAZIYOR Allows you to press modifier keys sequentially Değiştirici tuşlara sırayla basmanıza izin verir POINTING PUANLAMA Mouse Keys Mouse Tuşları Allows you to move the cursor using the number pad Sayısal tuş takımını kullanarak imleci hareket ettirmenize izin verir StickyKeysChunk Disable Sticky Keys Yapışkan Tuşları Devre Dışı Bırak ================================================ FILE: plugins/AccessibilityPlugin/translations/vi.ts ================================================ AccessibilitySettingsPane Accessibility Trở nặng Sticky Keys Phím dính TYPING ĐÁNH MÁY Allows you to press modifier keys sequentially Cho bạn nhấn các phím bổ trợ liên tiếp POINTING CHỈ TRỎ Mouse Keys Phím chuột Allows you to move the cursor using the number pad Cho bạn di chuyển chuột sử dụng bàn phím số StickyKeysChunk Disable Sticky Keys Tắt phím dính ================================================ FILE: plugins/AccessibilityPlugin/translations/vi_VN.ts ================================================ AccessibilitySettingsPane Accessibility Khả năng Sticky Keys Phím dính TYPING ĐÁNH MÁY Allows you to press modifier keys sequentially Cho phép bạn nhấn các phím bổ trợ liên tục thay vì song song POINTING CHỈ TRỎ Mouse Keys Phím chuột Allows you to move the cursor using the number pad Cho phép bạn di chuyển con trỏ bằng bàn phím số StickyKeysChunk Disable Sticky Keys Tất phím dính ================================================ FILE: plugins/AudioPlugin/AudioPlugin.pro ================================================ QT += gui widgets TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) LIBS += -lKF5PulseAudioQt INCLUDEPATH += /usr/include/KF5/KF5PulseAudioQt/PulseAudioQt # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ audiochunk.cpp \ audioquickwidget.cpp \ common.cpp \ eventhandler.cpp \ micchunk.cpp \ plugin.cpp \ quickwidgetsink.cpp \ quickwidgetsinkinput.cpp HEADERS += \ audiochunk.h \ audioquickwidget.h \ common.h \ eventhandler.h \ micchunk.h \ plugin.h \ quickwidgetsink.h \ quickwidgetsinkinput.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/AudioPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/AudioPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ audioquickwidget.ui \ quickwidgetsink.ui \ quickwidgetsinkinput.ui ================================================ FILE: plugins/AudioPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.4.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) find_package(KF${KF_VERSION_MAJOR}PulseAudioQt REQUIRED) set(SOURCES audiochunk.cpp audioquickwidget.cpp common.cpp eventhandler.cpp micchunk.cpp plugin.cpp quickwidgetsink.cpp quickwidgetsinkinput.cpp ) set(HEADERS audiochunk.h audioquickwidget.h common.h eventhandler.h micchunk.h plugin.h quickwidgetsink.h quickwidgetsinkinput.h ) set(PLUGIN_NAME pulseaudio) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-audio.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt${QT_VERSION_MAJOR}::Widgets KF${KF_VERSION_MAJOR}::PulseAudioQt libcontemporary libthedesk) ================================================ FILE: plugins/AudioPlugin/Plugin.json ================================================ { "name": "Audio Management", "icon": "preferences-desktop-audio", "uuid": "6a978f09-c3f4-4843-b32f-4e377ed6cd0f", "vi": { "name": "Quản lý âm thanh" } } ================================================ FILE: plugins/AudioPlugin/audiochunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "audiochunk.h" #include #include #include #include "audioquickwidget.h" struct AudioChunkPrivate { AudioQuickWidget* qw = new AudioQuickWidget(); }; AudioChunk::AudioChunk() : IconTextChunk("audio") { d = new AudioChunkPrivate(); connect(StateManager::quietModeManager(), &QuietModeManagerTd::quietModeChanged, this, &AudioChunk::updateData); updateData(); d->qw = new AudioQuickWidget(); this->setQuickWidget(d->qw); } AudioChunk::~AudioChunk() { d->qw->deleteLater(); delete d; } void AudioChunk::updateData() { this->setIcon(QIcon::fromTheme(QuietModeManagerTd::icon(StateManager::quietModeManager()->currentMode()))); this->setText(QuietModeManagerTd::name(StateManager::quietModeManager()->currentMode())); } ================================================ FILE: plugins/AudioPlugin/audiochunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef AUDIOCHUNK_H #define AUDIOCHUNK_H #include struct AudioChunkPrivate; class AudioChunk : public IconTextChunk { Q_OBJECT public: explicit AudioChunk(); ~AudioChunk(); signals: private: AudioChunkPrivate* d; void updateData(); }; #endif // AUDIOCHUNK_H ================================================ FILE: plugins/AudioPlugin/audioquickwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "audioquickwidget.h" #include "ui_audioquickwidget.h" #include #include #include #include #include "quickwidgetsink.h" #include "quickwidgetsinkinput.h" #include struct AudioQuickWidgetPrivate { QScreen* primaryScreen = nullptr; QMap sinkWidgets; QMap sinkInputWidgets; }; AudioQuickWidget::AudioQuickWidget(QWidget* parent) : QWidget(parent), ui(new Ui::AudioQuickWidget) { ui->setupUi(this); d = new AudioQuickWidgetPrivate(); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkAdded, this, &AudioQuickWidget::sinkAdded); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkRemoved, this, &AudioQuickWidget::sinkRemoved); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkInputAdded, this, &AudioQuickWidget::sinkInputAdded); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkInputRemoved, this, &AudioQuickWidget::sinkInputRemoved); for (PulseAudioQt::Sink* sink : PulseAudioQt::Context::instance()->sinks()) sinkAdded(sink); for (PulseAudioQt::SinkInput* sinkInput : PulseAudioQt::Context::instance()->sinkInputs()) sinkInputAdded(sinkInput); ui->sinkInputsWidget->setVisible(false); for (QuietModeManagerTd::QuietMode mode : StateManager::quietModeManager()->availableQuietModes()) { QuietModeManagerTd::QuietMode m = mode; QPushButton* button = new QPushButton(this); button->setText(StateManager::quietModeManager()->name(m)); button->setIcon(QIcon::fromTheme(StateManager::quietModeManager()->icon(m))); button->setCheckable(true); button->setAutoExclusive(true); button->setChecked(StateManager::quietModeManager()->currentMode() == m); connect(button, &QPushButton::toggled, this, [=](bool checked) { if (checked) { StateManager::quietModeManager()->setQuietMode(m); } }); connect(StateManager::quietModeManager(), &QuietModeManagerTd::quietModeChanged, this, [=](QuietModeManagerTd::QuietMode newMode, QuietModeManagerTd::QuietMode oldMode) { Q_UNUSED(oldMode); button->setChecked(newMode == m); }); ui->quietModesLayout->addWidget(button); } connect(qApp, &QApplication::primaryScreenChanged, this, &AudioQuickWidget::updatePrimaryScreen); updatePrimaryScreen(); } AudioQuickWidget::~AudioQuickWidget() { delete ui; delete d; } QSize AudioQuickWidget::sizeHint() const { QSize sizeHint = ui->scrollAreaWidgetContents->sizeHint(); if (sizeHint.height() > this->maximumHeight()) sizeHint.setHeight(this->maximumHeight()); return sizeHint; } void AudioQuickWidget::sinkAdded(PulseAudioQt::Sink* sink) { QuickWidgetSink* sinkWidget = new QuickWidgetSink(sink); sinkWidget->installEventFilter(this); ui->sinksLayout->addWidget(sinkWidget); d->sinkWidgets.insert(sink, sinkWidget); } void AudioQuickWidget::sinkRemoved(PulseAudioQt::Sink* sink) { QuickWidgetSink* sinkWidget = d->sinkWidgets.take(sink); ui->sinksLayout->removeWidget(sinkWidget); sinkWidget->setVisible(false); sinkWidget->deleteLater(); } void AudioQuickWidget::sinkInputAdded(PulseAudioQt::SinkInput* sinkInput) { QuickWidgetSinkInput* sinkInputWidget = new QuickWidgetSinkInput(sinkInput); sinkInputWidget->installEventFilter(this); ui->sinkInputsLayout->addWidget(sinkInputWidget); d->sinkInputWidgets.insert(sinkInput, sinkInputWidget); ui->sinkInputsWidget->setVisible(true); } void AudioQuickWidget::sinkInputRemoved(PulseAudioQt::SinkInput* sinkInput) { QuickWidgetSinkInput* sinkInputWidget = d->sinkInputWidgets.take(sinkInput); ui->sinksLayout->removeWidget(sinkInputWidget); sinkInputWidget->setVisible(false); sinkInputWidget->deleteLater(); if (d->sinkInputWidgets.isEmpty()) ui->sinkInputsWidget->setVisible(false); } bool AudioQuickWidget::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Show || event->type() == QEvent::Hide) { this->updateGeometry(); QEvent* event = new QEvent(QEvent::LayoutRequest); qApp->postEvent(this, event); } return false; } void AudioQuickWidget::updatePrimaryScreen() { if (d->primaryScreen) d->primaryScreen->disconnect(this); d->primaryScreen = qApp->primaryScreen(); connect(d->primaryScreen, &QScreen::geometryChanged, this, &AudioQuickWidget::updateMaxHeight); updateMaxHeight(); } void AudioQuickWidget::updateMaxHeight() { this->setMaximumHeight(d->primaryScreen->geometry().height() * 0.7); } ================================================ FILE: plugins/AudioPlugin/audioquickwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef AUDIOQUICKWIDGET_H #define AUDIOQUICKWIDGET_H #include #include #include namespace Ui { class AudioQuickWidget; } struct AudioQuickWidgetPrivate; class AudioQuickWidget : public QWidget { Q_OBJECT public: explicit AudioQuickWidget(QWidget* parent = nullptr); ~AudioQuickWidget(); QSize sizeHint() const; void sinkAdded(PulseAudioQt::Sink* sink); void sinkRemoved(PulseAudioQt::Sink* sink); void sinkInputAdded(PulseAudioQt::SinkInput* sinkInput); void sinkInputRemoved(PulseAudioQt::SinkInput* sinkInput); private: Ui::AudioQuickWidget* ui; AudioQuickWidgetPrivate* d; bool eventFilter(QObject* watched, QEvent* event); void updatePrimaryScreen(); void updateMaxHeight(); }; #endif // AUDIOQUICKWIDGET_H ================================================ FILE: plugins/AudioPlugin/audioquickwidget.ui ================================================ AudioQuickWidget 0 0 366 238 Form 0 0 0 0 0 QFrame::NoFrame true 0 0 366 238 75 true VOLUME 0 0 0 0 75 true APPLICATIONS 75 true QUIET MODE 0 ================================================ FILE: plugins/AudioPlugin/common.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "common.h" #include #include Common::DevicePort Common::portForSink(PulseAudioQt::Sink* sink) { QVariantMap properties = sink->properties(); QString api = properties.value("device.api").toString(); if (api == QStringLiteral("bluez")) { return Bluetooth; } else { if (sink->ports().count() <= sink->activePortIndex()) return Unknown; PulseAudioQt::Port* port = sink->ports().at(sink->activePortIndex()); if (port->availability() == PulseAudioQt::Port::Unavailable) { // Weird thing? Use a workaround here QList availablePorts; for (PulseAudioQt::Port* port : sink->ports()) { if (port->availability() != PulseAudioQt::Port::Unavailable) availablePorts.append(port); } if (availablePorts.count() == 1) { port = availablePorts.first(); } else { port = nullptr; } } if (port != nullptr) { QString newPort; if (port->name().contains("headphones", Qt::CaseInsensitive)) { return Headphones; } else if (port->name().contains("speaker", Qt::CaseInsensitive)) { return Speakers; } else if (port->name().contains("lineout", Qt::CaseInsensitive)) { return LineOut; } } return Unknown; } } QString Common::nameForSink(PulseAudioQt::Sink* sink) { QVariantMap properties = sink->properties(); QString api = properties.value("device.api").toString(); if (api == QStringLiteral("alsa")) { return properties.value("device.product.name", properties.value("node.nick")).toString(); } else if (api == QStringLiteral("bluez")) { return properties.value("bluez.alias").toString(); } else { return sink->description(); } } ================================================ FILE: plugins/AudioPlugin/common.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef COMMON_H #define COMMON_H #include namespace Common { enum DevicePort { Speakers, Headphones, LineOut, Bluetooth, Unknown }; DevicePort portForSink(PulseAudioQt::Sink* sink); QString nameForSink(PulseAudioQt::Sink* sink); } // namespace Common #endif // COMMON_H ================================================ FILE: plugins/AudioPlugin/eventhandler.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "eventhandler.h" #include "common.h" #include #include #include #include #include #include #include #include struct EventHandlerPrivate { KeyGrab* volumeUp; KeyGrab* volumeDown; KeyGrab* volumeMute; PulseAudioQt::Sink* defaultSink = nullptr; bool firstSink = true; quint32 oldActivePortIndex; }; EventHandler::EventHandler(QObject* parent) : QObject(parent) { d = new EventHandlerPrivate(); connect(PulseAudioQt::Context::instance()->server(), &PulseAudioQt::Server::defaultSinkChanged, this, &EventHandler::defaultSinkChanged); defaultSinkChanged(PulseAudioQt::Context::instance()->server()->defaultSink()); d->volumeUp = new KeyGrab(QKeySequence(Qt::Key_VolumeUp), "volumeUp"); d->volumeDown = new KeyGrab(QKeySequence(Qt::Key_VolumeDown), "volumeDown"); d->volumeMute = new KeyGrab(QKeySequence(Qt::Key_VolumeMute), "volumeMute"); connect(d->volumeUp, &KeyGrab::activated, this, [=] { this->adjustVolume(5); }); connect(d->volumeDown, &KeyGrab::activated, this, [=] { this->adjustVolume(-5); }); connect(d->volumeMute, &KeyGrab::activated, this, [=] { QuietModeManagerTd::QuietMode newMode = StateManager::quietModeManager()->nextQuietMode(); StateManager::quietModeManager()->setQuietMode(newMode); StateManager::instance()->hudManager()->showHud({ {"icon", StateManager::quietModeManager()->icon(newMode) }, {"title", StateManager::quietModeManager()->name(newMode) }, {"text", StateManager::quietModeManager()->description(newMode)} }); }); connect(StateManager::quietModeManager(), &QuietModeManagerTd::quietModeChanged, this, &EventHandler::quietModeChanged); quietModeChanged(); } EventHandler::~EventHandler() { d->volumeUp->deleteLater(); d->volumeDown->deleteLater(); d->volumeMute->deleteLater(); delete d; } void EventHandler::adjustVolume(int percentageChange) { if (StateManager::quietModeManager()->currentMode() == QuietModeManagerTd::Mute) { showHud(nullptr); return; } // Get the default sink and find the widget for this sink PulseAudioQt::Sink* sink = PulseAudioQt::Context::instance()->server()->defaultSink(); if (!sink) { StateManager::instance()->hudManager()->showHud({ {"icon", "audio-volume-muted" }, {"title", tr("No Audio Devices")} }); return; } qint64 factor = PulseAudioQt::normalVolume(); qint64 newVolume = sink->volume() + (factor / 100) * percentageChange; if (newVolume < PulseAudioQt::minimumVolume()) newVolume = PulseAudioQt::minimumVolume(); sink->setVolume(newVolume); showHud(sink, newVolume); } void EventHandler::defaultSinkChanged(PulseAudioQt::Sink* defaultSink) { if (d->defaultSink == defaultSink) return; if (d->defaultSink) { d->defaultSink->disconnect(this); } d->defaultSink = defaultSink; if (defaultSink) { connect(defaultSink, &PulseAudioQt::Sink::activePortIndexChanged, this, [=] { if (d->oldActivePortIndex != defaultSink->activePortIndex()) { d->oldActivePortIndex = defaultSink->activePortIndex(); showHud(defaultSink); } }); d->oldActivePortIndex = defaultSink->activePortIndex(); if (d->firstSink) { d->firstSink = false; } else { showHud(defaultSink); } } } void EventHandler::showHud(PulseAudioQt::Sink* sink, qint64 volume) { if (StateManager::quietModeManager()->currentMode() == QuietModeManagerTd::Mute) { StateManager::instance()->hudManager()->showHud({ {"icon", StateManager::quietModeManager()->icon(QuietModeManagerTd::Mute)}, {"title", tr("Mute") }, {"text", tr("Unmute Quiet Mode before changing the volume") } }); return; } double displayVolume; if (volume == -1) { displayVolume = sink->volume() / static_cast(PulseAudioQt::normalVolume()); } else { displayVolume = volume / static_cast(PulseAudioQt::normalVolume()); } QVariantMap hudData; hudData.insert("value", displayVolume); switch (Common::portForSink(sink)) { case Common::Speakers: hudData.insert("icon", "audio-volume-high"); hudData.insert("title", tr("Speakers")); break; case Common::Headphones: hudData.insert("icon", "audio-headphones"); hudData.insert("title", tr("Headphones")); break; case Common::LineOut: hudData.insert("icon", "audio-lineout"); hudData.insert("title", tr("Line Out")); break; case Common::Bluetooth: hudData.insert("icon", "bluetooth"); hudData.insert("title", Common::nameForSink(sink)); break; case Common::Unknown: hudData.insert("icon", "audio-volume-high"); hudData.insert("title", tr("Volume")); break; } StateManager::instance()->hudManager()->showHud(hudData); } void EventHandler::quietModeChanged() { QuietModeManagerTd::QuietMode mode = StateManager::quietModeManager()->currentMode(); QVector sinks = PulseAudioQt::Context::instance()->sinks(); for (PulseAudioQt::Sink* sink : sinks) { sink->setMuted(mode == QuietModeManagerTd::Mute); } } ================================================ FILE: plugins/AudioPlugin/eventhandler.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYHANDLER_H #define KEYHANDLER_H #include namespace PulseAudioQt { class Sink; } struct EventHandlerPrivate; class EventHandler : public QObject { Q_OBJECT public: explicit EventHandler(QObject* parent = nullptr); ~EventHandler(); signals: private: EventHandlerPrivate* d; void adjustVolume(int percentageChange); void defaultSinkChanged(PulseAudioQt::Sink* defaultSink); void showHud(PulseAudioQt::Sink* sink, qint64 volume = -1); void quietModeChanged(); }; #endif // KEYHANDLER_H ================================================ FILE: plugins/AudioPlugin/micchunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "micchunk.h" #include #include #include #include #include #include MicChunk::MicChunk() : IconTextChunk("audio-mic") { connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sourceOutputAdded, this, &MicChunk::sourceOutputAdded); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sourceOutputRemoved, this, &MicChunk::updateSourceOutputs); for (PulseAudioQt::SourceOutput* output : PulseAudioQt::Context::instance()->sourceOutputs()) sourceOutputAdded(output); updateSourceOutputs(); } void MicChunk::sourceOutputAdded(PulseAudioQt::SourceOutput* sourceOutput) { connect(sourceOutput, &PulseAudioQt::SourceOutput::clientChanged, this, &MicChunk::updateSourceOutputs); connect(sourceOutput, &PulseAudioQt::SourceOutput::mutedChanged, this, &MicChunk::updateSourceOutputs); connect(sourceOutput, &PulseAudioQt::SourceOutput::propertiesChanged, this, &MicChunk::updateSourceOutputs); updateSourceOutputs(); } void MicChunk::updateSourceOutputs() { bool micMuted = true; QStringList micClients; for (PulseAudioQt::SourceOutput* output : PulseAudioQt::Context::instance()->sourceOutputs()) { if (!output->isMuted()) micMuted = false; micClients.append(output->properties().value("application.name").toString()); // if (output->client()) { // micClients.append(output->client()->name()); // } else { // micClients.append(this->fontMetrics().elidedText(output->name(), Qt::ElideRight, SC_DPI(100))); // } } micClients.removeDuplicates(); if (micClients.isEmpty()) { if (StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->removeChunk(this); } else { this->setIcon(QIcon::fromTheme(micMuted ? "mic-off" : "mic-on")); if (micClients.count() == 1) { this->setText(micClients.first()); } else { this->setText(tr("%n applications", nullptr, micClients.count())); } if (!StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->addChunk(this); } } ================================================ FILE: plugins/AudioPlugin/micchunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MICCHUNK_H #define MICCHUNK_H #include #include class MicChunk : public IconTextChunk { Q_OBJECT public: explicit MicChunk(); signals: private: void sourceOutputAdded(PulseAudioQt::SourceOutput* sourceOutput); void updateSourceOutputs(); }; #endif // MICCHUNK_H ================================================ FILE: plugins/AudioPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "audiochunk.h" #include "eventhandler.h" #include "micchunk.h" #include #include #include #include #include #include #include #include #include struct PluginPrivate { EventHandler* keyHandler; AudioChunk* chunk; MicChunk* micChunk; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/AudioPlugin/thedesk-audio.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-audio.conf"); d->keyHandler = new EventHandler(); d->chunk = new AudioChunk(); StateManager::barManager()->addChunk(d->chunk); d->micChunk = new MicChunk(); } void Plugin::deactivate() { d->micChunk->deleteLater(); StateManager::barManager()->removeChunk(d->chunk); d->chunk->deleteLater(); d->keyHandler->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/AudioPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/AudioPlugin/quickwidgetsink.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "quickwidgetsink.h" #include "ui_quickwidgetsink.h" #include "common.h" #include #include #include #include #include struct QuickWidgetSinkPrivate { PulseAudioQt::Sink* sink; bool changingVolume = false; QMenu* menu; }; QuickWidgetSink::QuickWidgetSink(PulseAudioQt::Sink* sink, QWidget* parent) : QWidget(parent), ui(new Ui::QuickWidgetSink) { ui->setupUi(this); d = new QuickWidgetSinkPrivate(); d->sink = sink; connect(PulseAudioQt::Context::instance()->server(), &PulseAudioQt::Server::defaultSinkChanged, this, &QuickWidgetSink::updateDefault, Qt::QueuedConnection); updateDefault(); connect(sink, &PulseAudioQt::Sink::volumeChanged, this, &QuickWidgetSink::updateVolume); connect(sink, &PulseAudioQt::Sink::propertiesChanged, this, &QuickWidgetSink::updateName); updateVolume(); updateName(); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkInputAdded, this, &QuickWidgetSink::sinkInputAdded); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkInputRemoved, this, &QuickWidgetSink::updateVisibility); for (PulseAudioQt::SinkInput* sinkInput : PulseAudioQt::Context::instance()->sinkInputs()) sinkInputAdded(sinkInput); updateVisibility(); this->setFixedWidth(SC_DPI(600)); ui->nameLabel->setFixedWidth(SC_DPI(200)); d->menu = new QMenu(); d->menu->addAction(ui->actionMake_Default); d->menu->addAction(ui->actionMove_All_Applications); ui->menuButton->setMenu(d->menu); } QuickWidgetSink::~QuickWidgetSink() { delete d; delete ui; } void QuickWidgetSink::updateVolume() { if (d->changingVolume) return; int volume = d->sink->volume() / static_cast(PulseAudioQt::normalVolume()) * 100; QSignalBlocker blocker(ui->volumeSlider); ui->volumeSlider->setValue(volume); } void QuickWidgetSink::updateDefault() { ui->actionMake_Default->setVisible(PulseAudioQt::Context::instance()->server()->defaultSink() != d->sink); updateVisibility(); } void QuickWidgetSink::on_volumeSlider_sliderPressed() { d->changingVolume = true; } void QuickWidgetSink::on_volumeSlider_sliderReleased() { d->changingVolume = false; } void QuickWidgetSink::sinkInputAdded(PulseAudioQt::SinkInput* sinkInput) { connect(sinkInput, &PulseAudioQt::SinkInput::deviceIndexChanged, this, &QuickWidgetSink::updateVisibility); updateVisibility(); } void QuickWidgetSink::updateVisibility() { QTimer::singleShot(0, this, [this] { if (PulseAudioQt::Context::instance()->server()->defaultSink() == d->sink) { this->setVisible(true); return; } for (PulseAudioQt::SinkInput* sinkInput : PulseAudioQt::Context::instance()->sinkInputs()) { if (sinkInput->deviceIndex() == d->sink->index()) { this->setVisible(true); return; } } this->setVisible(false); }); } void QuickWidgetSink::updateName() { ui->nameLabel->setText(this->fontMetrics().elidedText(Common::nameForSink(d->sink), Qt::ElideRight, SC_DPI(200))); } void QuickWidgetSink::on_volumeSlider_valueChanged(int value) { qint64 factor = PulseAudioQt::normalVolume() / 100; qint64 newVolume = value * factor; d->sink->setVolume(newVolume); } void QuickWidgetSink::on_actionMake_Default_triggered() { PulseAudioQt::Context::instance()->server()->setDefaultSink(d->sink); } void QuickWidgetSink::on_actionMove_All_Applications_triggered() { for (PulseAudioQt::SinkInput* sinkInput : PulseAudioQt::Context::instance()->sinkInputs()) { sinkInput->setDeviceIndex(d->sink->index()); } } ================================================ FILE: plugins/AudioPlugin/quickwidgetsink.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef QUICKWIDGETSINK_H #define QUICKWIDGETSINK_H #include #include #include namespace Ui { class QuickWidgetSink; } struct QuickWidgetSinkPrivate; class QuickWidgetSink : public QWidget { Q_OBJECT public: explicit QuickWidgetSink(PulseAudioQt::Sink* sink, QWidget* parent = nullptr); ~QuickWidgetSink(); private slots: void on_volumeSlider_sliderPressed(); void on_volumeSlider_sliderReleased(); void on_volumeSlider_valueChanged(int value); void on_actionMake_Default_triggered(); void on_actionMove_All_Applications_triggered(); private: Ui::QuickWidgetSink* ui; QuickWidgetSinkPrivate* d; void sinkInputAdded(PulseAudioQt::SinkInput* sinkInput); void updateVisibility(); void updateName(); void updateVolume(); void updateDefault(); }; #endif // QUICKWIDGETSINK_H ================================================ FILE: plugins/AudioPlugin/quickwidgetsink.ui ================================================ QuickWidgetSink 0 0 400 35 Form 0 0 0 0 TextLabel Qt::Horizontal 0 0 QToolButton::InstantPopup Make Default Use for All Applications ================================================ FILE: plugins/AudioPlugin/quickwidgetsinkinput.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "quickwidgetsinkinput.h" #include "ui_quickwidgetsinkinput.h" #include "common.h" #include #include #include #include #include struct QuickWidgetSinkInputPrivate { bool changingVolume = false; PulseAudioQt::SinkInput* sinkInput; QString pid; static QMultiMap sinkInputsByPid; QMenu* menu; QMenu* devicesMenu; QMap sinkActions; QActionGroup* devicesGroup; }; QMultiMap QuickWidgetSinkInputPrivate::sinkInputsByPid = QMultiMap(); QuickWidgetSinkInput::QuickWidgetSinkInput(PulseAudioQt::SinkInput* sinkInput, QWidget* parent) : QWidget(parent), ui(new Ui::QuickWidgetSinkInput) { ui->setupUi(this); d = new QuickWidgetSinkInputPrivate(); d->sinkInput = sinkInput; connect(sinkInput, &PulseAudioQt::SinkInput::nameChanged, this, &QuickWidgetSinkInput::updateClient); connect(sinkInput, &PulseAudioQt::SinkInput::clientChanged, this, &QuickWidgetSinkInput::updateClient); connect(sinkInput, &PulseAudioQt::SinkInput::volumeChanged, this, &QuickWidgetSinkInput::updateVolume); connect(sinkInput, &PulseAudioQt::SinkInput::propertiesChanged, this, &QuickWidgetSinkInput::updateProperties); updateClient(); updateVolume(); updateProperties(); d->devicesGroup = new QActionGroup(this); d->devicesGroup->setExclusive(true); d->devicesMenu = new QMenu(); d->devicesMenu->setTitle(tr("Play on")); d->devicesMenu->setIcon(QIcon::fromTheme("audio-headphones")); d->menu = new QMenu(); d->menu->addMenu(d->devicesMenu); ui->menuButton->setMenu(d->menu); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkAdded, this, &QuickWidgetSinkInput::sinkAdded); connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkRemoved, this, &QuickWidgetSinkInput::sinkRemoved); for (PulseAudioQt::Sink* sink : PulseAudioQt::Context::instance()->sinks()) sinkAdded(sink); this->setFixedWidth(SC_DPI(600)); ui->nameLabel->setFixedWidth(SC_DPI(200)); } QuickWidgetSinkInput::~QuickWidgetSinkInput() { d->sinkInputsByPid.remove(d->pid, this); for (QuickWidgetSinkInput* sinkInputWidget : d->sinkInputsByPid.values(d->pid)) sinkInputWidget->updateVisibility(); delete ui; } void QuickWidgetSinkInput::updateVolume() { if (d->changingVolume) return; int volume = d->sinkInput->volume() / static_cast(PulseAudioQt::normalVolume()) * 100; QSignalBlocker blocker(ui->volumeSlider); ui->volumeSlider->setValue(volume); } void QuickWidgetSinkInput::updateClient() { QString name = d->sinkInput->properties().value("application.name", d->sinkInput->name()).toString(); // if (d->sinkInput->client()) { // name = d->sinkInput->client()->name(); // } else { // name = d->sinkInput->name(); // } ui->nameLabel->setText(this->fontMetrics().elidedText(name, Qt::ElideRight, SC_DPI(200))); } void QuickWidgetSinkInput::updateProperties() { d->sinkInputsByPid.remove(d->pid, this); for (QuickWidgetSinkInput* sinkInputWidget : d->sinkInputsByPid.values(d->pid)) sinkInputWidget->updateVisibility(); d->pid = d->sinkInput->properties().value("application.process.id").toString(); d->sinkInputsByPid.insert(d->pid, this); for (QuickWidgetSinkInput* sinkInputWidget : d->sinkInputsByPid.values(d->pid)) sinkInputWidget->updateVisibility(); } void QuickWidgetSinkInput::updateVisibility() { this->setVisible(d->sinkInputsByPid.values(d->pid).first() == this); } void QuickWidgetSinkInput::on_volumeSlider_sliderPressed() { d->changingVolume = true; } void QuickWidgetSinkInput::on_volumeSlider_sliderReleased() { d->changingVolume = false; } void QuickWidgetSinkInput::on_volumeSlider_valueChanged(int value) { qint64 factor = PulseAudioQt::normalVolume() / 100; qint64 newVolume = value * factor; for (QuickWidgetSinkInput* sinkInputWidget : d->sinkInputsByPid.values(d->pid)) sinkInputWidget->d->sinkInput->setVolume(newVolume); } void QuickWidgetSinkInput::sinkAdded(PulseAudioQt::Sink* sink) { QAction* action = new QAction(this); action->setCheckable(true); connect(sink, &PulseAudioQt::Sink::propertiesChanged, action, [=] { action->setText(Common::nameForSink(sink)); }); action->setText(Common::nameForSink(sink)); connect(d->sinkInput, &PulseAudioQt::SinkInput::deviceIndexChanged, action, [=] { action->setChecked(sink->index() == d->sinkInput->deviceIndex()); }); action->setChecked(sink->index() == d->sinkInput->deviceIndex()); connect(action, &QAction::toggled, this, [=](bool checked) { if (checked) { for (QuickWidgetSinkInput* sinkInputWidget : d->sinkInputsByPid.values(d->pid)) sinkInputWidget->d->sinkInput->setDeviceIndex(sink->index()); } }); d->devicesMenu->addAction(action); d->devicesGroup->addAction(action); d->sinkActions.insert(sink, action); } void QuickWidgetSinkInput::sinkRemoved(PulseAudioQt::Sink* sink) { QAction* action = d->sinkActions.take(sink); d->devicesMenu->removeAction(action); d->devicesGroup->removeAction(action); action->deleteLater(); } ================================================ FILE: plugins/AudioPlugin/quickwidgetsinkinput.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef QUICKWIDGETSINKINPUT_H #define QUICKWIDGETSINKINPUT_H #include #include #include namespace Ui { class QuickWidgetSinkInput; } struct QuickWidgetSinkInputPrivate; class QuickWidgetSinkInput : public QWidget { Q_OBJECT public: explicit QuickWidgetSinkInput(PulseAudioQt::SinkInput* sinkInput, QWidget* parent = nullptr); ~QuickWidgetSinkInput(); private slots: void on_volumeSlider_sliderPressed(); void on_volumeSlider_sliderReleased(); void on_volumeSlider_valueChanged(int value); private: Ui::QuickWidgetSinkInput* ui; QuickWidgetSinkInputPrivate* d; void sinkAdded(PulseAudioQt::Sink* sink); void sinkRemoved(PulseAudioQt::Sink* sink); void updateVolume(); void updateClient(); void updateProperties(); void updateVisibility(); }; #endif // QUICKWIDGETSINKINPUT_H ================================================ FILE: plugins/AudioPlugin/quickwidgetsinkinput.ui ================================================ QuickWidgetSinkInput 0 0 400 300 Form 0 0 0 0 TextLabel true Qt::Horizontal 0 0 ... QToolButton::InstantPopup ================================================ FILE: plugins/AudioPlugin/thedesk-audio.conf ================================================ ================================================ FILE: plugins/AudioPlugin/translations/ar_SA.ts ================================================ AudioQuickWidget VOLUME الصوت APPLICATIONS التطبيقات QUIET MODE الوضع الصامت EventHandler No Audio Devices لا يوجد أجهزة صوت Mute صامت Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/au_AU.ts ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/cy.ts ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/da.ts ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/de.ts ================================================ AudioQuickWidget VOLUME LAUTSTÄRKE APPLICATIONS ANWENDUNGEN QUIET MODE STILLER MODUS EventHandler No Audio Devices Keine Audiogeräte Mute Stumm Unmute Quiet Mode before changing the volume Speakers Lautsprecher Headphones Kopfhörer Line Out Line Out Volume Lautstärke MicChunk %n applications %n Anwendung %n Anwendungen QuickWidgetSink Make Default Als Standard festlegen Use for All Applications Für alle Anwendungen verwenden QuickWidgetSinkInput Play on Abspielen auf ================================================ FILE: plugins/AudioPlugin/translations/en_GB.ts ================================================ EventHandler No Audio Devices No Audio Devices Speakers Speakers Headphones Headphones Volume Volume Mute Mute Unmute Quiet Mode before changing the volume Unmute Quiet Mode before changing the volume Line Out MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/en_US.qm ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/es.ts ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/es_VE.ts ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/id.ts ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/ja.ts ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/nl.ts ================================================ AudioQuickWidget VOLUME VOLUME APPLICATIONS APPLICATIES QUIET MODE STILTEMODUS EventHandler No Audio Devices Geen Audio-apparaten Mute Stil Unmute Quiet Mode before changing the volume Zet Stiltemodus uit voordat je het volume aanpast Speakers Speakers Headphones Koptelefoons Line Out Lijn Uit Volume Volume MicChunk %n applications %n applicatie %n applicaties QuickWidgetSink Make Default Standaard Maken Use for All Applications Voor Alle Applicaties Gebruiken QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/pt_BR.ts ================================================ AudioQuickWidget VOLUME VOLUME APPLICATIONS APLICAÇÕES QUIET MODE MODO SILENCIOSO EventHandler No Audio Devices Nenhum dispositivo de áudio Mute Mudo Unmute Quiet Mode before changing the volume Desative o modo silencioso antes de mudar o volume Speakers Alto-falantes Headphones Fones de ouvido Line Out Saída de linha (Line Out) Volume Volume MicChunk %n applications %n aplicativo %n aplicativos QuickWidgetSink Make Default Tornar padrão Use for All Applications Usar para todos os aplicativos QuickWidgetSinkInput Play on Reproduzir em ================================================ FILE: plugins/AudioPlugin/translations/ro_RO.ts ================================================ AudioQuickWidget VOLUME VOLUM QUIET MODE MOD SILENȚIOS APPLICATIONS APLICAȚII EventHandler No Audio Devices Niciun dispozitiv audio conectat Speakers Boxe Headphones Căști Volume Volum Mute Mut Unmute Quiet Mode before changing the volume Dezactivați modul silențios înainte de a schimba volumul Line Out Mufă căști/boxe MicChunk %n applications o aplicație %n aplicații %n aplicații QuickWidgetSink Make Default Setează ca implicit Use for All Applications Folosiți pentru toate aplicații QuickWidgetSinkInput Play on Redă pe ================================================ FILE: plugins/AudioPlugin/translations/sv.ts ================================================ EventHandler No Audio Devices Mute Unmute Quiet Mode before changing the volume Speakers Headphones Line Out Volume MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/tr_TR.ts ================================================ AudioQuickWidget VOLUME SES QUIET MODE SESSİZ MOD APPLICATIONS UYGULAMALAR EventHandler No Audio Devices Ses Cihazı Yok Speakers Hoparlörler Headphones Kulaklıklar Volume Ses Mute Sessiz Unmute Quiet Mode before changing the volume Sesi değiştirmeden önce Sessiz Modu Açın Line Out Hat Çıkışı MicChunk %n applications QuickWidgetSink Make Default Varsayılan Yap Use for All Applications Tüm uygulamalar için kullan QuickWidgetSinkInput Play on Oynamak ================================================ FILE: plugins/AudioPlugin/translations/vi_VN.ts ================================================ AudioQuickWidget VOLUME ÂM LƯỢNG QUIET MODE CHẾ ĐỘ IM APPLICATIONS ỨNG DỤNG EventHandler No Audio Devices Không có thiết bị âm thanh Speakers Loa Headphones Tai nghe Volume Âm lượng Mute Im lặng Unmute Quiet Mode before changing the volume Đổi khỏi chế độ im lặng trước khi đổi âm lượng Line Out Dòng ra MicChunk %n applications %n ứng dụng QuickWidgetSink Make Default Đặt thành mặc định Use for All Applications Sử dụng cho các ứng dụng QuickWidgetSinkInput Play on Phát trên ================================================ FILE: plugins/AudioPlugin/translations/zh_CN.ts ================================================ EventHandler No Audio Devices 未找到音频设备 Speakers 音响 Headphones 耳机 Volume 音量 Mute 静音 Unmute Quiet Mode before changing the volume 在更改音量之前请解除安静模式 Line Out MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/AudioPlugin/translations/zu_ZA.qm ================================================ EventHandler No Audio Devices Speakers Headphones Volume Mute Unmute Quiet Mode before changing the volume Line Out MicChunk %n applications QuickWidgetSinkInput Play on ================================================ FILE: plugins/BluetoothPlugin/BluetoothPlugin.pro ================================================ QT += gui widgets BluezQt TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ btagent.cpp \ btobex.cpp \ chunk/bluetoothchunk.cpp \ common.cpp \ devicedelegate.cpp \ plugin.cpp \ settings/bluetoothsettingspane.cpp \ settings/devicepopover.cpp \ settings/pairpopover.cpp HEADERS += \ btagent.h \ btobex.h \ chunk/bluetoothchunk.h \ common.h \ devicedelegate.h \ plugin.h \ settings/bluetoothsettingspane.h \ settings/devicepopover.h \ settings/pairpopover.h DISTFILES += Plugin.json \ defaults.conf \ defaults.json unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/BluetoothPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/BluetoothPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ settings/bluetoothsettingspane.ui \ settings/devicepopover.ui \ settings/pairpopover.ui ================================================ FILE: plugins/BluetoothPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) find_package(KF${KF_VERSION_MAJOR}BluezQt) set(SOURCES btagent.cpp btobex.cpp chunk/bluetoothchunk.cpp bluetoothplugincommon.cpp devicedelegate.cpp plugin.cpp settings/bluetoothsettingspane.cpp settings/devicepopover.cpp settings/pairpopover.cpp settings/bluetoothsettingspane.ui settings/devicepopover.ui settings/pairpopover.ui ) set(HEADERS btagent.h btobex.h chunk/bluetoothchunk.h bluetoothplugincommon.h devicedelegate.h plugin.h settings/bluetoothsettingspane.h settings/devicepopover.h settings/pairpopover.h ) set(PLUGIN_NAME bluetooth) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-bluetooth.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets KF${KF_VERSION_MAJOR}::BluezQt libcontemporary libthedesk) ================================================ FILE: plugins/BluetoothPlugin/Plugin.json ================================================ { "name": "Bluetooth", "icon": "preferences-system-bluetooth", "uuid": "e64f4005-56a6-4401-962d-e325b6109eec", "vi": { "name": "Bluetooth" } } ================================================ FILE: plugins/BluetoothPlugin/bluetoothplugincommon.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "bluetoothplugincommon.h" BluetoothPluginCommon::BluetoothPluginCommon(QObject* parent) : QObject(parent) { } QString BluetoothPluginCommon::stringForDeviceType(BluezQt::Device::Type type) { switch (type) { case BluezQt::Device::Phone: return tr("Phone"); case BluezQt::Device::Modem: return tr("Modem"); case BluezQt::Device::Computer: return tr("Computer"); case BluezQt::Device::Network: return tr("Networking"); case BluezQt::Device::Headset: return tr("Headset"); case BluezQt::Device::Headphones: return tr("Headphones"); case BluezQt::Device::AudioVideo: return tr("Audio/Video"); case BluezQt::Device::Keyboard: return tr("Keyboard"); case BluezQt::Device::Mouse: return tr("Mouse"); case BluezQt::Device::Joypad: return tr("Gamepad"); case BluezQt::Device::Tablet: return tr("Drawing Tablet"); case BluezQt::Device::Peripheral: return tr("Peripheral"); case BluezQt::Device::Camera: return tr("Camera"); case BluezQt::Device::Printer: return tr("Printer"); case BluezQt::Device::Imaging: return tr("Imaging"); case BluezQt::Device::Wearable: return tr("Wearable"); case BluezQt::Device::Toy: return tr("Toy"); case BluezQt::Device::Health: return tr("Health"); default: return tr("Unknown"); } } ================================================ FILE: plugins/BluetoothPlugin/bluetoothplugincommon.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BLUETOOTHPLUGINCOMMON_H #define BLUETOOTHPLUGINCOMMON_H #include class BluetoothPluginCommon : public QObject { Q_OBJECT public: explicit BluetoothPluginCommon(QObject* parent = nullptr); static QString stringForDeviceType(BluezQt::Device::Type type); signals: }; #endif // BLUETOOTHPLUGINCOMMON_H ================================================ FILE: plugins/BluetoothPlugin/btagent.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "btagent.h" #include #include #include #include "settings/pairpopover.h" struct BtAgentPrivate { BluezQt::DevicePtr capturedDevice; PairPopover* capturedPopover; QPointer notification; }; BtAgent::BtAgent(QObject* parent) : BluezQt::Agent(parent) { d = new BtAgentPrivate(); } BtAgent::~BtAgent() { delete d; } void BtAgent::capturePairRequests(BluezQt::DevicePtr device, PairPopover* popover) { d->capturedDevice = device; d->capturedPopover = popover; } QDBusObjectPath BtAgent::objectPath() const { return QDBusObjectPath("/com/vicr123/theDesk/BluetoothPlugin/Agent"); } BluezQt::Agent::Capability BtAgent::capability() const { return DisplayYesNo; } void BtAgent::requestPinCode(BluezQt::DevicePtr device, const BluezQt::Request& request) { } void BtAgent::displayPinCode(BluezQt::DevicePtr device, const QString& pinCode) { if (device == d->capturedDevice) { d->capturedPopover->triggerPairConfirmation(PairPopover::KeyPinCode, pinCode)->error([ = ](QString error) { device->cancelPairing(); }); } else { //TODO: Show a notification } } void BtAgent::requestPasskey(BluezQt::DevicePtr device, const BluezQt::Request& request) { } void BtAgent::displayPasskey(BluezQt::DevicePtr device, const QString& passkey, const QString& entered) { if (device == d->capturedDevice) { d->capturedPopover->triggerPairConfirmation(PairPopover::KeyPinCode, passkey); } else { //TODO: Show a notification } } void BtAgent::requestConfirmation(BluezQt::DevicePtr device, const QString& passkey, const BluezQt::Request<>& request) { if (device == d->capturedDevice) { d->capturedPopover->triggerPairConfirmation(PairPopover::ConfirmPinCode, passkey)->then([ = ](QString pinCode) { request.accept(); })->error([ = ](QString error) { request.reject(); }); } else { tNotification* notification = new tNotification(); notification->setAppIcon("preferences-system-bluetooth"); notification->setAppName(tr("Bluetooth")); notification->setSummary(tr("Pair with %1?").arg(QLocale().quoteString(device->name()))); notification->setText(tr("In order to complete pairing, confirm that the following pairing code is shown on %1.").arg(QLocale().quoteString(device->name())).append(QStringLiteral("

%1

").arg(passkey)) .append(tr("If it is, you can accept the pairing request."))); notification->insertAction("1reject", tr("Decline")); notification->insertAction("2accept", tr("Accept and Pair")); notification->setTimeout(0); connect(notification, &tNotification::actionClicked, this, [ = ](QString key) { if (key == "1reject") { request.reject(); } else if (key == "2accept") { request.accept(); } }); connect(notification, &tNotification::dismissed, this, [ = ] { request.reject(); }); notification->post(); d->notification = notification; } } void BtAgent::requestAuthorization(BluezQt::DevicePtr device, const BluezQt::Request<>& request) { if (device == d->capturedDevice) { //Automatically accept the pairing request request.accept(); } else { tNotification* notification = new tNotification(); notification->setAppIcon("preferences-system-bluetooth"); notification->setAppName(tr("Bluetooth")); notification->setSummary(tr("Pair with %1?").arg(QLocale().quoteString(device->name()))); notification->setText(tr("Accept the pairing request from %1?").arg(QLocale().quoteString(device->name()))); notification->insertAction("1reject", tr("Decline")); notification->insertAction("2accept", tr("Pair")); notification->setTimeout(0); connect(notification, &tNotification::actionClicked, this, [ = ](QString key) { if (key == "1reject") { request.reject(); } else if (key == "2accept") { request.accept(); } }); connect(notification, &tNotification::dismissed, this, [ = ] { request.reject(); }); notification->post(); d->notification = notification; } } void BtAgent::authorizeService(BluezQt::DevicePtr device, const QString& uuid, const BluezQt::Request<>& request) { request.accept(); } void BtAgent::cancel() { if (d->capturedDevice) { d->capturedPopover->cancelPendingPairing(); } else if (d->notification) { d->notification->dismiss(); } } ================================================ FILE: plugins/BluetoothPlugin/btagent.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BTAGENT_H #define BTAGENT_H #include struct BtAgentPrivate; class PairPopover; class BtAgent : public BluezQt::Agent { Q_OBJECT public: explicit BtAgent(QObject* parent = nullptr); ~BtAgent(); void capturePairRequests(BluezQt::DevicePtr device, PairPopover* popover); signals: private: BtAgentPrivate* d; // Agent interface public: QDBusObjectPath objectPath() const; Capability capability() const; void requestPinCode(BluezQt::DevicePtr device, const BluezQt::Request& request); void displayPinCode(BluezQt::DevicePtr device, const QString& pinCode); void requestPasskey(BluezQt::DevicePtr device, const BluezQt::Request& request); void displayPasskey(BluezQt::DevicePtr device, const QString& passkey, const QString& entered); void requestConfirmation(BluezQt::DevicePtr device, const QString& passkey, const BluezQt::Request<>& request); void requestAuthorization(BluezQt::DevicePtr device, const BluezQt::Request<>& request); void authorizeService(BluezQt::DevicePtr device, const QString& uuid, const BluezQt::Request<>& request); void cancel(); }; #endif // BTAGENT_H ================================================ FILE: plugins/BluetoothPlugin/btobex.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "btobex.h" #include #include #include #include #include #include #include #include #include #include #include #include #include struct BtObexPrivate { BluezQt::ManagerPtr manager; BluezQt::ObexManagerPtr obexManager; QPointer notification; }; BtObex::BtObex(BluezQt::ManagerPtr manager, QObject* parent) : BluezQt::ObexAgent(parent) { d = new BtObexPrivate(); d->manager = manager; d->obexManager = BluezQt::ObexManagerPtr(new BluezQt::ObexManager()); BluezQt::PendingCall* startCall = BluezQt::ObexManager::startService(); connect(startCall, &BluezQt::PendingCall::finished, this, [ = ] { BluezQt::InitObexManagerJob* initObexManagerJob = d->obexManager->init(); connect(initObexManagerJob, &BluezQt::InitObexManagerJob::result, this, [ = ] { d->obexManager->registerAgent(this); }); initObexManagerJob->start(); }); } BtObex::~BtObex() { delete d; } QDBusObjectPath BtObex::objectPath() const { return QDBusObjectPath("/com/vicr123/theDesk/BluetoothPlugin/ObexAgent"); } void BtObex::authorizePush(BluezQt::ObexTransferPtr transfer, BluezQt::ObexSessionPtr session, const BluezQt::Request& request) { tNotification* notification = new tNotification(); notification->setAppIcon("preferences-system-bluetooth"); notification->setAppName(tr("Bluetooth")); notification->setSummary(tr("Incoming file")); notification->setText(tr("%1 is sending you the file %2.").arg(QLocale().quoteString(d->manager->deviceForAddress(session->destination())->name()), QLocale().quoteString(transfer->name()))); notification->insertAction("1reject", tr("Decline")); notification->insertAction("2accept", tr("Accept")); notification->setTimeout(0); connect(notification, &tNotification::actionClicked, this, [ = ](QString key) { if (key == "1reject") { request.reject(); } else if (key == "2accept") { QString transferName = transfer->name(); QString cachePath = QFile::decodeName(qgetenv("XDG_CACHE_HOME")); if (cachePath == "") cachePath = QDir::home().absoluteFilePath(".cache"); cachePath += "/obexd/"; QString temporaryPath = cachePath + transferName; int number = 0; while (QFile::exists(temporaryPath)) { temporaryPath = cachePath + transferName + "_" + QString::number(number); number++; } connect(transfer.data(), &BluezQt::ObexTransfer::statusChanged, this, [ = ](BluezQt::ObexTransfer::Status status) { if (status == BluezQt::ObexTransfer::Complete) { //Move the file to a good place QString downloadsDir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); if (!QDir(downloadsDir).exists()) QDir::root().mkpath(downloadsDir); QString permanantPath = QDir(downloadsDir).absoluteFilePath(transferName); int number = 0; while (QFile::exists(permanantPath)) { permanantPath = QDir(downloadsDir).absoluteFilePath(QStringLiteral("%1 (%2)").arg(transferName, number)); number++; } QFile::rename(temporaryPath, permanantPath); tNotification* notification = new tNotification(); notification->setAppIcon("preferences-system-bluetooth"); notification->setAppName(tr("Bluetooth")); notification->setSummary(tr("File received")); notification->setText(tr("The file %1 has been received and can be found in your Downloads folder.").arg(QLocale().quoteString(transferName))); notification->post(); } else if (status == BluezQt::ObexTransfer::Error) { tNotification* notification = new tNotification(); notification->setAppIcon("preferences-system-bluetooth"); notification->setAppName(tr("Bluetooth")); notification->setSummary(tr("File transfer failed")); notification->setText(tr("The file %1 was unable to be received.").arg(QLocale().quoteString(transferName))); notification->post(); } }); request.accept(temporaryPath); } }); connect(notification, &tNotification::dismissed, this, [ = ] { request.reject(); }); notification->post(); d->notification = notification; } void BtObex::cancel() { if (d->notification) d->notification->dismiss(); } void BtObex::release() { } ================================================ FILE: plugins/BluetoothPlugin/btobex.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BTOBEX_H #define BTOBEX_H #include struct BtObexPrivate; class BtObex : public BluezQt::ObexAgent { Q_OBJECT public: explicit BtObex(BluezQt::ManagerPtr manager, QObject* parent = nullptr); ~BtObex(); signals: private: BtObexPrivate* d; // ObexAgent interface public: QDBusObjectPath objectPath() const; void authorizePush(BluezQt::ObexTransferPtr transfer, BluezQt::ObexSessionPtr session, const BluezQt::Request& request); void cancel(); void release(); }; #endif // BTOBEX_H ================================================ FILE: plugins/BluetoothPlugin/chunk/bluetoothchunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "bluetoothchunk.h" #include #include #include #include struct BluetoothChunkPrivate { BluezQt::ManagerPtr manager; }; BluetoothChunk::BluetoothChunk(BluezQt::ManagerPtr manager) : IconTextChunk("bluetooth") { d = new BluetoothChunkPrivate(); d->manager = manager; this->setIcon(QIcon::fromTheme("bluetooth")); connect(manager.data(), &BluezQt::Manager::deviceAdded, this, &BluetoothChunk::updateChunk); connect(manager.data(), &BluezQt::Manager::deviceRemoved, this, &BluetoothChunk::updateChunk); connect(manager.data(), &BluezQt::Manager::deviceChanged, this, &BluetoothChunk::updateChunk); updateChunk(); } BluetoothChunk::~BluetoothChunk() { if (StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->removeChunk(this); delete d; } void BluetoothChunk::updateChunk() { QVector activeDevices; for (const BluezQt::DevicePtr& device : d->manager->devices()) { if (device->isConnected()) activeDevices.append(device); } if (activeDevices.isEmpty()) { if (StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->removeChunk(this); } else { if (activeDevices.count() == 1) { this->setText(activeDevices.first()->name()); } else { this->setText(tr("%n devices connected", nullptr, activeDevices.count())); } if (!StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->addChunk(this); } } ================================================ FILE: plugins/BluetoothPlugin/chunk/bluetoothchunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BLUETOOTHCHUNK_H #define BLUETOOTHCHUNK_H #include #include struct BluetoothChunkPrivate; class BluetoothChunk : public IconTextChunk { Q_OBJECT public: explicit BluetoothChunk(BluezQt::ManagerPtr manager); ~BluetoothChunk(); signals: private: BluetoothChunkPrivate* d; void updateChunk(); }; #endif // BLUETOOTHCHUNK_H ================================================ FILE: plugins/BluetoothPlugin/defaults.json ================================================ ================================================ FILE: plugins/BluetoothPlugin/devicedelegate.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "devicedelegate.h" #include "bluetoothplugincommon.h" #include #include #include #include #include #include struct DeviceDelegatePrivate { bool isPair; struct Rects { QRect iconRect; QRect textRect; QRect descRect; QRect arrowRect; Rects(const QStyleOptionViewItem& option) { QRect newRect = option.rect; QPoint center = newRect.center(); newRect.setWidth(StateManager::statusCenterManager()->preferredContentWidth()); newRect.moveCenter(center); iconRect.setLeft(newRect.left() + SC_DPI(6)); iconRect.setTop(newRect.top() + SC_DPI(6)); iconRect.setBottom(iconRect.top() + SC_DPI(32)); iconRect.setRight(iconRect.left() + SC_DPI(32)); arrowRect.setSize(SC_DPI_T(QSize(16, 16), QSize)); arrowRect.moveCenter(newRect.center()); arrowRect.moveRight(newRect.right() - SC_DPI(6)); textRect.setLeft(iconRect.right() + SC_DPI(6)); textRect.setTop(newRect.top() + SC_DPI(6)); textRect.setBottom(newRect.top() + option.fontMetrics.height() + SC_DPI(6)); textRect.setRight(arrowRect.left() - SC_DPI(6)); descRect.setLeft(iconRect.right() + SC_DPI(6)); descRect.setTop(newRect.top() + option.fontMetrics.height() + SC_DPI(8)); descRect.setBottom(newRect.top() + option.fontMetrics.height() * 2 + SC_DPI(6)); descRect.setRight(arrowRect.left() - SC_DPI(6)); } }; }; DeviceDelegate::DeviceDelegate(bool isPair, QObject* parent) : QAbstractItemDelegate(parent) { d = new DeviceDelegatePrivate(); d->isPair = isPair; } DeviceDelegate::~DeviceDelegate() { delete d; } void DeviceDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { painter->setFont(option.font); tPaintCalculator calculator; calculator.setPainter(painter); calculator.setLayoutDirection(option.direction); calculator.setDrawBounds(option.rect); DeviceDelegatePrivate::Rects rects(option); QString text = index.data().toString(); QString desc = BluetoothPluginCommon::stringForDeviceType(index.data(BluezQt::DevicesModel::TypeRole).value()); QIcon icon = QIcon::fromTheme(index.data(BluezQt::DevicesModel::IconRole).toString()); bool active = index.data(BluezQt::DevicesModel::ConnectedRole).toBool(); if (option.state & QStyle::State_Selected) { calculator.addRect(option.rect, [=](QRectF drawBounds) { painter->setPen(Qt::transparent); painter->setBrush(option.palette.color(QPalette::Highlight)); painter->drawRect(drawBounds); }); calculator.addRect(rects.textRect, [=](QRectF drawBounds) { painter->setBrush(Qt::transparent); painter->setPen(option.palette.color(QPalette::HighlightedText)); if (!active && !d->isPair) painter->setOpacity(0.5); painter->drawText(drawBounds, Qt::AlignLeading, text); }); calculator.addRect(rects.descRect, [=](QRectF drawBounds) { painter->drawText(drawBounds, Qt::AlignLeading, desc); }); } else if (option.state & QStyle::State_MouseOver) { calculator.addRect(option.rect, [=](QRectF drawBounds) { QColor col = option.palette.color(QPalette::Highlight); col.setAlpha(127); painter->setBrush(col); painter->setPen(Qt::transparent); painter->drawRect(drawBounds); }); calculator.addRect(rects.textRect, [=](QRectF drawBounds) { if (!active && !d->isPair) painter->setOpacity(0.5); painter->setBrush(Qt::transparent); painter->setPen(option.palette.color(QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, text); }); calculator.addRect(rects.descRect, [=](QRectF drawBounds) { painter->setPen(option.palette.color(QPalette::Disabled, QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, desc); }); } else { calculator.addRect(rects.textRect, [=](QRectF drawBounds) { if (!active && !d->isPair) painter->setOpacity(0.5); painter->setPen(option.palette.color(QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, text); }); calculator.addRect(rects.descRect, [=](QRectF drawBounds) { painter->setPen(option.palette.color(QPalette::Disabled, QPalette::WindowText)); painter->drawText(drawBounds, Qt::AlignLeading, desc); }); } if (!icon.isNull()) { calculator.addRect(rects.iconRect, [=](QRectF drawBounds) { painter->drawPixmap(drawBounds.toRect(), icon.pixmap(rects.iconRect.size())); }); } calculator.addRect(rects.arrowRect, [=](QRectF drawBounds) { painter->setOpacity(1); painter->drawPixmap(drawBounds.toRect(), QIcon::fromTheme("go-next").pixmap(rects.arrowRect.size())); }); calculator.performPaint(); } QSize DeviceDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { DeviceDelegatePrivate::Rects rects(option); QRect u = rects.iconRect; u = u.united(rects.textRect); u = u.united(rects.descRect); u.adjust(SC_DPI(-6), SC_DPI(-6), SC_DPI(6), SC_DPI(6)); return u.size(); } ================================================ FILE: plugins/BluetoothPlugin/devicedelegate.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef DEVICEDELEGATE_H #define DEVICEDELEGATE_H #include struct DeviceDelegatePrivate; class DeviceDelegate : public QAbstractItemDelegate { Q_OBJECT public: explicit DeviceDelegate(bool isPair, QObject* parent = nullptr); ~DeviceDelegate(); signals: private: DeviceDelegatePrivate* d; // QAbstractItemDelegate interface public: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; }; #endif // DEVICEDELEGATE_H ================================================ FILE: plugins/BluetoothPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "btobex.h" #include "chunk/bluetoothchunk.h" #include "settings/bluetoothsettingspane.h" #include #include #include #include #include #include #include #include #include struct PluginPrivate { BluezQt::ManagerPtr manager; BtAgent* agent; BtObex* obex; BluetoothSettingsPane* bluetoothSettings; BluetoothChunk* chunk; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/BluetoothPlugin/thedesk-bluetooth.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-bluetooth.conf"); d->manager = BluezQt::ManagerPtr(new BluezQt::Manager()); d->agent = new BtAgent(); d->bluetoothSettings = new BluetoothSettingsPane(d->manager, d->agent); StateManager::statusCenterManager()->addPane(d->bluetoothSettings, StatusCenterManager::SystemSettings); d->chunk = new BluetoothChunk(d->manager); d->obex = new BtObex(d->manager); BluezQt::PendingCall* startCall = BluezQt::Manager::startService(); connect(startCall, &BluezQt::PendingCall::finished, this, [=] { BluezQt::InitManagerJob* initManagerJob = d->manager->init(); connect(initManagerJob, &BluezQt::InitManagerJob::result, this, [=] { BluezQt::PendingCall* agentRegister = d->manager->registerAgent(d->agent); connect(agentRegister, &BluezQt::PendingCall::finished, this, [=] { d->manager->requestDefaultAgent(d->agent); }); }); initManagerJob->start(); }); } void Plugin::deactivate() { d->obex->deleteLater(); d->agent->deleteLater(); d->chunk->deleteLater(); StateManager::statusCenterManager()->removePane(d->bluetoothSettings); d->bluetoothSettings->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/BluetoothPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/BluetoothPlugin/settings/bluetoothsettingspane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "bluetoothsettingspane.h" #include "ui_bluetoothsettingspane.h" #include #include #include #include #include "pairpopover.h" #include "devicepopover.h" #include #include "btagent.h" #include "devicedelegate.h" #include #include #include #include #include #include struct BluetoothSettingsPanePrivate { QString currentHostname; BluezQt::ManagerPtr manager; BluezQt::AdapterPtr usableAdapter; BtAgent* agent; QuickSwitch* bluetoothSwitch; }; BluetoothSettingsPane::BluetoothSettingsPane(BluezQt::ManagerPtr manager, BtAgent* agent) : StatusCenterPane(), ui(new Ui::BluetoothSettingsPane) { ui->setupUi(this); d = new BluetoothSettingsPanePrivate(); d->manager = manager; d->agent = agent; ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->actionsWidget->setFixedWidth(contentWidth); ui->discoverabilityWidget->setFixedWidth(contentWidth); ui->devicesLabel->setFixedWidth(contentWidth); ui->bluetoothUnavailableIcon->setPixmap(QIcon::fromTheme("bluetooth").pixmap(SC_DPI_T(QSize(128, 128), QSize))); ui->bluetoothUnavailableIcon_2->setPixmap(QIcon::fromTheme("bluetooth").pixmap(SC_DPI_T(QSize(128, 128), QSize))); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); QDBusConnection::systemBus().connect("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(updateHostname())); updateHostname(); d->bluetoothSwitch = new QuickSwitch("Bluetooth"); d->bluetoothSwitch->setTitle(tr("Bluetooth")); connect(d->bluetoothSwitch, &QuickSwitch::toggled, this, [ = ](bool isEnabled) { if (isEnabled) { ui->enableBluetoothButton->click(); } else { d->manager->setBluetoothBlocked(true); } }); BluezQt::DevicesModel* devicesModel = new BluezQt::DevicesModel(d->manager.data()); QSortFilterProxyModel* devicesFilter = new QSortFilterProxyModel(); devicesFilter->setSourceModel(devicesModel); devicesFilter->setFilterRole(BluezQt::DevicesModel::PairedRole); devicesFilter->setFilterFixedString("true"); ui->devicesList->setModel(devicesFilter); ui->devicesList->setItemDelegate(new DeviceDelegate(false)); connect(d->manager.data(), &BluezQt::Manager::adapterAdded, this, &BluetoothSettingsPane::updateUsableAdapter); connect(d->manager.data(), &BluezQt::Manager::adapterRemoved, this, &BluetoothSettingsPane::updateUsableAdapter); connect(d->manager.data(), &BluezQt::Manager::usableAdapterChanged, this, &BluetoothSettingsPane::updateUsableAdapter); connect(d->manager.data(), &BluezQt::Manager::operationalChanged, this, &BluetoothSettingsPane::updateOperational); connect(d->manager.data(), &BluezQt::Manager::bluetoothBlockedChanged, this, &BluetoothSettingsPane::updateOperational); updateUsableAdapter(); updateOperational(); } BluetoothSettingsPane::~BluetoothSettingsPane() { delete d; delete ui; } void BluetoothSettingsPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void BluetoothSettingsPane::updateHostname() { QDBusInterface hostnamed("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", QDBusConnection::systemBus()); QString hostname = hostnamed.property("PrettyHostname").toString(); if (hostname.isEmpty()) hostname = hostnamed.property("Hostname").toString(); d->currentHostname = hostname; if (d->usableAdapter) d->usableAdapter->setName(hostname); ui->discoverabilityMessage->setText(tr("To pair with this device, look for %1 on the other device.").arg("" + hostname + "")); } void BluetoothSettingsPane::updateUsableAdapter() { if (d->usableAdapter) { d->usableAdapter->disconnect(this); } //Find an adapter // d->usableAdapter.clear(); // for (const BluezQt::AdapterPtr& adapter : d->manager->adapters()) { // if (adapter->isPowered()) { // d->usableAdapter = adapter; // break; // } // } // if (!d->usableAdapter && !d->manager->adapters().isEmpty()) d->usableAdapter = d->manager->adapters().first(); if (!d->manager->adapters().isEmpty()) { d->usableAdapter = d->manager->adapters().at(0); } else { d->usableAdapter = nullptr; } if (d->usableAdapter) { connect(d->usableAdapter.data(), &BluezQt::Adapter::poweredChanged, this, [ = ](bool powered) { updateOperational(); }); connect(d->usableAdapter.data(), &BluezQt::Adapter::discoverableChanged, this, [ = ](bool discoverable) { ui->visibilitySwitch->setChecked(discoverable); }); ui->visibilitySwitch->setChecked(d->usableAdapter->isDiscoverable()); updateHostname(); } updateOperational(); } void BluetoothSettingsPane::updateOperational() { QSignalBlocker blocker(d->bluetoothSwitch); if (!d->manager->isOperational()) { ui->stackedWidget->setCurrentWidget(ui->unavailablePage, false); if (StateManager::statusCenterManager()->isSwitchRegistered(d->bluetoothSwitch)) StateManager::statusCenterManager()->removeSwitch(d->bluetoothSwitch); } else if (d->manager->adapters().isEmpty()) { ui->stackedWidget->setCurrentWidget(ui->unavailablePage, false); if (StateManager::statusCenterManager()->isSwitchRegistered(d->bluetoothSwitch)) StateManager::statusCenterManager()->removeSwitch(d->bluetoothSwitch); } else if (d->manager->isBluetoothBlocked() || d->usableAdapter == nullptr || !d->usableAdapter->isPowered()) { ui->stackedWidget->setCurrentWidget(ui->disabledPage, false); d->bluetoothSwitch->setChecked(false); if (!StateManager::statusCenterManager()->isSwitchRegistered(d->bluetoothSwitch)) StateManager::statusCenterManager()->addSwitch(d->bluetoothSwitch); } else { ui->stackedWidget->setCurrentWidget(ui->mainPage, false); d->bluetoothSwitch->setChecked(true); if (!StateManager::statusCenterManager()->isSwitchRegistered(d->bluetoothSwitch)) StateManager::statusCenterManager()->addSwitch(d->bluetoothSwitch); } } QString BluetoothSettingsPane::name() { return "BluetoothSettings"; } QString BluetoothSettingsPane::displayName() { return tr("Bluetooth"); } QIcon BluetoothSettingsPane::icon() { return QIcon::fromTheme("preferences-system-bluetooth"); } QWidget* BluetoothSettingsPane::leftPane() { return nullptr; } void BluetoothSettingsPane::on_visibilitySwitch_toggled(bool checked) { if (d->usableAdapter) d->usableAdapter->setDiscoverable(checked); } void BluetoothSettingsPane::on_pairButton_clicked() { PairPopover* pairPopover = new PairPopover(d->manager.data(), d->agent); tPopover* popover = new tPopover(pairPopover); popover->setPopoverWidth(SC_DPI(600)); connect(pairPopover, &PairPopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, pairPopover, &PairPopover::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); } void BluetoothSettingsPane::on_enableBluetoothButton_clicked() { d->manager->setBluetoothBlocked(false); if (!d->manager->adapters().isEmpty()) { d->manager->adapters().at(0)->setPowered(true); } } void BluetoothSettingsPane::on_devicesList_activated(const QModelIndex& index) { BluezQt::AdapterPtr adapter = d->manager->adapterForAddress(index.data(BluezQt::DevicesModel::AdapterAddressRole).toString()); BluezQt::DevicePtr device = adapter->deviceForAddress(index.data(BluezQt::DevicesModel::AddressRole).toString()); DevicePopover* devicePopover = new DevicePopover(device); tPopover* popover = new tPopover(devicePopover); popover->setPopoverWidth(SC_DPI(600)); connect(devicePopover, &DevicePopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, devicePopover, &DevicePopover::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); } void BluetoothSettingsPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/BluetoothPlugin/settings/bluetoothsettingspane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BLUETOOTHSETTINGSPANE_H #define BLUETOOTHSETTINGSPANE_H #include #include #include "btagent.h" namespace Ui { class BluetoothSettingsPane; } struct BluetoothSettingsPanePrivate; class BluetoothSettingsPane : public StatusCenterPane { Q_OBJECT public: explicit BluetoothSettingsPane(BluezQt::ManagerPtr manager, BtAgent* agent); ~BluetoothSettingsPane(); private slots: void on_titleLabel_backButtonClicked(); void updateHostname(); void on_visibilitySwitch_toggled(bool checked); void on_pairButton_clicked(); void on_enableBluetoothButton_clicked(); void on_devicesList_activated(const QModelIndex& index); private: Ui::BluetoothSettingsPane* ui; BluetoothSettingsPanePrivate* d; void updateUsableAdapter(); void updateOperational(); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // BLUETOOTHSETTINGSPANE_H ================================================ FILE: plugins/BluetoothPlugin/settings/bluetoothsettingspane.ui ================================================ BluetoothSettingsPane 0 0 664 458 Form 0 0 0 0 0 Bluetooth 0 0 0 0 0 0 QFrame::NoFrame true 0 0 664 441 0 0 0 0 0 75 true ACTIONS Pair New Device 16777215 1 Qt::Horizontal Visible to other devices VisibilitySwitch TextLabel 75 true DISCOVERABILITY 16777215 1 Qt::Horizontal 0 0 0 0 0 75 true DEVICES 9 QFrame::NoFrame Qt::Vertical 20 54 Qt::Vertical 20 40 20 Bluetooth is unavailable Qt::AlignCenter false TextLabel Qt::AlignCenter Install a Bluetooth card to use Bluetooth Qt::AlignCenter Qt::Vertical 20 40 Qt::Vertical 20 148 20 Bluetooth is disabled Qt::AlignCenter false TextLabel Qt::AlignCenter Switch Bluetooth on to connect to Bluetooth devices Qt::AlignCenter Enable Bluetooth .. Qt::Vertical 20 147 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tSwitch QPushButton
tswitch.h
================================================ FILE: plugins/BluetoothPlugin/settings/devicepopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "devicepopover.h" #include "ui_devicepopover.h" #include "bluetoothplugincommon.h" #include #include #include struct DevicePopoverPrivate { BluezQt::DevicePtr device; }; DevicePopover::DevicePopover(BluezQt::DevicePtr device, QWidget* parent) : QWidget(parent), ui(new Ui::DevicePopover) { ui->setupUi(this); d = new DevicePopoverPrivate(); d->device = device; ui->titleLabel->setBackButtonShown(true); ui->titleLabel->setText(device->name()); ui->iconLabel->setPixmap(QIcon::fromTheme(device->icon()).pixmap(SC_DPI_T(QSize(64, 64), QSize))); ui->nameLabel->setText(device->name()); ui->typeLabel->setText(BluetoothPluginCommon::stringForDeviceType(device->type())); connect(d->device.data(), &BluezQt::Device::connectedChanged, this, &DevicePopover::updateDevice); updateDevice(); ui->removeButton->setProperty("type", "destructive"); } DevicePopover::~DevicePopover() { delete d; delete ui; } void DevicePopover::on_titleLabel_backButtonClicked() { emit done(); } void DevicePopover::on_removeButton_clicked() { // TODO: Ask d->device->adapter()->removeDevice(d->device); emit done(); } void DevicePopover::on_connectButton_clicked() { BluezQt::PendingCall* call = d->device->connectToDevice(); connect(call, &BluezQt::PendingCall::finished, this, [=] { if (call->error() != BluezQt::PendingCall::NoError) { tToast* toast = new tToast(); toast->setTitle(tr("Failed to connect")); switch (call->error()) { default: toast->setText(tr("Connecting to %1 failed.").arg(QLocale().quoteString(d->device->name()))); } connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); } }); } void DevicePopover::on_disconnectButton_clicked() { d->device->disconnectFromDevice(); } void DevicePopover::updateDevice() { if (d->device->isConnected()) { ui->connectButton->setVisible(false); ui->disconnectButton->setVisible(true); } else { ui->connectButton->setVisible(true); ui->disconnectButton->setVisible(false); } } ================================================ FILE: plugins/BluetoothPlugin/settings/devicepopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef DEVICEPOPOVER_H #define DEVICEPOPOVER_H #include #include namespace Ui { class DevicePopover; } struct DevicePopoverPrivate; class DevicePopover : public QWidget { Q_OBJECT public: explicit DevicePopover(BluezQt::DevicePtr device, QWidget* parent = nullptr); ~DevicePopover(); private slots: void on_titleLabel_backButtonClicked(); void on_removeButton_clicked(); void on_connectButton_clicked(); void on_disconnectButton_clicked(); signals: void done(); private: Ui::DevicePopover* ui; DevicePopoverPrivate* d; void updateDevice(); }; #endif // DEVICEPOPOVER_H ================================================ FILE: plugins/BluetoothPlugin/settings/devicepopover.ui ================================================ DevicePopover 0 0 400 300 Form 0 0 0 0 0 0 0 0 0 0 Device TextLabel 0 0 TextLabel false TextLabel 6 9 9 9 6 75 true ACTIONS Connect Disconnect Remove Qt::Vertical 20 113 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/BluetoothPlugin/settings/pairpopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "pairpopover.h" #include "ui_pairpopover.h" #include #include #include #include #include #include #include "btagent.h" #include "devicedelegate.h" struct PairPopoverPrivate { BluezQt::Manager* manager; BluezQt::AdapterPtr adapter; BtAgent* agent; tPromiseFunctions::SuccessFunction pairSuccessFunction; tPromiseFunctions::FailureFunction pairFailFunction; }; PairPopover::PairPopover(BluezQt::Manager* manager, BtAgent* agent, QWidget* parent) : QWidget(parent), ui(new Ui::PairPopover) { ui->setupUi(this); d = new PairPopoverPrivate(); d->manager = manager; d->adapter = d->manager->usableAdapter(); d->agent = agent; ui->titleLabel->setBackButtonShown(true); ui->confirmCodeTitleLabel->setBackButtonShown(true); ui->confirmCodeReturnIcon->setPixmap(QIcon::fromTheme("key-enter").pixmap(SC_DPI_T(QSize(16, 16), QSize))); BluezQt::DevicesModel* devicesModel = new BluezQt::DevicesModel(d->manager); QSortFilterProxyModel* devicesFilter = new QSortFilterProxyModel(); devicesFilter->setSourceModel(devicesModel); devicesFilter->setFilterRole(BluezQt::DevicesModel::PairedRole); devicesFilter->setFilterFixedString("false"); QSortFilterProxyModel* devicesFilter2 = new QSortFilterProxyModel(); devicesFilter2->setSourceModel(devicesFilter); devicesFilter2->setFilterRole(BluezQt::DevicesModel::AdapterAddressRole); devicesFilter2->setFilterFixedString(d->adapter->address()); ui->pairList->setModel(devicesFilter2); ui->pairList->setItemDelegate(new DeviceDelegate(true)); d->adapter->startDiscovery(); } PairPopover::~PairPopover() { d->adapter->stopDiscovery(); delete d; delete ui; } tPromise* PairPopover::triggerPairConfirmation(PairPopover::PairConfirmationType pairType, QString pinCode) { return TPROMISE_CREATE_SAME_THREAD(QString, { d->pairSuccessFunction = res; d->pairFailFunction = rej; switch (pairType) { case PairPopover::ConfirmPinCode: ui->stackedWidget->setCurrentWidget(ui->confirmCodePage); ui->confirmCodeActionLabel->setText("Confirm this pairing code"); ui->confirmCodeSubtitle->setVisible(false); ui->confirmCodeText->setText(pinCode); ui->confirmCodeReturnIcon->setVisible(false); ui->confirmCodeAcceptButton->setVisible(true); break; case PairPopover::KeyPinCode: ui->stackedWidget->setCurrentWidget(ui->confirmCodePage); ui->confirmCodeActionLabel->setText("Key this in on the device"); ui->confirmCodeSubtitle->setText(tr("Then press ENTER or RETURN.")); ui->confirmCodeSubtitle->setVisible(true); ui->confirmCodeText->setText(pinCode); ui->confirmCodeReturnIcon->setVisible(true); ui->confirmCodeAcceptButton->setVisible(false); break; } }); } void PairPopover::cancelPendingPairing() { // if (d->pairFailFunction) d->pairFailFunction("Cancelled"); } void PairPopover::on_titleLabel_backButtonClicked() { emit done(); } void PairPopover::on_pairList_activated(const QModelIndex& index) { ui->stackedWidget->setCurrentWidget(ui->loadingPage); BluezQt::DevicePtr device = d->adapter->deviceForAddress(index.data(BluezQt::DevicesModel::AddressRole).toString()); d->agent->capturePairRequests(device, this); ui->deviceNameConfirmCode->setText(device->name()); BluezQt::PendingCall* pairRequest = device->pair(); connect(pairRequest, &BluezQt::PendingCall::finished, this, [ = ] { d->agent->capturePairRequests(nullptr, nullptr); if (pairRequest->error() == BluezQt::PendingCall::NoError) { device->setTrusted(true); device->connectToDevice(); emit done(); } else { ui->stackedWidget->setCurrentWidget(ui->deviceSelectionPage); tToast* toast = new tToast(); toast->setTitle(tr("Failed to pair")); switch (pairRequest->error()) { case BluezQt::PendingCall::AuthenticationFailed: toast->setText(tr("Pairing with %1 failed because the pairing code was incorrect.").arg(QLocale().quoteString(device->name()))); break; case BluezQt::PendingCall::AuthenticationRejected: toast->setText(tr("Pairing with %1 failed because the device rejected the pairing request.").arg(QLocale().quoteString(device->name()))); break; case BluezQt::PendingCall::AuthenticationTimeout: toast->setText(tr("Pairing with %1 failed because the pairing code was not confirmed in time.").arg(QLocale().quoteString(device->name()))); break; default: toast->setText(tr("Pairing with %1 failed.").arg(QLocale().quoteString(device->name()))); } connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); } }); } void PairPopover::on_confirmCodeAcceptButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->loadingPage); d->pairSuccessFunction(""); } void PairPopover::on_confirmCodeTitleLabel_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->loadingPage); d->pairFailFunction("Failure"); } ================================================ FILE: plugins/BluetoothPlugin/settings/pairpopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PAIRPOPOVER_H #define PAIRPOPOVER_H #include #include #include namespace Ui { class PairPopover; } struct PairPopoverPrivate; class BtAgent; class PairPopover : public QWidget { Q_OBJECT public: explicit PairPopover(BluezQt::Manager* manager, BtAgent* agent, QWidget* parent = nullptr); ~PairPopover(); enum PairConfirmationType { ConfirmPinCode, KeyPinCode }; tPromise* triggerPairConfirmation(PairConfirmationType pairType, QString pinCode); void cancelPendingPairing(); signals: void done(); private slots: void on_titleLabel_backButtonClicked(); void on_pairList_activated(const QModelIndex& index); void on_confirmCodeAcceptButton_clicked(); void on_confirmCodeTitleLabel_backButtonClicked(); private: Ui::PairPopover* ui; PairPopoverPrivate* d; }; #endif // PAIRPOPOVER_H ================================================ FILE: plugins/BluetoothPlugin/settings/pairpopover.ui ================================================ PairPopover 0 0 616 699 Form 0 0 0 0 0 0 0 0 0 0 0 Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. true 9 16777215 1 Qt::Horizontal QFrame::NoFrame Qt::Vertical 20 297 Qt::Horizontal 241 20 Qt::Horizontal 240 20 Qt::Vertical 20 297 0 0 0 0 0 Qt::Horizontal 40 20 Qt::Horizontal 55 20 Qt::Vertical 20 235 500 0 false QFrame::NoFrame QFrame::Plain 0 15 Device Name 20 Confirm this pairing code false TextLabel Qt::Vertical QSizePolicy::Fixed 20 40 0 true 0 0 0 0 0 0 30 TextLabel Qt::AlignCenter Return 0 0 ../../NetworkPlugin/statusCenter/popovers../../NetworkPlugin/statusCenter/popovers false true Qt::Vertical 20 235 Confirm Pairing Code tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/BluetoothPlugin/thedesk-bluetooth.conf ================================================ ================================================ FILE: plugins/BluetoothPlugin/translations/ar_SA.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/au_AU.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/cy.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/da.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/de.ts ================================================ BluetoothChunk %n devices connected %n Gerät verbunden %n Geräte verbunden BluetoothPluginCommon Phone Telefon Modem Modem Computer Computer Networking Vernetzung Headset Headset Headphones Kopfhörer Audio/Video Audio/Video Keyboard Tastatur Mouse Maus Gamepad Gamepad Drawing Tablet Grafiktablett Peripheral Peripheriegerät Camera Kamera Printer Drucker Imaging Wearable Wearable Toy Spielzeug Health Gesundheit Unknown Unbekannt BluetoothSettingsPane Bluetooth Bluetooth ACTIONS AKTIONEN Pair New Device Neues Gerät koppeln Visible to other devices Für andere Geräte sichtbar DISCOVERABILITY ENTDECKBARKEIT DEVICES GERÄTE Bluetooth is unavailable Bluetooth ist unverfügbar Install a Bluetooth card to use Bluetooth Installiere eine Bluetoothkarte um Bluetooth zu verwenden Bluetooth is disabled Bluetooth ist deaktiviert Switch Bluetooth on to connect to Bluetooth devices Schalte Bluetooth um sich zu Bluetoothgeräten zu verbinden Enable Bluetooth Bluetooth aktivieren To pair with this device, look for %1 on the other device. Schau nach %1 auf dem anderen Gerät, um sich mit diesem zu verbinden. BtAgent Bluetooth Bluetooth Pair with %1? Mit %1 koppeln? In order to complete pairing, confirm that the following pairing code is shown on %1. Stelle sicher, dass der folgende Koppelcode auf %1 angezeigt wird, um das Koppeln fertigzustellen. If it is, you can accept the pairing request. Falls ja, kannst du die Koppelanfrage annehmen. Decline Ablehnen Accept and Pair Annehmen und koppeln Accept the pairing request from %1? Koppelanfrage von %1 annehmen? Pair Koppeln BtObex Bluetooth Bluetooth Incoming file Eingehende Datei %1 is sending you the file %2. %1 sendet dir die Datei %2. Decline Ablehnen Accept Annehmen File received Datei empfangen The file %1 has been received and can be found in your Downloads folder. Die Datei %1 wurde empfangen und kann in deinem Downloadsordner gefunden werden. File transfer failed Dateitransfer gescheitert The file %1 was unable to be received. Die Datei %1 konnte nicht empfangen werden. Common Phone Telefon Modem Modem Computer Computer Networking Vernetzung Headset Headset Headphones Kopfhörer Audio/Video Audio/Video Keyboard Tastatur Mouse Maus Gamepad Gamepad Drawing Tablet Grafiktablett Peripheral Peripheriegerät Camera Kamera Printer Drucker Wearable Wearable Toy Spielzeug Health Gesundheit Unknown Unbekannt DevicePopover ACTIONS AKTIONEN Connect Verbinden Disconnect Trennen Remove Entfernen Failed to connect Verbindung gescheitert Connecting to %1 failed. Die Verbindung zu %1 ist gescheitert. PairPopover Pair Device Gerät koppeln To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/en_US.qm ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/es.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/es_VE.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/id.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/nl.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/pt_BR.ts ================================================ BluetoothChunk %n devices connected %n dispositivo conectado %n dispositivos conectados BluetoothPluginCommon Phone Telefone Modem Modem Computer Computador Networking Rede Headset Headset Headphones Fones de ouvido Audio/Video Áudio/Vídeo Keyboard Teclado Mouse Mouse Gamepad Gamepad Drawing Tablet Mesa digitalizadora Peripheral Periférico Camera Câmera Printer Impressora Imaging Dispositivo de imagem Wearable Acessório wearable Toy Brinquedo Health Saúde Unknown Desconhecido BluetoothSettingsPane Bluetooth Bluetooth ACTIONS AÇÕES Pair New Device Emparelhar um novo dispositivo Visible to other devices Visível a outros dispositivos DISCOVERABILITY VISIBILIDADE DEVICES DISPOSITIVOS Bluetooth is unavailable Bluetooth está indisponível Install a Bluetooth card to use Bluetooth Instale um adaptador Bluetooth para usar o Bluetooth Bluetooth is disabled Bluetooth está desabilitado Switch Bluetooth on to connect to Bluetooth devices Ligue o Bluetooth para conectar dispositivos Bluetooth Enable Bluetooth Ativar o Bluetooth To pair with this device, look for %1 on the other device. Para emparelhar com este dispositivo, procure por %1 no outro dispositivo. BtAgent Bluetooth Bluetooth Pair with %1? Emparelhar com %1? In order to complete pairing, confirm that the following pairing code is shown on %1. Para completar o emparelhamento, confirme que o seguinte código está sendo exibido em %1. If it is, you can accept the pairing request. Se for, você pode aceitar o pedido de emparelhamento. Decline Recusar Accept and Pair Aceitar e emparelhar Accept the pairing request from %1? Aceitar o pedido de emparelhamento de %1? Pair Emparelhar BtObex Bluetooth Bluetooth Incoming file Arquivo a ser recebido %1 is sending you the file %2. %1 está mandando o arquivo %2. Decline Recusar Accept Aceitar File received Arquivo recebido The file %1 has been received and can be found in your Downloads folder. O arquivo %1 foi recebido e pode ser encontrado na pasta Downloads. File transfer failed Falha na transferência The file %1 was unable to be received. Não foi possível receber o arquivo %1. Common Phone Telefone Modem Modem Computer Computador Networking Rede Headset Headset Headphones Fones de ouvido Audio/Video Áudio/Vídeo Keyboard Teclado Mouse Mouse Gamepad Gamepad Drawing Tablet Mesa digitalizadora Peripheral Periférico Camera Câmera Printer Impressora Imaging Dispositivo de imagem Wearable Acessório wearable Toy Brinquedo Health Saúde Unknown Desconhecido DevicePopover ACTIONS AÇÕES Connect Conectar Disconnect Desconectar Remove Remover Failed to connect Falha ao conectar Connecting to %1 failed. Falha ao conectar-se com %1. PairPopover Pair Device Emparelhar dispositivo To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Certifique-se que o dispositivo que você quer emparelhar está visível. Pode ser necessário abrir as configurações Bluetooth ou apertar um botão no outro dispositivo. Confirm Pairing Code Confirme o código de emparelhamento Then press ENTER or RETURN. Então aperte ENTER. Failed to pair Falha ao emparelhar Pairing with %1 failed because the pairing code was incorrect. O emparelhamento com %1 falhou porque o código de emparelhamento estava incorreto. Pairing with %1 failed because the device rejected the pairing request. O emparelhamento com %1 falhou porque o dispositivo rejeitou a solicitação de emparelhamento. Pairing with %1 failed because the pairing code was not confirmed in time. O emparelhamento com %1 falhou porque o código de emparelhamento não foi confirmado a tempo. Pairing with %1 failed. O emparelhamento com %1 falhou. ================================================ FILE: plugins/BluetoothPlugin/translations/ro.ts ================================================ BluetoothChunk %n devices connected Un dispozitiv conectat %n dispozitive conectate %n dispozitive conectate BluetoothPluginCommon Phone Telefon Modem Modem Computer Calculator Networking Rețelistică Headset Headset Headphones Căști Audio/Video Audio/Video Keyboard Tastatură Mouse Mouse Gamepad Gamepad Drawing Tablet Tabletă grafică Peripheral Periferic Camera Cameră Printer Imprimantă Imaging Imagistică Wearable De purtat Toy Jucărie Health Sănătate Unknown Necunoscut BluetoothSettingsPane Bluetooth Bluetooth ACTIONS ACȚIUNI Pair New Device Asociază un nou dispozitiv Visible to other devices Vizibil de către alte dispozitive DISCOVERABILITY VIZIBILITATE DEVICES DISPOZITIVE Bluetooth is unavailable Bluetooth este indisponibil Install a Bluetooth card to use Bluetooth Instalați un adaptor Bluetooth pentru a folosi Bluetooth Bluetooth is disabled Bluetooth este dezactivat Switch Bluetooth on to connect to Bluetooth devices Activați Bluetooth pentru a putea folosi dispozitivele Bluetooth Enable Bluetooth Activează Bluetooth To pair with this device, look for %1 on the other device. Pentru se asocia cu acest dispozitiv, căutați %1 celuilalt dispozitiv. BtAgent Bluetooth Bluetooth Pair with %1? Doriți să asociați %1? In order to complete pairing, confirm that the following pairing code is shown on %1. Pentru a finaliza asocierea, asigurați-v că următorul cod de asociere este afișat pe %1. If it is, you can accept the pairing request. Dacă da, puteți să acceptați solicitarea. Decline Refuză Accept and Pair Acceptă și asociază Accept the pairing request from %1? Acceptați solicitarea de asociere din partea %1? Pair Asociere BtObex Bluetooth Bluetooth Incoming file Fișier în primire %1 is sending you the file %2. %1 dorește să trimită %2. Decline Refuză Accept Acceptă File received Fișier primit The file %1 has been received and can be found in your Downloads folder. Fișierul %1 a fost primit și poate fi găsit în folderul de descărcări. File transfer failed Transfer eșuat The file %1 was unable to be received. Fișierul %1 nu a putut fi primit. Common Phone Telefon Modem Modem Computer Calculator Networking Rețelistică Headset Headset Headphones Căști Audio/Video Audio/Video Keyboard Tastatură Mouse Mouse Gamepad Gamepad Drawing Tablet Tabletă grafică Peripheral Periferic Camera Cameră Printer Imprimantă Imaging Imagistică Wearable De purtat Toy Jucărie Health Sănătate Unknown Necunoscut DevicePopover ACTIONS ACȚIUNI Connect Conectare Disconnect Deconectare Remove Elimină Failed to connect Conexiunea a eșuat Connecting to %1 failed. Conectarea la %1 a eșuat. PairPopover Pair Device Asociază dispozitivul To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Asigurați-vă că dispozitivul pe care doriți să îl asociați este vizibil pentru a începe. Acest lucru poate fi realizat prin deschiderea setărilor de Bluetooth sau apăsarea unui buton pe dispozitiv. Confirm Pairing Code Confirmați codul de asociere Then press ENTER or RETURN. Apoi apăsați ENTER sau RETURN. Failed to pair Nu s-a putut asocia Pairing with %1 failed because the pairing code was incorrect. Asocierea cu %1 a eșuat deoarece codul de asociere este incorect. Pairing with %1 failed because the device rejected the pairing request. Asocierea cu %1 a eșuat deoarece dispozitivul a refuzat solicitarea. Pairing with %1 failed because the pairing code was not confirmed in time. Asocierea cu %1 a eșuat deoarece codul de asociere nu a fost confirmat la timp. Pairing with %1 failed. Asocierea cu %1 a eșuat. ================================================ FILE: plugins/BluetoothPlugin/translations/sv.ts ================================================ BluetoothChunk %n devices connected BluetoothPluginCommon Phone Modem Computer Networking Headset Headphones Audio/Video Keyboard Mouse Gamepad Drawing Tablet Peripheral Camera Printer Imaging Wearable Toy Health Unknown BluetoothSettingsPane Bluetooth ACTIONS Pair New Device Visible to other devices DISCOVERABILITY DEVICES Bluetooth is unavailable Install a Bluetooth card to use Bluetooth Bluetooth is disabled Switch Bluetooth on to connect to Bluetooth devices Enable Bluetooth To pair with this device, look for %1 on the other device. BtAgent Bluetooth Pair with %1? In order to complete pairing, confirm that the following pairing code is shown on %1. If it is, you can accept the pairing request. Decline Accept and Pair Accept the pairing request from %1? Pair BtObex Bluetooth Incoming file %1 is sending you the file %2. Decline Accept File received The file %1 has been received and can be found in your Downloads folder. File transfer failed The file %1 was unable to be received. DevicePopover ACTIONS Connect Disconnect Remove Failed to connect Connecting to %1 failed. PairPopover Pair Device To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Confirm Pairing Code Then press ENTER or RETURN. Failed to pair Pairing with %1 failed because the pairing code was incorrect. Pairing with %1 failed because the device rejected the pairing request. Pairing with %1 failed because the pairing code was not confirmed in time. Pairing with %1 failed. ================================================ FILE: plugins/BluetoothPlugin/translations/tr.ts ================================================ BluetoothChunk %n devices connected %n bağlı cihazlar BluetoothPluginCommon Phone Telefon Modem Modem Computer Bilgisayar Networking Headset Kulaklık Headphones Kulaklıklar Audio/Video Ses/Video Keyboard Klavye Mouse Mouse Gamepad Oyun kumanda Drawing Tablet Çizim Tableti Peripheral Çevresel Camera Kamera Printer Yazıcı Imaging Görüntüleme Wearable Giyilebilir Toy Oyuncak Health Sağlık Unknown Bilinmeyen BluetoothSettingsPane Bluetooth Bluetooth ACTIONS HAREKETLER Pair New Device Yeni Cihazı Eşle Visible to other devices Diğer cihazlara görünür DISCOVERABILITY KEŞFEDİLEBİLİRLİK DEVICES CIHAZLAR Bluetooth is unavailable Bluetooth kullanılamıyor Install a Bluetooth card to use Bluetooth Bluetooth'u kullanmak için bir Bluetooth kartı takın Bluetooth is disabled Bluetooth devre dışı Switch Bluetooth on to connect to Bluetooth devices Bluetooth cihazlarına bağlanmak için Bluetooth'u açın Enable Bluetooth Bluetooth'u etkinleştir To pair with this device, look for %1 on the other device. Bu aygıtla eşleştirmek için diğer aygıtta %1 öğesini arayın. BtAgent Bluetooth Bluetooth Pair with %1? %1 ile eşleşecek mi? In order to complete pairing, confirm that the following pairing code is shown on %1. Eşleştirmeyi tamamlamak için, %1 üzerinde aşağıdaki eşleştirme kodunun gösterildiğinden emin olun. If it is, you can accept the pairing request. Eğer öyleyse, eşleştirme isteğini kabul edebilirsiniz. Decline Reddet Accept and Pair Kabul et ve Eşleştir Accept the pairing request from %1? %1 gelen eşleştirme isteğini kabul ediyor musun? Pair Ekle BtObex Bluetooth Bluetooth Incoming file Gelen dosya %1 is sending you the file %2. %1 seni %2 dosyasını gönderiyor. Decline Reddet Accept Kabul et File received Dosya alındı The file %1 has been received and can be found in your Downloads folder. %1 dosyası alındı ve indirilenler klasörünüzde bulunabilir. File transfer failed Dosya aktarımı başarısız oldu The file %1 was unable to be received. %1 dosyası alınamadı. Common Phone Telefon Modem Modem Computer Bilgisayar Networking Headset Kulaklık Headphones Kulaklıklar Audio/Video Ses/Video Keyboard Klavye Mouse Mouse Gamepad Oyun kumanda Drawing Tablet Çizim Tableti Peripheral Çevresel Camera Kamera Printer Yazıcı Imaging Görüntüleme Wearable Giyilebilir Toy Oyuncak Health Sağlık Unknown Bilinmeyen DevicePopover ACTIONS HAREKETLER Connect Bağlan Disconnect Bağlantıyı kes Remove Sil Failed to connect Bağlanılamadı Connecting to %1 failed. %1'e bağlanılamadı. PairPopover Pair Device Cihazı Eşleştir To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Başlamak için, eşleştirmek istediğiniz cihazın görünür olduğundan emin olun. Bu, Bluetooth ayarlarını açarak ya da başka bir cihazdaki bir düğmeye basarak elde edilebilir. Confirm Pairing Code Eşleştirme Kodunu Onayla Then press ENTER or RETURN. Ardından ENTER ya da RETURN'e basın. Failed to pair Eşleştirmek için başarısız oldu Pairing with %1 failed because the pairing code was incorrect. Eşleştirme kodu yanlış olduğu için %1 ile eşleştirme başarısız oldu. Pairing with %1 failed because the device rejected the pairing request. Cihaz eşleştirme isteğini reddettiği için %1 ile eşleştirme başarısız oldu. Pairing with %1 failed because the pairing code was not confirmed in time. Eşleştirme kodu zamanında onaylanmadığı için %1 ile eşleştirme başarısız oldu. Pairing with %1 failed. %1 ile eşleştirme başarısız oldu. ================================================ FILE: plugins/BluetoothPlugin/translations/vi.ts ================================================ BluetoothChunk %n devices connected %n thiết bị kết nối BluetoothPluginCommon Phone Điện thoại Modem Bộ điều giải Computer Máy tính Networking Thiết bị mạng Headset Tai nghe có micrô Headphones Tai nghe Audio/Video Âm thanh/Video Keyboard Bàn phím Mouse Chuột Gamepad Bộ điều khiển Drawing Tablet Bảng vẽ Peripheral Ngoại vi Camera Máy ảnh Printer Máy in Imaging Máy hình ảnh Wearable Thiết bị đeo Toy Đồ chơi Health Thiết bị sức khỏe Unknown Không xác định BluetoothSettingsPane Bluetooth Bluetooth ACTIONS HOẠT ĐỘNG Pair New Device Ghép thiết bị mới Visible to other devices Phát hiện trên thiết bị khác DISCOVERABILITY HIỂN THỊ TRÊN THIẾT BỊ KHÁC DEVICES THIẾT BỊ Bluetooth is unavailable Bluetooth không khả dụng Install a Bluetooth card to use Bluetooth Hãy cài một bộ mạch Bluetooth để sử dụng Bluetooth Bluetooth is disabled Bluetooth bị vô hiệu Switch Bluetooth on to connect to Bluetooth devices Bật Bluetooth để kết nối với thiết bị Bluetooth Enable Bluetooth Bật Bluetooth To pair with this device, look for %1 on the other device. Để ghép với thiết bị này, tìm tên %1 trên thiết bị kia. BtAgent Bluetooth Bluetooth Pair with %1? Ghép với %1? In order to complete pairing, confirm that the following pairing code is shown on %1. Để hoàn thành hoạt động ghép nối, vui lòng đảm bảo rằng mã dưới đây hiển thị trên %1. If it is, you can accept the pairing request. Nếu mã có hiển thị, bạn có thể chấp nhận yêu cầu ghép nối. Decline Từ chối Accept and Pair Chấp nhận và Ghép nối Accept the pairing request from %1? Chấp nhận yêu cầu ghép nối từ %1? Pair Ghép nối BtObex Bluetooth Bluetooth Incoming file Tệp đến %1 is sending you the file %2. %1 muốn gửi bạn tệp %2. Decline Từ chối Accept Chấp nhận File received Tệp đã nhận được The file %1 has been received and can be found in your Downloads folder. Tệp X đã bị nhận được, và bạn có thể xem nó trong thư mục tải xuống. File transfer failed Hoạt động chuyển tệp không thành công The file %1 was unable to be received. Tệp %1 không thể nhận được. Common Phone Điện thoại Modem Bộ điều giải Computer Máy tính Networking Thiết bị mạng Headset Tai nghe có micrô Headphones Tai nghe Audio/Video Âm thanh/Video Keyboard Bàn phím Mouse Chuột Gamepad Bộ điều khiển Drawing Tablet Bảng vẽ Peripheral Ngoại vi Camera Máy ảnh Printer Máy in Imaging Máy hình ảnh Wearable Thiết bị đeo Toy Đồ chơi Health Thiết bị sức khỏe Unknown Không xác định DevicePopover ACTIONS HOẠT ĐỘNG Connect Kết nối Disconnect Ngắt kết nối Remove Xóa Failed to connect Không thể kết nối Connecting to %1 failed. Không thể kết nối với %1. PairPopover Pair Device Ghép thiết bị mới To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Để bắt đầu, hãy đảm bảo thiết bị bạn muốn ghép nối cho sẽ phát hiện với thiết bị khác. Điều này có thể đạt được bằng cách cài đặt Bluetooth hoặc nhấn một nút trên thiết bị kia. Confirm Pairing Code Xác nhận mã ghép Then press ENTER or RETURN. Rồi bấm ENTER hoặc RETURN. Failed to pair Không thể ghép nối Pairing with %1 failed because the pairing code was incorrect. Không thể ghép với %1 tại vì mã ghép không đúng. Pairing with %1 failed because the device rejected the pairing request. Không thể ghép với %1 tại vì thiết bị kia từ chối yêu cầu ghép nối. Pairing with %1 failed because the pairing code was not confirmed in time. Không thể ghép với %1 tại vì mất quá nhiều thời gian xác nhận mã ghép. Pairing with %1 failed. Không thể ghép với %1. ================================================ FILE: plugins/BluetoothPlugin/translations/vi_VN.ts ================================================ BluetoothChunk %n devices connected %n thiết bị kết nối BluetoothPluginCommon Phone Điện thoại Modem Modem Computer Máy tính Networking Thiết bị mạng Headset Tai nghe có micrô Headphones Tai nghe Audio/Video Âm thanh/video Keyboard Bàn phím Mouse Chuột Gamepad Tay cầm trò chơi Drawing Tablet Bảng vẽ Peripheral Thiết bị ngoại vi Camera Máy ảnh Printer Máy in Imaging Máy quét Wearable Thiết bị đeo Toy Trò chơi Health Thiết bị y tế Unknown Không xác định BluetoothSettingsPane Bluetooth Bluetooth ACTIONS HOẠT ĐỘNG Pair New Device Ghép nối thiết bị mới Visible to other devices Có thể khám phá bởi thiết bị khác DISCOVERABILITY KHẢ NĂNG KHÁM PHÁ DEVICES THIẾT BỊ Bluetooth is unavailable Bluetooth không có sẵn Install a Bluetooth card to use Bluetooth Cài đặt phần cứng Bluetooth để sử dụng Bluetooth Bluetooth is disabled Bluetooth bị vô hiệu Switch Bluetooth on to connect to Bluetooth devices Bật Bluetooth để kết nối với thiết bị Bluetooth Enable Bluetooth Bật Bluetooth To pair with this device, look for %1 on the other device. Để ghép nối với thiết bị này, tìm kiếm tên %1 trên thiết bị kia. BtAgent Bluetooth Bluetooth Pair with %1? Ghép nối với %1? In order to complete pairing, confirm that the following pairing code is shown on %1. Để hoàn thành hoạt động ghép nối, vùi lòng xác nhận rằng đoạn mã sau được hiển thị trên %1. If it is, you can accept the pairing request. Nếu thiết bị đó hiển thị mã, bạn có thể chấp nhận yêu cầu ghép nối. Decline Từ chối Accept and Pair Chấp nhận và ghép nối Accept the pairing request from %1? Chấp nhận yêu cầu ghép nối từ %1? Pair Ghép nối BtObex Bluetooth Bluetooth Incoming file Tệp đến %1 is sending you the file %2. %1 đang gửi bạn tệp %2. Decline Từ chối Accept Chấp nhận File received Tệp bị nhận thành công The file %1 has been received and can be found in your Downloads folder. Tệp %1 đã bị nhận thành công và được đặt trong thử mục tài xuống của bạn. File transfer failed Hoạt động chuyển tệp không thành công The file %1 was unable to be received. Không thể nhận được tệp %1. DevicePopover ACTIONS HOẠT ĐỘNG Connect Kết nối Disconnect Ngắt kết nối Remove Xóa Failed to connect Không thể kết nối Connecting to %1 failed. Kết nối với %1 không có thành công. PairPopover Pair Device Ghép nối thiết bị To get started, ensure the device you want to pair is visible. This may be achieved by opening the Bluetooth settings or pressing a button on the other device. Để bắt đầu, đảm bảo rằng cái thiết bị bạn muốn ghép nối có thể bị khám phá. Bạn có thể đạt được điều này bằng cách mở cái đặt Bluetooth hoặc nhấn nút trên thiết bị kia. Confirm Pairing Code Xác nhận mã ghép nối Then press ENTER or RETURN. Rồi nhấn ENTER hoặc RETURN Failed to pair Không thể ghép nối Pairing with %1 failed because the pairing code was incorrect. Ghép nối với %1 không thành công tại vì mã ghép nối không có khớp. Pairing with %1 failed because the device rejected the pairing request. Ghép nối với %1 không thành công tại vì thiết bị kia từ chối yêu cầu ghép nối. Pairing with %1 failed because the pairing code was not confirmed in time. Ghép nối với %1 không thành công tại vì hết giờ xác nhận mã ghép nối. Pairing with %1 failed. Ghép nối với %1 không thành công. ================================================ FILE: plugins/BrightnessPlugin/BrightnessPlugin.pro ================================================ QT += gui widgets TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ plugin.cpp \ screenbrightnesschunk.cpp HEADERS += \ plugin.h \ screenbrightnesschunk.h DISTFILES += Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/BrightnessPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/BrightnessPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ screenbrightnesschunk.ui ================================================ FILE: plugins/BrightnessPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) set(SOURCES plugin.cpp screenbrightnesschunk.cpp screenbrightnesschunk.ui ) set(HEADERS plugin.h screenbrightnesschunk.h ) set(PLUGIN_NAME brightness) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-brightness.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets libcontemporary libthedesk) ================================================ FILE: plugins/BrightnessPlugin/Plugin.json ================================================ { "name": "Screen Brightness Management", "icon": "preferences-system-display", "uuid": "97d10af3-da66-470c-85cb-aa2e4ed2f8d7", "vi": { "name": "Quản lý độ sáng" } } ================================================ FILE: plugins/BrightnessPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "screenbrightnesschunk.h" #include #include #include #include #include #include #include #include #include #include #include #include struct PluginPrivate { KeyGrab* brightnessUp; KeyGrab* brightnessDown; ScreenBrightnessChunk* chunk; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/BrightnessPlugin/thedesk-brightness.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-brightness.conf"); d->brightnessUp = new KeyGrab(QKeySequence(Qt::Key_MonBrightnessUp), "brightnessUp"); d->brightnessDown = new KeyGrab(QKeySequence(Qt::Key_MonBrightnessDown), "brightnessDown"); connect(d->brightnessUp, &KeyGrab::activated, this, [=] { SystemScreen* screen = ScreenDaemon::instance()->primayScreen(); if (screen && screen->isScreenBrightnessAvailable()) { double newBrightness = screen->screenBrightness() + 0.05; if (newBrightness > 1) newBrightness = 1; screen->setScreenBrightness(newBrightness); StateManager::instance()->hudManager()->showHud({ {"icon", "video-display" }, {"title", tr("Brightness")}, {"value", newBrightness } }); } else { StateManager::instance()->hudManager()->showHud({ {"icon", "video-display" }, {"title", tr("Brightness")}, {"text", "Unavailable" } }); } }); connect(d->brightnessDown, &KeyGrab::activated, this, [=] { SystemScreen* screen = ScreenDaemon::instance()->primayScreen(); if (screen && screen->isScreenBrightnessAvailable()) { double newBrightness = screen->screenBrightness() - 0.05; if (newBrightness < 0) newBrightness = 0; screen->setScreenBrightness(newBrightness); StateManager::instance()->hudManager()->showHud({ {"icon", "video-display" }, {"title", tr("Brightness")}, {"value", newBrightness } }); } else { StateManager::instance()->hudManager()->showHud({ {"icon", "video-display" }, {"title", tr("Brightness")}, {"text", "Unavailable" } }); } }); d->chunk = new ScreenBrightnessChunk(); } void Plugin::deactivate() { d->brightnessUp->deleteLater(); d->brightnessDown->deleteLater(); d->chunk->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/BrightnessPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/BrightnessPlugin/screenbrightnesschunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "screenbrightnesschunk.h" #include "ui_screenbrightnesschunk.h" #include #include #include #include #include #include ScreenBrightnessChunk::ScreenBrightnessChunk() : Chunk(), ui(new Ui::ScreenBrightnessChunk) { ui->setupUi(this); ui->iconLabel->setPixmap(QIcon::fromTheme("video-display").pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->brightnessSlider->setFixedWidth(SC_DPI(200)); SystemScreen* screen = ScreenDaemon::instance()->primayScreen(); if (screen && screen->isScreenBrightnessAvailable()) { StateManager::barManager()->addChunk(this); connect(screen, &SystemScreen::screenBrightnessChanged, this, [=] { ui->brightnessSlider->setValue(static_cast(screen->screenBrightness() * 100)); }); ui->brightnessSlider->setValue(static_cast(screen->screenBrightness() * 100)); } connect(StateManager::barManager(), &BarManager::barHeightTransitioning, this, [=](qreal percentage) { if (qFuzzyCompare(percentage, 1)) { this->setFixedWidth(QWIDGETSIZE_MAX); } else { this->setFixedWidth(static_cast(this->sizeHint().width() * percentage)); } }); } ScreenBrightnessChunk::~ScreenBrightnessChunk() { StateManager::barManager()->removeChunk(this); delete ui; } QString ScreenBrightnessChunk::name() { return "Brightness"; } int ScreenBrightnessChunk::expandedHeight() { return this->sizeHint().height(); } int ScreenBrightnessChunk::statusBarHeight() { return 0; } void ScreenBrightnessChunk::on_brightnessSlider_sliderMoved(int position) { ScreenDaemon::instance()->primayScreen()->setScreenBrightness(position / 100.0); } ================================================ FILE: plugins/BrightnessPlugin/screenbrightnesschunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SCREENBRIGHTNESSCHUNK_H #define SCREENBRIGHTNESSCHUNK_H #include namespace Ui { class ScreenBrightnessChunk; } class ScreenBrightnessChunk : public Chunk { Q_OBJECT public: explicit ScreenBrightnessChunk(); ~ScreenBrightnessChunk(); private: Ui::ScreenBrightnessChunk* ui; // Chunk interface public: QString name(); int expandedHeight(); int statusBarHeight(); private slots: void on_brightnessSlider_sliderMoved(int position); }; #endif // SCREENBRIGHTNESSCHUNK_H ================================================ FILE: plugins/BrightnessPlugin/screenbrightnesschunk.ui ================================================ ScreenBrightnessChunk 0 0 167 35 Form TextLabel 0 0 100 Qt::Horizontal ================================================ FILE: plugins/BrightnessPlugin/thedesk-brightness.conf ================================================ ================================================ FILE: plugins/BrightnessPlugin/translations/ar_SA.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/au_AU.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/cy.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/da.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/de.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/en_GB.ts ================================================ Plugin Brightness Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/en_US.qm ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/es.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/es_VE.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/id_ID.ts ================================================ Plugin Brightness Kecerahan ================================================ FILE: plugins/BrightnessPlugin/translations/nl.ts ================================================ Plugin Brightness Helderheid ================================================ FILE: plugins/BrightnessPlugin/translations/pl_PL.ts ================================================ Plugin Brightness Jasność ================================================ FILE: plugins/BrightnessPlugin/translations/pt_BR.ts ================================================ Plugin Brightness Brilho ================================================ FILE: plugins/BrightnessPlugin/translations/ro_RO.ts ================================================ Plugin Brightness Luminozitate ================================================ FILE: plugins/BrightnessPlugin/translations/sk_SK.ts ================================================ Plugin Brightness jas ================================================ FILE: plugins/BrightnessPlugin/translations/sv.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/tr_TR.ts ================================================ Plugin Brightness Parlaklık ================================================ FILE: plugins/BrightnessPlugin/translations/vi_VN.ts ================================================ Plugin Brightness Độ sáng ================================================ FILE: plugins/BrightnessPlugin/translations/zh_CN.ts ================================================ Plugin Brightness 亮度 ================================================ FILE: plugins/BrightnessPlugin/translations/zh_SG.ts ================================================ Plugin Brightness ================================================ FILE: plugins/BrightnessPlugin/translations/zu_ZA.qm ================================================ Plugin Brightness ================================================ FILE: plugins/CMakeLists.txt ================================================ macro(add_plugin_td target) add_library(plugin-${target} SHARED) target_include_directories(plugin-${target} PUBLIC ../../libthedesk/) cntp_init_plugin(thedesk plugin-${target} 20 plugin-${target}) cntp_translate(plugin-${target}) set_target_properties(plugin-${target} PROPERTIES OUTPUT_NAME ${target}Plugin FRAMEWORK FALSE) endmacro() add_subdirectory(OverviewPlugin) add_subdirectory(DisplayPlugin) add_subdirectory(ScreenshotPlugin) add_subdirectory(NotificationsPlugin) add_subdirectory(ThemePlugin) add_subdirectory(PowerPlugin) add_subdirectory(LocalePlugin) add_subdirectory(BrightnessPlugin) add_subdirectory(DefaultsPlugin) add_subdirectory(InputPlugin) add_subdirectory(TimeDatePlugin) add_subdirectory(AccessibilityPlugin) #add_subdirectory(AudioPlugin) add_subdirectory(BluetoothPlugin) add_subdirectory(NetworkPlugin) add_subdirectory(UsersPlugin) ================================================ FILE: plugins/DefaultsPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) set(SOURCES defaultspane.cpp plugin.cpp defaultspane.ui ) set(HEADERS defaultspane.h plugin.h ) set(PLUGIN_NAME defaults) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-defaults.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt${QT_VERSION_MAJOR}::Widgets libcontemporary libthedesk) ================================================ FILE: plugins/DefaultsPlugin/DefaultsPlugin.pro ================================================ QT += gui widgets tdesktopenvironment TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ defaultspane.cpp \ plugin.cpp HEADERS += \ defaultspane.h \ plugin.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/DefaultsPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/DefaultsPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ defaultspane.ui ================================================ FILE: plugins/DefaultsPlugin/Plugin.json ================================================ { "name": "Default Applications Management", "icon": "preferences-desktop-default-applications", "uuid": "f747b256-997f-4d0d-b0ba-6e111188cba5", "vi": { "name": "Quản lý ứng dụng mặc định" } } ================================================ FILE: plugins/DefaultsPlugin/defaultspane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "defaultspane.h" #include "ui_defaultspane.h" #include #include #include #include DefaultsPane::DefaultsPane() : StatusCenterPane(), ui(new Ui::DefaultsPane) { ui->setupUi(this); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->defaultsWidget->setFixedWidth(contentWidth); loadDefaults(); } DefaultsPane::~DefaultsPane() { delete ui; } void DefaultsPane::loadDefaults() { auto populateBox = [ = ](QComboBox * box, QString mimeType) { box->clear(); QList apps = MimeAssociationManager::applicationsForMimeType(mimeType); if (apps.isEmpty()) { box->setEnabled(false); } else { box->setEnabled(true); QSignalBlocker blocker(box); for (const ApplicationPointer& app : apps) { box->addItem(QIcon::fromTheme(app->getProperty("Icon").toString()), app->getProperty("Name").toString(), app->desktopEntry()); } ApplicationPointer app = MimeAssociationManager::defaultApplicationForMimeType(mimeType); if (app) { for (int i = 0; i < box->count(); i++) { if (box->itemData(i).toString() == app->desktopEntry()) box->setCurrentIndex(i); } } } }; populateBox(ui->defaultBrowserBox, "x-scheme-handler/http"); populateBox(ui->defaultMailBox, "x-scheme-handler/mailto"); } QString DefaultsPane::name() { return "DefaultAppsSettings"; } QString DefaultsPane::displayName() { return tr("Default Applications"); } QIcon DefaultsPane::icon() { return QIcon::fromTheme("preferences-desktop-default-applications"); } QWidget* DefaultsPane::leftPane() { return nullptr; } void DefaultsPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void DefaultsPane::on_defaultBrowserBox_currentIndexChanged(int index) { QString app = ui->defaultBrowserBox->itemData(index).toString(); MimeAssociationManager::setDefaultApplicationForMimeType(app, "x-scheme-handler/http"); MimeAssociationManager::setDefaultApplicationForMimeType(app, "x-scheme-handler/https"); } void DefaultsPane::on_defaultMailBox_currentIndexChanged(int index) { QString app = ui->defaultMailBox->itemData(index).toString(); MimeAssociationManager::setDefaultApplicationForMimeType(app, "x-scheme-handler/mailto"); } void DefaultsPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/DefaultsPlugin/defaultspane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef DEFAULTSPANE_H #define DEFAULTSPANE_H #include namespace Ui { class DefaultsPane; } class DefaultsPane : public StatusCenterPane { Q_OBJECT public: explicit DefaultsPane(); ~DefaultsPane(); private: Ui::DefaultsPane* ui; void loadDefaults(); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); private slots: void on_titleLabel_backButtonClicked(); void on_defaultBrowserBox_currentIndexChanged(int index); void on_defaultMailBox_currentIndexChanged(int index); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // DEFAULTSPANE_H ================================================ FILE: plugins/DefaultsPlugin/defaultspane.ui ================================================ DefaultsPane 0 0 828 648 Form 0 0 0 0 0 Default Applications 0 0 Web Browser Set your default apps below Mail Client Qt::Vertical 20 531 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/DefaultsPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "defaultspane.h" #include #include #include #include #include #include #include #include #include #include #include struct PluginPrivate { DefaultsPane* defaultsPane; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/DefaultsPlugin/thedesk-defaults.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-defaults.conf"); d->defaultsPane = new DefaultsPane(); StateManager::statusCenterManager()->addPane(d->defaultsPane, StatusCenterManager::SystemSettings); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->defaultsPane); d->defaultsPane->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/DefaultsPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/DefaultsPlugin/thedesk-defaults.conf ================================================ ================================================ FILE: plugins/DefaultsPlugin/translations/ar_SA.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/au_AU.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/cy.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/da.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/de.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/en_US.qm ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/es.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/es_VE.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/id.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/nl.ts ================================================ DefaultsPane Default Applications Standaardapplicaties Web Browser Webbrowser Set your default apps below Stel je standaardapps hieronder in Mail Client E-mailclient ================================================ FILE: plugins/DefaultsPlugin/translations/pt_BR.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/ro.ts ================================================ DefaultsPane Default Applications Aplicații implicite Web Browser Browser web Set your default apps below Configurați aplicațiile implicite aici Mail Client Client de mail ================================================ FILE: plugins/DefaultsPlugin/translations/sv.ts ================================================ DefaultsPane Default Applications Web Browser Set your default apps below Mail Client ================================================ FILE: plugins/DefaultsPlugin/translations/tr.ts ================================================ DefaultsPane Default Applications Varsayılan Uygulamalar Web Browser İnternet tarayıcısı Set your default apps below Varsayılan uygulamalarınızı aşağıda ayarlayın Mail Client Posta İstemcisi ================================================ FILE: plugins/DefaultsPlugin/translations/vi.ts ================================================ DefaultsPane Default Applications Ứng dụng mặc định Web Browser Trình duyệt web Set your default apps below Đặt các ứng dụng mặc định dưới đây Mail Client Ứng dụng thư ================================================ FILE: plugins/DefaultsPlugin/translations/vi_VN.ts ================================================ DefaultsPane Default Applications Ứng dụng mặc định Web Browser Trình duyệt web Set your default apps below Đặt ứng dụng mặc định của bạn dưới đây Mail Client Ứng dụng thư khách ================================================ FILE: plugins/DisplayPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets DBus Positioning) find_package(libcontemporary) set(SOURCES arrange/arrangecontroller.cpp arrange/arrangewidget.cpp arrange/overlaywindow.cpp arrange/screenarranger.cpp plugin.cpp redshift/colorramp.cpp redshift/redshiftdaemon.cpp settings/displaysettings.cpp arrange/arrangewidget.ui arrange/overlaywindow.ui settings/displaysettings.ui ) set(HEADERS arrange/arrangecontroller.h arrange/arrangewidget.h arrange/overlaywindow.h arrange/screenarranger.h plugin.h redshift/colorramp.h redshift/redshiftdaemon.h settings/displaysettings.h ) set(PLUGIN_NAME display) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-display.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets Qt::Multimedia Qt::Positioning libcontemporary libthedesk) ================================================ FILE: plugins/DisplayPlugin/DisplayPlugin.pro ================================================ QT += gui widgets twebservices positioning TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ arrange/arrangecontroller.cpp \ arrange/arrangewidget.cpp \ arrange/overlaywindow.cpp \ arrange/screenarranger.cpp \ plugin.cpp \ redshift/colorramp.cpp \ redshift/redshiftdaemon.cpp \ settings/displaysettings.cpp HEADERS += \ arrange/arrangecontroller.h \ arrange/arrangewidget.h \ arrange/overlaywindow.h \ arrange/screenarranger.h \ plugin.h \ redshift/colorramp.h \ redshift/redshiftdaemon.h \ settings/displaysettings.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/DisplayPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/DisplayPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ arrange/arrangewidget.ui \ arrange/overlaywindow.ui \ settings/displaysettings.ui ================================================ FILE: plugins/DisplayPlugin/Plugin.json ================================================ { "name": "Display Management", "icon": "preferences-system-display", "uuid": "cc637480-e9ae-420d-98bd-dc737677e8cf", "vi": { "name": "Quản lý màn hình" } } ================================================ FILE: plugins/DisplayPlugin/arrange/arrangecontroller.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "arrangecontroller.h" #include "overlaywindow.h" #include "arrangewidget.h" #include #include #include struct ArrangeControllerPrivate { QList arrangers; }; ArrangeController::ArrangeController(QObject* parent) : QObject(parent) { d = new ArrangeControllerPrivate(); } ArrangeController::~ArrangeController() { delete d; } void ArrangeController::begin() { for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { screen->reset(); ArrangeWidget* w = new ArrangeWidget(screen); connect(w, &ArrangeWidget::reject, this, [ = ] { for (ArrangeWidget* w : d->arrangers) { w->dismiss(); } }); connect(w, &ArrangeWidget::destroyed, this, [ = ] { d->arrangers.removeOne(w); if (d->arrangers.isEmpty()) { emit done(); } }); d->arrangers.append(w); } } ================================================ FILE: plugins/DisplayPlugin/arrange/arrangecontroller.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ARRANGECONTROLLER_H #define ARRANGECONTROLLER_H #include struct ArrangeControllerPrivate; class ArrangeController : public QObject { Q_OBJECT public: explicit ArrangeController(QObject* parent = nullptr); ~ArrangeController(); void begin(); signals: void done(); private: ArrangeControllerPrivate* d; }; #endif // ARRANGECONTROLLER_H ================================================ FILE: plugins/DisplayPlugin/arrange/arrangewidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "arrangewidget.h" #include "ui_arrangewidget.h" #include "overlaywindow.h" #include #include #include #include #include struct ArrangeWidgetPrivate { OverlayWindow* overlay; SystemScreen* screen = nullptr; tPopover* popover; QMap buttons; bool init = true; }; ArrangeWidget::ArrangeWidget(SystemScreen* screen, QWidget* parent) : QWidget(parent), ui(new Ui::ArrangeWidget) { ui->setupUi(this); d = new ArrangeWidgetPrivate(); ui->titleLabel->setBackButtonShown(true); ui->screensWidget->setFixedWidth(600); ui->displayPropertiesWidget->setFixedWidth(600); ui->applyButton->setFixedWidth(600); d->overlay = new OverlayWindow(); d->overlay->show(); tScrim::scrimForWidget(d->overlay)->setBlurEnabled(false); d->popover = new tPopover(this); d->popover->setDismissable(false); d->popover->setPopoverSide(tPopover::Bottom); d->popover->setPopoverWidth(600); connect(d->popover, &tPopover::dismissed, this, &ArrangeWidget::deleteLater); connect(d->popover, &tPopover::dismissed, d->popover, &tPopover::deleteLater); QTimer::singleShot(500, [=] { d->popover->show(d->overlay); }); updateScreenList(); setScreen(screen); } ArrangeWidget::~ArrangeWidget() { d->overlay->deleteLater(); delete d; delete ui; } void ArrangeWidget::dismiss() { d->popover->dismiss(); } void ArrangeWidget::on_titleLabel_backButtonClicked() { emit reject(); } void ArrangeWidget::updateScreenGeometry() { d->overlay->setGeometry(d->screen->geometry()); d->overlay->showFullScreen(); } void ArrangeWidget::updateAvailableModes() { QSignalBlocker blocker(ui->resolutionBox); ui->resolutionBox->clear(); QList resolutions; for (SystemScreen::Mode mode : d->screen->availableModes()) { QSize res = QSize(mode.width, mode.height); if (!resolutions.contains(res)) { resolutions.append(res); ui->resolutionBox->addItem(QStringLiteral("%1 × %2").arg(res.width()).arg(res.height()), res); } if (d->init && d->screen->currentMode() == mode.id) ui->resolutionBox->setCurrentIndex(resolutions.indexOf(res)); } updateRefreshRateBox(); } void ArrangeWidget::updateRefreshRateBox() { QSignalBlocker blocker(ui->refreshRateBox); QSize selected = ui->resolutionBox->currentData().toSize(); ui->refreshRateBox->clear(); int select = -1; for (SystemScreen::Mode mode : d->screen->availableModes()) { QSize res = QSize(mode.width, mode.height); if (res == selected) { ui->refreshRateBox->addItem(tr("%1 hz").arg(mode.framerate, 0, 'f', 2), mode.id); if (d->init && d->screen->currentMode() == mode.id) select = ui->refreshRateBox->count() - 1; } } if (select != -1) ui->refreshRateBox->setCurrentIndex(select); } void ArrangeWidget::updateOrientationBox() { QSignalBlocker blocker(ui->orientationBox); ui->orientationBox->setCurrentIndex(d->screen->currentRotation()); } void ArrangeWidget::updateIsPrimary() { ui->primaryDisplaySwitch->setChecked(d->screen->isPrimary()); ui->primaryDisplaySwitch->setEnabled(!d->screen->isPrimary()); } void ArrangeWidget::updatePowered() { QSignalBlocker blocker(ui->enableDisplaySwitch); ui->enableDisplaySwitch->setChecked(d->screen->powered()); ui->displaySettingsWidget->setExpanded(d->screen->powered()); } void ArrangeWidget::updateScreenList() { for (QPushButton* button : d->buttons.values()) { ui->screensLayout->removeWidget(button); button->deleteLater(); } d->buttons.clear(); for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { QPushButton* button = new QPushButton(this); button->setText(screen->displayName()); button->setCheckable(true); button->setAutoExclusive(true); button->setChecked(d->screen == screen); connect(button, &QPushButton::toggled, this, [=](bool checked) { if (checked) setScreen(screen); }); ui->screensLayout->addWidget(button); d->buttons.insert(screen, button); } } void ArrangeWidget::setScreen(SystemScreen* screen) { d->init = true; if (d->screen) { d->screen->disconnect(this); } d->screen = screen; connect(screen, &SystemScreen::rotationChanged, this, &ArrangeWidget::updateOrientationBox); connect(screen, &SystemScreen::geometryChanged, this, &ArrangeWidget::updateScreenGeometry); connect(screen, &SystemScreen::availableModesChanged, this, &ArrangeWidget::updateAvailableModes); connect(screen, &SystemScreen::currentModeChanged, this, &ArrangeWidget::updateAvailableModes); connect(screen, &SystemScreen::isPrimaryChanged, this, &ArrangeWidget::updateIsPrimary); connect(screen, &SystemScreen::poweredChanged, this, &ArrangeWidget::updatePowered); updateScreenGeometry(); updateAvailableModes(); updateOrientationBox(); updateIsPrimary(); updatePowered(); d->buttons.value(screen)->setChecked(true); ui->titleLabel->setText(d->screen->displayName()); d->init = false; } void ArrangeWidget::on_refreshRateBox_currentIndexChanged(int index) { d->screen->setCurrentMode(ui->refreshRateBox->currentData().toInt()); } void ArrangeWidget::on_resolutionBox_currentIndexChanged(int index) { updateRefreshRateBox(); } void ArrangeWidget::on_applyButton_clicked() { for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { screen->set(); } ScreenDaemon::instance()->saveCurrentConfiguration(); } void ArrangeWidget::on_primaryDisplaySwitch_toggled(bool checked) { if (checked) { d->screen->setAsPrimary(); } } void ArrangeWidget::on_orientationBox_currentIndexChanged(int index) { d->screen->setRotation(static_cast(index)); } void ArrangeWidget::on_enableDisplaySwitch_toggled(bool checked) { d->screen->setPowered(checked); } ================================================ FILE: plugins/DisplayPlugin/arrange/arrangewidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ARRANGEWIDGET_H #define ARRANGEWIDGET_H #include namespace Ui { class ArrangeWidget; } class SystemScreen; struct ArrangeWidgetPrivate; class ArrangeWidget : public QWidget { Q_OBJECT public: explicit ArrangeWidget(SystemScreen* screen, QWidget* parent = nullptr); ~ArrangeWidget(); void dismiss(); private slots: void on_titleLabel_backButtonClicked(); void on_refreshRateBox_currentIndexChanged(int index); void on_resolutionBox_currentIndexChanged(int index); void on_applyButton_clicked(); void on_primaryDisplaySwitch_toggled(bool checked); void on_orientationBox_currentIndexChanged(int index); void on_enableDisplaySwitch_toggled(bool checked); signals: void reject(); void accept(); private: Ui::ArrangeWidget* ui; ArrangeWidgetPrivate* d; void updateScreenGeometry(); void updateAvailableModes(); void updateRefreshRateBox(); void updateOrientationBox(); void updateIsPrimary(); void updatePowered(); void updateScreenList(); void setScreen(SystemScreen* screen); }; #endif // MAINARRANGEWIDGET_H ================================================ FILE: plugins/DisplayPlugin/arrange/arrangewidget.ui ================================================ ArrangeWidget 0 0 642 355 Form 0 0 0 0 0 Display Name 0 0 0 0 0 0 0 0 0 0 0 Resolution Refresh Rate Orientation Landscape Portrait Upside Down Portrait (Upside Down) Primary Display PrimaryDisplaySwitch 75 true DISPLAY PROPERTIES 0 0 Enable Display EnableDisplaySwitch Apply Settings Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tSwitch QPushButton
tswitch.h
tConditionalWidget QWidget
tconditionalwidget.h
1
ScreenArranger QWidget
arrange/screenarranger.h
1
================================================ FILE: plugins/DisplayPlugin/arrange/overlaywindow.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "overlaywindow.h" #include "ui_overlaywindow.h" OverlayWindow::OverlayWindow(QWidget* parent) : QDialog(parent), ui(new Ui::OverlayWindow) { ui->setupUi(this); this->setAttribute(Qt::WA_TranslucentBackground); this->setWindowFlag(Qt::FramelessWindowHint); } OverlayWindow::~OverlayWindow() { delete ui; } ================================================ FILE: plugins/DisplayPlugin/arrange/overlaywindow.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef OVERLAYWINDOW_H #define OVERLAYWINDOW_H #include namespace Ui { class OverlayWindow; } class OverlayWindow : public QDialog { Q_OBJECT public: explicit OverlayWindow(QWidget *parent = nullptr); ~OverlayWindow(); private: Ui::OverlayWindow *ui; }; #endif // OVERLAYWINDOW_H ================================================ FILE: plugins/DisplayPlugin/arrange/overlaywindow.ui ================================================ OverlayWindow 0 0 400 300 Dialog ================================================ FILE: plugins/DisplayPlugin/arrange/screenarranger.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "screenarranger.h" #include #include #include #include #include struct Snap { Snap() { valid = false; } Snap(double local, int global) { this->local = local; this->global = global; valid = true; } operator bool() const { return valid; } double local; int global; bool valid; }; struct ScreenArrangerPrivate { QList registeredScreens; SystemScreen* draggedScreen; QPointF initialDragPoint; QPointF dragOffset; Snap snapLeft, snapRight, snapTop, snapBottom; }; ScreenArranger::ScreenArranger(QWidget* parent) : QWidget(parent) { d = new ScreenArrangerPrivate(); connect(ScreenDaemon::instance(), &ScreenDaemon::screensUpdated, this, &ScreenArranger::updateScreens); updateScreens(); } ScreenArranger::~ScreenArranger() { delete d; } QSize ScreenArranger::sizeHint() const { return SC_DPI_T(QSize(0, 300), QSize); } void ScreenArranger::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.setFont(this->font()); painter.setBrush(this->palette().color(QPalette::Window)); painter.setPen(this->palette().color(QPalette::WindowText)); for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { painter.save(); QRectF rect = screenRect(screen); if (d->draggedScreen == screen) rect = draggedScreenRect(rect); painter.fillRect(rect, painter.brush()); if (!screen->powered()) painter.setOpacity(0.5); painter.drawRect(rect); QString text = screen->displayName(); painter.drawText(rect, Qt::AlignCenter, text); painter.restore(); } } double ScreenArranger::scaling() { QRect rect = ScreenDaemon::instance()->screens().first()->geometry(); for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { rect = rect.united(screen->geometry()); } // TODO: better scaling return qMin((this->height() * 0.5) / rect.height(), (this->width() * 0.5) / rect.width()); } QRectF ScreenArranger::totalScreen() { QRectF totalScreen = ScreenDaemon::instance()->screens().first()->geometry(); for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { totalScreen = totalScreen.united(screen->geometry()); } totalScreen = QRectF(totalScreen.topLeft() * scaling(), totalScreen.size() * scaling()); totalScreen.moveCenter(QPoint(this->width() / 2, this->height() / 2)); return totalScreen; } QRectF ScreenArranger::screenRect(SystemScreen* screen) { QRect geometry = screen->geometry(); return QRectF(geometry.topLeft() * scaling(), geometry.size() * scaling()).translated(totalScreen().topLeft()); } QRectF ScreenArranger::draggedScreenRect(QRectF screenRect) { screenRect.translate(d->dragOffset); if (d->snapLeft) screenRect.moveLeft(d->snapLeft.local); if (d->snapRight) screenRect.moveRight(d->snapRight.local); if (d->snapTop) screenRect.moveTop(d->snapTop.local); if (d->snapBottom) screenRect.moveBottom(d->snapBottom.local); return screenRect; } void ScreenArranger::updateScreens() { for (SystemScreen* screen : d->registeredScreens) { screen->disconnect(this); } d->registeredScreens.clear(); for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { connect(screen, &SystemScreen::geometryChanged, this, QOverload<>::of(&ScreenArranger::update)); d->registeredScreens.append(screen); } this->update(); } void ScreenArranger::mousePressEvent(QMouseEvent* event) { for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { if (screenRect(screen).contains(event->pos())) { d->draggedScreen = screen; d->initialDragPoint = event->pos(); d->dragOffset = QPoint(); } } } void ScreenArranger::mouseReleaseEvent(QMouseEvent* event) { if (d->draggedScreen) { QRectF newGeometry = draggedScreenRect(screenRect(d->draggedScreen)).translated(-totalScreen().topLeft()); newGeometry = QRectF(newGeometry.topLeft() / scaling(), newGeometry.size() / scaling()); if (d->snapLeft) newGeometry.moveLeft(d->snapLeft.global); if (d->snapRight) newGeometry.moveRight(d->snapRight.global); if (d->snapTop) newGeometry.moveTop(d->snapTop.global); if (d->snapBottom) newGeometry.moveBottom(d->snapBottom.global); d->draggedScreen->move(newGeometry.topLeft().toPoint()); } d->draggedScreen = nullptr; this->update(); } void ScreenArranger::mouseMoveEvent(QMouseEvent* event) { if (d->draggedScreen) { d->dragOffset = event->pos() - d->initialDragPoint; auto trySnap = [=](Snap* snap, double snapTo, int snapToGlobal, double currentValue) { if ((currentValue < snapTo + SC_DPI(5)) && (currentValue > snapTo - SC_DPI(5))) { *snap = Snap(snapTo, snapToGlobal); } }; d->snapLeft = d->snapRight = d->snapTop = d->snapBottom = Snap(); QRectF geometry = screenRect(d->draggedScreen).translated(d->dragOffset); for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { // Attempt to snap to this screen QRectF snapTo = screenRect(screen); trySnap(&d->snapLeft, snapTo.right(), screen->geometry().right() + 1, geometry.left()); // Left edge to right edge trySnap(&d->snapRight, snapTo.left(), screen->geometry().left(), geometry.right()); // Right edge to left edge trySnap(&d->snapBottom, snapTo.bottom(), screen->geometry().bottom() + 1, geometry.bottom()); // Bottom edge to bottom edge trySnap(&d->snapTop, snapTo.top(), screen->geometry().top(), geometry.top()); // Top edge to top edge trySnap(&d->snapBottom, snapTo.top(), screen->geometry().top(), geometry.bottom()); // Bottom edge to top edge trySnap(&d->snapTop, snapTo.bottom(), screen->geometry().bottom() + 1, geometry.top()); // Top edge to bottom edge } this->update(); } } ================================================ FILE: plugins/DisplayPlugin/arrange/screenarranger.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SCREENARRANGER_H #define SCREENARRANGER_H #include class SystemScreen; struct ScreenArrangerPrivate; class ScreenArranger : public QWidget { Q_OBJECT public: explicit ScreenArranger(QWidget* parent = nullptr); ~ScreenArranger(); QSize sizeHint() const; signals: private: ScreenArrangerPrivate* d; void paintEvent(QPaintEvent* event); double scaling(); QRectF totalScreen(); QRectF screenRect(SystemScreen* screen); QRectF draggedScreenRect(QRectF screenRect); void updateScreens(); // QWidget interface protected: void mousePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); }; #endif // SCREENARRANGER_H ================================================ FILE: plugins/DisplayPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "settings/displaysettings.h" #include "tsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "redshift/redshiftdaemon.h" struct PluginPrivate { DisplaySettings* settingsPage; RedshiftDaemon* daemon; tSettings* settings; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/DisplayPlugin/thedesk-display.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-display.conf"); d->settingsPage = new DisplaySettings(); d->daemon = new RedshiftDaemon(); StateManager::statusCenterManager()->addPane(d->settingsPage, StatusCenterManager::SystemSettings); // Keep screen configuration up to date ScreenDaemon::instance()->enableAutomaticRestore(); d->settings = new tSettings(); connect(d->settings, &tSettings::settingChanged, this, [this] { ScreenDaemon::instance()->setDpi(d->settings->value("Display/dpi").toInt()); }); ScreenDaemon::instance()->setDpi(d->settings->value("Display/dpi").toInt()); } void Plugin::deactivate() { d->daemon->deleteLater(); StateManager::statusCenterManager()->removePane(d->settingsPage); d->settingsPage->deleteLater(); d->settings->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/DisplayPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/DisplayPlugin/redshift/colorramp.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ /* colorramp.c -- color temperature calculation source This file is part of Redshift. Redshift is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Redshift is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Redshift. If not, see . Copyright (c) 2013-2014 Jon Lund Steffensen Copyright (c) 2013 Ingo Thies */ #include "colorramp.h" #include /* Whitepoint values for temperatures at 100K intervals. These will be interpolated for the actual temperature. This table was provided by Ingo Thies, 2013. See the file README-colorramp for more information. */ static const double blackbody_color[] = { 1.00000000, 0.18172716, 0.00000000, /* 1000K */ 1.00000000, 0.25503671, 0.00000000, /* 1100K */ 1.00000000, 0.30942099, 0.00000000, /* 1200K */ 1.00000000, 0.35357379, 0.00000000, /* ... */ 1.00000000, 0.39091524, 0.00000000, 1.00000000, 0.42322816, 0.00000000, 1.00000000, 0.45159884, 0.00000000, 1.00000000, 0.47675916, 0.00000000, 1.00000000, 0.49923747, 0.00000000, 1.00000000, 0.51943421, 0.00000000, 1.00000000, 0.54360078, 0.08679949, 1.00000000, 0.56618736, 0.14065513, 1.00000000, 0.58734976, 0.18362641, 1.00000000, 0.60724493, 0.22137978, 1.00000000, 0.62600248, 0.25591950, 1.00000000, 0.64373109, 0.28819679, 1.00000000, 0.66052319, 0.31873863, 1.00000000, 0.67645822, 0.34786758, 1.00000000, 0.69160518, 0.37579588, 1.00000000, 0.70602449, 0.40267128, 1.00000000, 0.71976951, 0.42860152, 1.00000000, 0.73288760, 0.45366838, 1.00000000, 0.74542112, 0.47793608, 1.00000000, 0.75740814, 0.50145662, 1.00000000, 0.76888303, 0.52427322, 1.00000000, 0.77987699, 0.54642268, 1.00000000, 0.79041843, 0.56793692, 1.00000000, 0.80053332, 0.58884417, 1.00000000, 0.81024551, 0.60916971, 1.00000000, 0.81957693, 0.62893653, 1.00000000, 0.82854786, 0.64816570, 1.00000000, 0.83717703, 0.66687674, 1.00000000, 0.84548188, 0.68508786, 1.00000000, 0.85347859, 0.70281616, 1.00000000, 0.86118227, 0.72007777, 1.00000000, 0.86860704, 0.73688797, 1.00000000, 0.87576611, 0.75326132, 1.00000000, 0.88267187, 0.76921169, 1.00000000, 0.88933596, 0.78475236, 1.00000000, 0.89576933, 0.79989606, 1.00000000, 0.90198230, 0.81465502, 1.00000000, 0.90963069, 0.82838210, 1.00000000, 0.91710889, 0.84190889, 1.00000000, 0.92441842, 0.85523742, 1.00000000, 0.93156127, 0.86836903, 1.00000000, 0.93853986, 0.88130458, 1.00000000, 0.94535695, 0.89404470, 1.00000000, 0.95201559, 0.90658983, 1.00000000, 0.95851906, 0.91894041, 1.00000000, 0.96487079, 0.93109690, 1.00000000, 0.97107439, 0.94305985, 1.00000000, 0.97713351, 0.95482993, 1.00000000, 0.98305189, 0.96640795, 1.00000000, 0.98883326, 0.97779486, 1.00000000, 0.99448139, 0.98899179, 1.00000000, 1.00000000, 1.00000000, /* 6500K */ 0.98947904, 0.99348723, 1.00000000, 0.97940448, 0.98722715, 1.00000000, 0.96975025, 0.98120637, 1.00000000, 0.96049223, 0.97541240, 1.00000000, 0.95160805, 0.96983355, 1.00000000, 0.94303638, 0.96443333, 1.00000000, 0.93480451, 0.95923080, 1.00000000, 0.92689056, 0.95421394, 1.00000000, 0.91927697, 0.94937330, 1.00000000, 0.91194747, 0.94470005, 1.00000000, 0.90488690, 0.94018594, 1.00000000, 0.89808115, 0.93582323, 1.00000000, 0.89151710, 0.93160469, 1.00000000, 0.88518247, 0.92752354, 1.00000000, 0.87906581, 0.92357340, 1.00000000, 0.87315640, 0.91974827, 1.00000000, 0.86744421, 0.91604254, 1.00000000, 0.86191983, 0.91245088, 1.00000000, 0.85657444, 0.90896831, 1.00000000, 0.85139976, 0.90559011, 1.00000000, 0.84638799, 0.90231183, 1.00000000, 0.84153180, 0.89912926, 1.00000000, 0.83682430, 0.89603843, 1.00000000, 0.83225897, 0.89303558, 1.00000000, 0.82782969, 0.89011714, 1.00000000, 0.82353066, 0.88727974, 1.00000000, 0.81935641, 0.88452017, 1.00000000, 0.81530175, 0.88183541, 1.00000000, 0.81136180, 0.87922257, 1.00000000, 0.80753191, 0.87667891, 1.00000000, 0.80380769, 0.87420182, 1.00000000, 0.80018497, 0.87178882, 1.00000000, 0.79665980, 0.86943756, 1.00000000, 0.79322843, 0.86714579, 1.00000000, 0.78988728, 0.86491137, 1.00000000, /* 10000K */ 0.78663296, 0.86273225, 1.00000000, 0.78346225, 0.86060650, 1.00000000, 0.78037207, 0.85853224, 1.00000000, 0.77735950, 0.85650771, 1.00000000, 0.77442176, 0.85453121, 1.00000000, 0.77155617, 0.85260112, 1.00000000, 0.76876022, 0.85071588, 1.00000000, 0.76603147, 0.84887402, 1.00000000, 0.76336762, 0.84707411, 1.00000000, 0.76076645, 0.84531479, 1.00000000, 0.75822586, 0.84359476, 1.00000000, 0.75574383, 0.84191277, 1.00000000, 0.75331843, 0.84026762, 1.00000000, 0.75094780, 0.83865816, 1.00000000, 0.74863017, 0.83708329, 1.00000000, 0.74636386, 0.83554194, 1.00000000, 0.74414722, 0.83403311, 1.00000000, 0.74197871, 0.83255582, 1.00000000, 0.73985682, 0.83110912, 1.00000000, 0.73778012, 0.82969211, 1.00000000, 0.73574723, 0.82830393, 1.00000000, 0.73375683, 0.82694373, 1.00000000, 0.73180765, 0.82561071, 1.00000000, 0.72989845, 0.82430410, 1.00000000, 0.72802807, 0.82302316, 1.00000000, 0.72619537, 0.82176715, 1.00000000, 0.72439927, 0.82053539, 1.00000000, 0.72263872, 0.81932722, 1.00000000, 0.72091270, 0.81814197, 1.00000000, 0.71922025, 0.81697905, 1.00000000, 0.71756043, 0.81583783, 1.00000000, 0.71593234, 0.81471775, 1.00000000, 0.71433510, 0.81361825, 1.00000000, 0.71276788, 0.81253878, 1.00000000, 0.71122987, 0.81147883, 1.00000000, 0.70972029, 0.81043789, 1.00000000, 0.70823838, 0.80941546, 1.00000000, 0.70678342, 0.80841109, 1.00000000, 0.70535469, 0.80742432, 1.00000000, 0.70395153, 0.80645469, 1.00000000, 0.70257327, 0.80550180, 1.00000000, 0.70121928, 0.80456522, 1.00000000, 0.69988894, 0.80364455, 1.00000000, 0.69858167, 0.80273941, 1.00000000, 0.69729688, 0.80184943, 1.00000000, 0.69603402, 0.80097423, 1.00000000, 0.69479255, 0.80011347, 1.00000000, 0.69357196, 0.79926681, 1.00000000, 0.69237173, 0.79843391, 1.00000000, 0.69119138, 0.79761446, 1.00000000, /* 15000K */ 0.69003044, 0.79680814, 1.00000000, 0.68888844, 0.79601466, 1.00000000, 0.68776494, 0.79523371, 1.00000000, 0.68665951, 0.79446502, 1.00000000, 0.68557173, 0.79370830, 1.00000000, 0.68450119, 0.79296330, 1.00000000, 0.68344751, 0.79222975, 1.00000000, 0.68241029, 0.79150740, 1.00000000, 0.68138918, 0.79079600, 1.00000000, 0.68038380, 0.79009531, 1.00000000, 0.67939381, 0.78940511, 1.00000000, 0.67841888, 0.78872517, 1.00000000, 0.67745866, 0.78805526, 1.00000000, 0.67651284, 0.78739518, 1.00000000, 0.67558112, 0.78674472, 1.00000000, 0.67466317, 0.78610368, 1.00000000, 0.67375872, 0.78547186, 1.00000000, 0.67286748, 0.78484907, 1.00000000, 0.67198916, 0.78423512, 1.00000000, 0.67112350, 0.78362984, 1.00000000, 0.67027024, 0.78303305, 1.00000000, 0.66942911, 0.78244457, 1.00000000, 0.66859988, 0.78186425, 1.00000000, 0.66778228, 0.78129191, 1.00000000, 0.66697610, 0.78072740, 1.00000000, 0.66618110, 0.78017057, 1.00000000, 0.66539706, 0.77962127, 1.00000000, 0.66462376, 0.77907934, 1.00000000, 0.66386098, 0.77854465, 1.00000000, 0.66310852, 0.77801705, 1.00000000, 0.66236618, 0.77749642, 1.00000000, 0.66163375, 0.77698261, 1.00000000, 0.66091106, 0.77647551, 1.00000000, 0.66019791, 0.77597498, 1.00000000, 0.65949412, 0.77548090, 1.00000000, 0.65879952, 0.77499315, 1.00000000, 0.65811392, 0.77451161, 1.00000000, 0.65743716, 0.77403618, 1.00000000, 0.65676908, 0.77356673, 1.00000000, 0.65610952, 0.77310316, 1.00000000, 0.65545831, 0.77264537, 1.00000000, 0.65481530, 0.77219324, 1.00000000, 0.65418036, 0.77174669, 1.00000000, 0.65355332, 0.77130560, 1.00000000, 0.65293404, 0.77086988, 1.00000000, 0.65232240, 0.77043944, 1.00000000, 0.65171824, 0.77001419, 1.00000000, 0.65112144, 0.76959404, 1.00000000, 0.65053187, 0.76917889, 1.00000000, 0.64994941, 0.76876866, 1.00000000, /* 20000K */ 0.64937392, 0.76836326, 1.00000000, 0.64880528, 0.76796263, 1.00000000, 0.64824339, 0.76756666, 1.00000000, 0.64768812, 0.76717529, 1.00000000, 0.64713935, 0.76678844, 1.00000000, 0.64659699, 0.76640603, 1.00000000, 0.64606092, 0.76602798, 1.00000000, 0.64553103, 0.76565424, 1.00000000, 0.64500722, 0.76528472, 1.00000000, 0.64448939, 0.76491935, 1.00000000, 0.64397745, 0.76455808, 1.00000000, 0.64347129, 0.76420082, 1.00000000, 0.64297081, 0.76384753, 1.00000000, 0.64247594, 0.76349813, 1.00000000, 0.64198657, 0.76315256, 1.00000000, 0.64150261, 0.76281076, 1.00000000, 0.64102399, 0.76247267, 1.00000000, 0.64055061, 0.76213824, 1.00000000, 0.64008239, 0.76180740, 1.00000000, 0.63961926, 0.76148010, 1.00000000, 0.63916112, 0.76115628, 1.00000000, 0.63870790, 0.76083590, 1.00000000, 0.63825953, 0.76051890, 1.00000000, 0.63781592, 0.76020522, 1.00000000, 0.63737701, 0.75989482, 1.00000000, 0.63694273, 0.75958764, 1.00000000, 0.63651299, 0.75928365, 1.00000000, 0.63608774, 0.75898278, 1.00000000, 0.63566691, 0.75868499, 1.00000000, 0.63525042, 0.75839025, 1.00000000, 0.63483822, 0.75809849, 1.00000000, 0.63443023, 0.75780969, 1.00000000, 0.63402641, 0.75752379, 1.00000000, 0.63362667, 0.75724075, 1.00000000, 0.63323097, 0.75696053, 1.00000000, 0.63283925, 0.75668310, 1.00000000, 0.63245144, 0.75640840, 1.00000000, 0.63206749, 0.75613641, 1.00000000, 0.63168735, 0.75586707, 1.00000000, 0.63131096, 0.75560036, 1.00000000, 0.63093826, 0.75533624, 1.00000000, 0.63056920, 0.75507467, 1.00000000, 0.63020374, 0.75481562, 1.00000000, 0.62984181, 0.75455904, 1.00000000, 0.62948337, 0.75430491, 1.00000000, 0.62912838, 0.75405319, 1.00000000, 0.62877678, 0.75380385, 1.00000000, 0.62842852, 0.75355685, 1.00000000, 0.62808356, 0.75331217, 1.00000000, 0.62774186, 0.75306977, 1.00000000, /* 25000K */ 0.62740336, 0.75282962, 1.00000000 /* 25100K */ }; /* Helper macro used in the fill functions */ //#define F(Y, C) Y * white_point[C] static void interpolate_color(double a, const double* c1, const double* c2, double* c) { c[0] = (1.0 - a) * c1[0] + a * c2[0]; c[1] = (1.0 - a) * c1[1] + a * c2[1]; c[2] = (1.0 - a) * c1[2] + a * c2[2]; } void colorramp_fill(quint16* gamma_r, quint16* gamma_g, quint16* gamma_b, int size, const int temperature) { /* Approximate white point */ double white_point[3]; double alpha = (temperature % 100) / 100.0; int temp_index = ((temperature - 1000) / 100) * 3; interpolate_color(alpha, &blackbody_color[temp_index], &blackbody_color[temp_index + 3], white_point); for (int i = 0; i < size; i++) { quint16 initialValue = static_cast(i / size * (UINT16_MAX + 1)); gamma_r[i] = static_cast(initialValue / (UINT16_MAX + 1) * white_point[0] * (UINT16_MAX + 1)); gamma_g[i] = static_cast(initialValue / (UINT16_MAX + 1) * white_point[1] * (UINT16_MAX + 1)); gamma_b[i] = static_cast(initialValue / (UINT16_MAX + 1) * white_point[2] * (UINT16_MAX + 1)); } } void gammaRampsForTemp(double* gamma_r, double* gamma_g, double* gamma_b, int temperature) { /* Approximate white point */ double white_point[3]; double alpha = (temperature % 100) / 100.0; int temp_index = ((temperature - 1000) / 100) * 3; interpolate_color(alpha, &blackbody_color[temp_index], &blackbody_color[temp_index + 3], white_point); *gamma_r = white_point[0]; *gamma_g = white_point[1]; *gamma_b = white_point[2]; } ================================================ FILE: plugins/DisplayPlugin/redshift/colorramp.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ /* colorramp.h -- color temperature calculation header This file is part of Redshift. Redshift is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Redshift is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Redshift. If not, see . Copyright (c) 2010-2014 Jon Lund Steffensen */ #ifndef COLORRAMP_H #define COLORRAMP_H #include void colorramp_fill(quint16* gamma_r, quint16* gamma_g, quint16* gamma_b, int size, const int temperature); void gammaRampsForTemp(double* gamma_r, double* gamma_g, double* gamma_b, int temperature); #endif // COLORRAMP_H ================================================ FILE: plugins/DisplayPlugin/redshift/redshiftdaemon.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "redshiftdaemon.h" #include "redshift/colorramp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include //#include struct RedshiftDaemonPrivate { enum RedshiftState { Initialising, Idle, ManualOff, ManualOn, Scheduled }; QTimer* redshiftStateTimer; QuickSwitch* sw; IconTextChunk* chunk; RedshiftState state = Initialising; bool updatingState = false; tSettings settings; // twMeteorology* meteorologyDaemon; QGeoPositionInfoSource* positonSource = nullptr; }; RedshiftDaemon::RedshiftDaemon(QObject* parent) : QObject(parent) { d = new RedshiftDaemonPrivate(); // d->meteorologyDaemon = new twMeteorology(this); // connect(d->meteorologyDaemon, &twMeteorology::sunriseSunsetChanged, this, [ = ] { // if (d->settings.value("Redshift/followSunlightCycle").toBool()) { // if (!d->meteorologyDaemon->sunset().isNull()) { // d->settings.setValue("Redshift/startTime", d->meteorologyDaemon->sunset().msecsSinceStartOfDay()); // d->settings.setValue("Redshift/endTime", d->meteorologyDaemon->sunrise().msecsSinceStartOfDay()); // } // } // }); d->sw = new QuickSwitch("Redshift"); d->sw->setTitle("Redshift"); connect(d->sw, &QuickSwitch::toggled, this, [=](bool on) { if (d->updatingState) return; // We'll only get here if the user manually toggled the switch d->state = on ? RedshiftDaemonPrivate::ManualOn : RedshiftDaemonPrivate::ManualOff; updateRedshiftState(); }); StateManager::statusCenterManager()->addSwitch(d->sw); d->chunk = new IconTextChunk("redshift"); d->chunk->setIcon(QIcon::fromTheme("redshift-on")); d->chunk->setText(tr("Redshift Active")); ActionQuickWidget* quickWidget = new ActionQuickWidget(d->chunk); quickWidget->addAction(QIcon::fromTheme("redshift-on"), tr("Disable Redshift until tomorrow"), [=] { d->sw->setChecked(false); }); quickWidget->addAction(QIcon::fromTheme("configure"), tr("Display Settings"), [=] { StateManager::statusCenterManager()->showWithPane("DisplaySettings"); }); d->chunk->setQuickWidget(quickWidget); d->redshiftStateTimer = new QTimer(); d->redshiftStateTimer->setInterval(60000); connect(d->redshiftStateTimer, &QTimer::timeout, this, &RedshiftDaemon::updateRedshiftState); if (d->settings.value("Redshift/scheduleRedshift").toBool()) d->redshiftStateTimer->start(); connect(&d->settings, &tSettings::settingChanged, this, [=](QString key, QVariant value) { if (key.startsWith("Redshift/")) { // Turn on/off the Redshift timer if (key == "Redshift/scheduleRedshift") { if (value.toBool()) { d->redshiftStateTimer->start(); } else { d->redshiftStateTimer->stop(); } // Recalculate the Redshift state this->updateRedshiftState(); } else if (key == "Redshift/followSunlightCycle") { updateSunlightCycleState(); } } }); this->updateRedshiftState(); this->updateSunlightCycleState(); } RedshiftDaemon::~RedshiftDaemon() { StateManager::statusCenterManager()->removeSwitch(d->sw); d->sw->deleteLater(); d->chunk->deleteLater(); delete d; } void RedshiftDaemon::updateRedshiftState() { d->updatingState = true; int time = QTime::currentTime().msecsSinceStartOfDay(); const int transitionTime = 1800000; // half an hour bool scheduled = d->settings.value("Redshift/scheduleRedshift").toBool(); int intensity = d->settings.value("Redshift/intensity").toInt(); // Time right in the middle of the transition time int startTime = d->settings.value("Redshift/startTime").toInt(); int endTime = d->settings.value("Redshift/endTime").toInt(); bool scheduledShouldBeOnMidTransitionTime = false; // First/last time when Redshift should be fully off int startTimeTransitionTime = startTime - transitionTime; int endTimeTransitionTime = endTime + transitionTime; bool scheduledShouldBeOn = false; // First/last time when Redshift should be fully on int startTimeFullTime = startTime + transitionTime; int endTimeFullTime = endTime - transitionTime; bool scheduledShouldBeOnFully = false; if (startTime > endTime) { // We're going overnight if (time > startTimeTransitionTime || time < endTimeTransitionTime) scheduledShouldBeOn = true; if (time > startTime || time < endTime) scheduledShouldBeOnMidTransitionTime = true; if (time > startTimeFullTime || time < endTimeFullTime) scheduledShouldBeOnFully = true; } else { if (time > startTimeTransitionTime && time < endTimeTransitionTime) scheduledShouldBeOn = true; if (time > startTime && time < endTime) scheduledShouldBeOnMidTransitionTime = true; if (time > startTimeFullTime && time < endTimeFullTime) scheduledShouldBeOnFully = true; } switch (d->state) { case RedshiftDaemonPrivate::Idle: case RedshiftDaemonPrivate::Initialising: if (scheduled) { // Set the appropriate state and recalculate the Redshift state d->state = RedshiftDaemonPrivate::Scheduled; updateRedshiftState(); } else { d->state = RedshiftDaemonPrivate::Idle; setRedshiftTemperature(6500); d->sw->setChecked(false); } break; case RedshiftDaemonPrivate::ManualOff: if (scheduled && !scheduledShouldBeOn) { // Revert to the schedule if we've ticked into the correct time d->state = RedshiftDaemonPrivate::Scheduled; } else if (!scheduled) { // Revert to the idle state if we're not scheduled d->state = RedshiftDaemonPrivate::Idle; setRedshiftTemperature(6500); } else { setRedshiftTemperature(6500); } break; case RedshiftDaemonPrivate::ManualOn: if (scheduled && scheduledShouldBeOnFully) { // Revert to the schedule if we've ticked into the correct time d->state = RedshiftDaemonPrivate::Scheduled; updateRedshiftState(); } else { setRedshiftTemperature(intensity); } break; case RedshiftDaemonPrivate::Scheduled: if (!scheduled) { // Set the appropriate state and recalculate the Redshift state d->state = RedshiftDaemonPrivate::Idle; updateRedshiftState(); } else { // Calculate the appropriate Redshift temperature and set it if (!scheduledShouldBeOn) { // Redshift shouldn't be on setRedshiftTemperature(6500); } else if (scheduledShouldBeOnFully) { // Redshift should be on fully setRedshiftTemperature(intensity); } else { // Figure out how intense the Redshift should be int midIntensity; if (time < startTimeFullTime && time > startTimeTransitionTime) { // Use start time values midIntensity = (6500 - intensity) - static_cast((6500 - intensity) * static_cast(time - startTimeTransitionTime) / (transitionTime * 2)) + intensity; } else { // Use end time values midIntensity = static_cast((6500 - intensity) * static_cast(time - endTimeFullTime) / (transitionTime * 2)) + intensity; } setRedshiftTemperature(midIntensity); } // Set the Redshift switch accordingly d->sw->setChecked(scheduledShouldBeOn); } break; } d->updatingState = false; } void RedshiftDaemon::updateSunlightCycleState() { if (d->settings.value("Redshift/followSunlightCycle").toBool()) { if (!d->positonSource) { d->positonSource = QGeoPositionInfoSource::createDefaultSource(this); d->positonSource->setPreferredPositioningMethods(QGeoPositionInfoSource::NonSatellitePositioningMethods); d->positonSource->setUpdateInterval(3600000); // Once an hour connect(d->positonSource, &QGeoPositionInfoSource::positionUpdated, this, [=](QGeoPositionInfo position) { // d->meteorologyDaemon->setLocation(position.coordinate().latitude(), position.coordinate().longitude()); }); } d->positonSource->startUpdates(); } else { if (d->positonSource) { d->positonSource->stopUpdates(); d->positonSource->deleteLater(); d->positonSource = nullptr; } } } void RedshiftDaemon::setRedshiftTemperature(int temp) { // Show/hide the chunk if (!d->chunk->chunkRegistered() && temp != 6500) { StateManager::barManager()->addChunk(d->chunk); } else if (d->chunk->chunkRegistered() && temp == 6500) { StateManager::barManager()->removeChunk(d->chunk); } for (SystemScreen* screen : ScreenDaemon::instance()->screens()) { SystemScreen::GammaRamps ramps; gammaRampsForTemp(&ramps.red, &ramps.green, &ramps.blue, temp); screen->adjustGammaRamps("redshift", ramps); } } ================================================ FILE: plugins/DisplayPlugin/redshift/redshiftdaemon.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef REDSHIFTDAEMON_H #define REDSHIFTDAEMON_H #include struct RedshiftDaemonPrivate; class RedshiftDaemon : public QObject { Q_OBJECT public: explicit RedshiftDaemon(QObject* parent = nullptr); ~RedshiftDaemon(); signals: private: RedshiftDaemonPrivate* d; void updateRedshiftState(); void updateSunlightCycleState(); void setRedshiftTemperature(int temp); }; #endif // REDSHIFTDAEMON_H ================================================ FILE: plugins/DisplayPlugin/settings/displaysettings.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "displaysettings.h" #include "ui_displaysettings.h" #include #include #include #include #include "arrange/arrangecontroller.h" struct DisplaySettingsPrivate { tSettings settings; }; DisplaySettings::DisplaySettings() : StatusCenterPane(), ui(new Ui::DisplaySettings) { ui->setupUi(this); d = new DisplaySettingsPrivate(); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->arrangeWidget->setFixedWidth(contentWidth); ui->arrangeButton->setFixedWidth(contentWidth); ui->scalingWidget->setFixedWidth(contentWidth); ui->redshiftWidget->setFixedWidth(contentWidth); connect(&d->settings, &tSettings::settingChanged, this, [ = ](QString key) { if (key.startsWith("Redshift/")) { updateRedshiftSettings(); } else if (key == "Display/dpi") { updateDpiSettings(); } }); updateRedshiftSettings(); updateDpiSettings(); } DisplaySettings::~DisplaySettings() { delete d; delete ui; } void DisplaySettings::updateRedshiftSettings() { ui->scheduleRedshiftSwitch->setChecked(d->settings.value("Redshift/scheduleRedshift").toBool()); ui->followSunlightSwitch->setChecked(d->settings.value("Redshift/followSunlightCycle").toBool()); ui->redshiftStartTime->setTime(QTime::fromMSecsSinceStartOfDay(d->settings.value("Redshift/startTime").toInt())); ui->redshiftEndTime->setTime(QTime::fromMSecsSinceStartOfDay(d->settings.value("Redshift/endTime").toInt())); ui->redshiftIntensitySlider->setValue(d->settings.value("Redshift/intensity").toInt()); ui->scheduleRedshiftConditionalWidget->setExpanded(d->settings.value("Redshift/scheduleRedshift").toBool()); ui->followSunlightConditionalWidget->setExpanded(!d->settings.value("Redshift/followSunlightCycle").toBool()); } void DisplaySettings::updateDpiSettings() { switch (d->settings.value("Display/dpi").toInt()) { case 96: ui->dpi100Button->setChecked(true); break; case 120: ui->dpi125Button->setChecked(true); break; case 144: ui->dpi150Button->setChecked(true); break; case 192: ui->dpi200Button->setChecked(true); break; } } QString DisplaySettings::name() { return "DisplaySettings"; } QString DisplaySettings::displayName() { return tr("Displays"); } QIcon DisplaySettings::icon() { return QIcon::fromTheme("preferences-desktop-display"); } QWidget* DisplaySettings::leftPane() { return nullptr; } void DisplaySettings::on_titleLabel_backButtonClicked() { StateManager::instance()->statusCenterManager()->showStatusCenterHamburgerMenu(); } void DisplaySettings::on_scheduleRedshiftSwitch_toggled(bool checked) { ui->scheduleRedshiftConditionalWidget->setExpanded(checked); d->settings.setValue("Redshift/scheduleRedshift", checked); } void DisplaySettings::on_followSunlightSwitch_toggled(bool checked) { ui->followSunlightConditionalWidget->setExpanded(!checked); d->settings.setValue("Redshift/followSunlightCycle", checked); } void DisplaySettings::on_redshiftStartTime_userTimeChanged(const QTime& time) { d->settings.setValue("Redshift/startTime", time.msecsSinceStartOfDay()); } void DisplaySettings::on_redshiftEndTime_userTimeChanged(const QTime& time) { d->settings.setValue("Redshift/endTime", time.msecsSinceStartOfDay()); } void DisplaySettings::on_redshiftIntensitySlider_valueChanged(int value) { d->settings.setValue("Redshift/intensity", value); } void DisplaySettings::on_arrangeButton_clicked() { StateManager::statusCenterManager()->hide(); ArrangeController* controller = new ArrangeController(); connect(controller, &ArrangeController::done, controller, &ArrangeController::deleteLater); controller->begin(); } void DisplaySettings::on_dpi100Button_toggled(bool checked) { if (checked) { d->settings.setValue("Display/dpi", 96); StateManager::statusCenterManager()->requestLogout(); } } void DisplaySettings::on_dpi125Button_toggled(bool checked) { if (checked) { d->settings.setValue("Display/dpi", 120); StateManager::statusCenterManager()->requestLogout(); } } void DisplaySettings::on_dpi150Button_toggled(bool checked) { if (checked) { d->settings.setValue("Display/dpi", 144); StateManager::statusCenterManager()->requestLogout(); } } void DisplaySettings::on_dpi200Button_toggled(bool checked) { if (checked) { d->settings.setValue("Display/dpi", 192); StateManager::statusCenterManager()->requestLogout(); } } void DisplaySettings::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/DisplayPlugin/settings/displaysettings.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef DISPLAYSETTINGS_H #define DISPLAYSETTINGS_H #include #include namespace Ui { class DisplaySettings; } struct DisplaySettingsPrivate; class DisplaySettings : public StatusCenterPane { Q_OBJECT public: explicit DisplaySettings(); ~DisplaySettings(); private: Ui::DisplaySettings* ui; DisplaySettingsPrivate* d; void updateRedshiftSettings(); void updateDpiSettings(); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); private slots: void on_titleLabel_backButtonClicked(); void on_scheduleRedshiftSwitch_toggled(bool checked); void on_followSunlightSwitch_toggled(bool checked); void on_redshiftStartTime_userTimeChanged(const QTime& time); void on_redshiftEndTime_userTimeChanged(const QTime& time); void on_redshiftIntensitySlider_valueChanged(int value); void on_arrangeButton_clicked(); void on_dpi100Button_toggled(bool checked); void on_dpi125Button_toggled(bool checked); void on_dpi150Button_toggled(bool checked); void on_dpi200Button_toggled(bool checked); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // DISPLAYSETTINGS_H ================================================ FILE: plugins/DisplayPlugin/settings/displaysettings.ui ================================================ DisplaySettings 0 0 500 375 Form 0 0 0 0 0 Displays QFrame::NoFrame true 0 0 486 570 0 0 0 0 0 75 true SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays Qt::Vertical QSizePolicy::Fixed 20 9 16777215 1 Qt::Horizontal 75 true SCALING If items on the screen are too small, you can scale them up to make them easier to see. true 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) 16777215 1 Qt::Horizontal 0 0 Schedule Redshift 75 true REDSHIFT Redshift blocks blue light so that you can sleep better at night scheduleRedshiftSwitch Intensity 1000 6500 Qt::Horizontal 0 0 0 0 followSunlightSwitch 0 0 Follow Sunlight Cycle 0 0 0 0 0 0 Start at End at false Your physical location will be sent to MET Norway to determine sunrise and sunset times. true Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tSwitch QPushButton
tswitch.h
tConditionalWidget QWidget
tconditionalwidget.h
1
scrollArea scheduleRedshiftSwitch followSunlightSwitch redshiftStartTime redshiftEndTime redshiftIntensitySlider
================================================ FILE: plugins/DisplayPlugin/thedesk-display.conf ================================================ [Redshift] scheduleRedshift=false followSunlightCycle=false startTime=61200000 endTime=21600000 intensity=4000 ================================================ FILE: plugins/DisplayPlugin/translations/ar_SA.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/au_AU.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/cy.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/da.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/de.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/en_GB.ts ================================================ ArrangeWidget DISPLAY PROPERTIES DISPLAY PROPERTIES Resolution Resolution Refresh Rate Refresh Rate %1 hz %1 hz Apply Settings Apply Settings Primary Display Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display DisplaySettings Displays Displays REDSHIFT REDSHIFT Redshift blocks blue light so that you can sleep better at night Redshift blocks blue light so that you can sleep better at night Schedule Redshift Schedule Redshift Intensity Intensity Follow Sunlight Cycle Follow Sunlight Cycle Start at Start at End at End at SCREENS SCREENS Change the resolution of your display and arrange your displays Change the resolution of your display and arrange your displays Arrange and Resize Displays Arrange and Resize Displays Your physical location will be sent to MET Norway to determine sunrise and sunset times. Your physical location will be sent to MET Norway to determine sunrise and sunset times. SCALING SCALING If items on the screen are too small, you can scale them up to make them easier to see. If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 100% (96 DPI) 125% (120 DPI) 125% (120 DPI) 150% (144 DPI) 150% (144 DPI) 200% (192 DPI) 200% (192 DPI) RedshiftDaemon Redshift Active Redshift Active Disable Redshift until tomorrow Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/en_US.qm ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/es.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/es_VE.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/id.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/nl.ts ================================================ ArrangeWidget DISPLAY PROPERTIES BEELDEIGENSCHAPPEN Refresh Rate Verversingssnelheid Resolution Resolutie Primary Display Primair Beeld Orientation Oriëntatie Landscape Landschap Portrait Portret Upside Down Ondersteboven Portrait (Upside Down) Portret (Ondersteboven) Enable Display Scherm Inschakelen Apply Settings Instellingen Toepassen %1 hz %1 Hz DisplaySettings Displays Schermen SCREENS SCHERMEN Change the resolution of your display and arrange your displays De resolutie van het beeld aanpassen en je schermen verplaatsen Arrange and Resize Displays Schermen Verplaatsen en van Formaat Wijzigen SCALING SCHALEN If items on the screen are too small, you can scale them up to make them easier to see. Als dingen op het scherm te klein zijn, kun je ze opschalen, zodat ze makkelijker te zien zijn. 100% (96 DPI) 100% (96 DPI) 125% (120 DPI) 125% (120 DPI) 150% (144 DPI) 150% (144 DPI) 200% (192 DPI) 200% (192 DPI) Schedule Redshift Redshift Plannen REDSHIFT REDSHIFT Redshift blocks blue light so that you can sleep better at night Redshift blokkeert blauw licht zodat je 's nachts beter kunt slapen Intensity Intensiteit Follow Sunlight Cycle Zonlichtcyclus Volgen Start at Beginnen Om End at Eindigen Om Your physical location will be sent to MET Norway to determine sunrise and sunset times. Je fysieke locatie zal worden opgestuurd naar MET Norway om de tijden van zonsopkomst en -ondergang te bepalen. RedshiftDaemon Redshift Active Redshift Actief Disable Redshift until tomorrow Redshift uitschakelen tot morgen Display Settings Beeldinstellingen ================================================ FILE: plugins/DisplayPlugin/translations/pt_BR.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/ro_RO.ts ================================================ ArrangeWidget DISPLAY PROPERTIES PROPRIETĂȚILE ECRANULUI Resolution Rezoluție Refresh Rate Rată de reîmprospătare %1 hz %1 hz Apply Settings Aplică setările Primary Display Monitor principal Orientation Orientație Landscape Peisaj Portrait Portret Upside Down Invers Portrait (Upside Down) Portret(invers) Enable Display Folosiți ecranul DisplaySettings Displays Monitoare REDSHIFT Redshift Redshift blocks blue light so that you can sleep better at night Redshift blochează lumina albastră ca să puteți dormi mai bine noaptea Schedule Redshift Programați Redshift Intensity Intensitate Follow Sunlight Cycle Urmărește ciclul solar Start at Începe la End at Termină la SCREENS ECRANE Change the resolution of your display and arrange your displays Schimbați rezoluția și aranjați monitoarele Arrange and Resize Displays Aranjează și redimensionează monitoarele Your physical location will be sent to MET Norway to determine sunrise and sunset times. Locația dumneavoastră va fi trimisă la MET Norway pentru a determina ora răsăritului și a apusului. SCALING SCALARE If items on the screen are too small, you can scale them up to make them easier to see. Dacă lucrurile de pe ecran sunt prea mici, puteți să le măriți pentru a le face mai ușor de văzut. 100% (96 DPI) 100% (96DPI) 125% (120 DPI) 125% (120 DPI) 150% (144 DPI) 150% (144 DPI) 200% (192 DPI) 200% (192 DPI) RedshiftDaemon Redshift Active Redshift activ Disable Redshift until tomorrow Dezactivează Redshift până mâine Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/sv.ts ================================================ ArrangeWidget DISPLAY PROPERTIES Refresh Rate Resolution Primary Display Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display Apply Settings %1 hz DisplaySettings Displays SCREENS Change the resolution of your display and arrange your displays Arrange and Resize Displays SCALING If items on the screen are too small, you can scale them up to make them easier to see. 100% (96 DPI) 125% (120 DPI) 150% (144 DPI) 200% (192 DPI) Schedule Redshift REDSHIFT Redshift blocks blue light so that you can sleep better at night Intensity Follow Sunlight Cycle Start at End at Your physical location will be sent to MET Norway to determine sunrise and sunset times. RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/tr_TR.ts ================================================ ArrangeWidget DISPLAY PROPERTIES GÖRÜNTÜ ÖZELLİKLERİ Resolution Ekran boyutu Refresh Rate Yenileme hızı %1 hz %1 hz Apply Settings Ayarları uygula Primary Display Birincil Ekran Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display DisplaySettings Displays Görüntüler REDSHIFT KIRMIZIÜSTKARAKTER Redshift blocks blue light so that you can sleep better at night Kirmizi Üst karakter geceleri daha iyi uyuyabilmeniz için mavi ışığı engeller Schedule Redshift Kirmizi Üstkarakter'i planlayın Intensity Yoğunluk Follow Sunlight Cycle Sunlight Cycle'ı Takip Edin Start at Başlamak End at Bitiş noktasında SCREENS EKRANLAR Change the resolution of your display and arrange your displays Ekranınızın çözünürlüğünü değiştirin ve ekranlarınızı düzenleyin Arrange and Resize Displays Ekranları Düzenleme ve Yeniden Boyutlandırma Your physical location will be sent to MET Norway to determine sunrise and sunset times. Fiziksel konumunuz, gün doğumu ve gün batımı saatlerini belirlemek için MET Norveç'e gönderilecektir. SCALING ÖLÇEKLENDİRME If items on the screen are too small, you can scale them up to make them easier to see. Ekrandaki öğeler çok küçükse, daha kolay görülmelerini sağlamak için ölçeklerini büyütebilirsiniz. 100% (96 DPI) 100% (96 DPI) 125% (120 DPI) 125% (120 DPI) 150% (144 DPI) 150% (144 DPI) 200% (192 DPI) 200% (192 DPI) RedshiftDaemon Redshift Active Kırmızı ÜstKarakter Aktif Disable Redshift until tomorrow Kırmızı ÜstKarakter'i yarına kadar devre dışı bırakın Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/vi_VN.ts ================================================ ArrangeWidget DISPLAY PROPERTIES THUỘC TÍNH MÀN HÌNH Resolution Độ phân giải Refresh Rate Tốc độ làm tươi %1 hz %1 hz Apply Settings Áp dụng cài đặt Primary Display Màn hình chính Orientation Hướng Landscape Ngang Portrait Dọc Upside Down Lật ngược Portrait (Upside Down) Dọc (Lật ngược) Enable Display Bật màn hình DisplaySettings Displays Màn hình REDSHIFT REDSHIFT Redshift blocks blue light so that you can sleep better at night Redshift chặn ánh sáng màu lam để cho bạn ngủ ngon hơn vào ban đêm Schedule Redshift Lên lịch Redshift Intensity Cường độ Follow Sunlight Cycle Theo mặt trời Start at Bật End at Tắt SCREENS MÀN HÌNH Change the resolution of your display and arrange your displays Đổi độ phân giải và sắp xếp màn hình của bạn Arrange and Resize Displays Điều chỉnh màn hình Your physical location will be sent to MET Norway to determine sunrise and sunset times. Vị trí thực của bạn sẽ bị gửi đến MET Norway để xác định thời gian mặt trời mọc và lặn. SCALING TỶ LỆ PHÓNG TO If items on the screen are too small, you can scale them up to make them easier to see. Nếu mục trên màn hình quá nhỏ, bạn có thể phóng to các mục để cho bạn xem dễ hơn. 100% (96 DPI) 100% (96 DPI) 125% (120 DPI) 125% (120 DPI) 150% (144 DPI) 150% (144 DPI) 200% (192 DPI) 200% (192 DPI) RedshiftDaemon Redshift Active Redshift hoạt động Disable Redshift until tomorrow Vô hiệu Redshift đến khi ngày mai Display Settings ================================================ FILE: plugins/DisplayPlugin/translations/zh_CN.ts ================================================ ArrangeWidget DISPLAY PROPERTIES 显示器属性 Resolution 分辨率 Refresh Rate 刷新率 %1 hz %1 hz Apply Settings 应用设置 Primary Display 主屏幕 Orientation Landscape Portrait Upside Down Portrait (Upside Down) Enable Display DisplaySettings Displays 显示器 REDSHIFT 夜间模式 Redshift blocks blue light so that you can sleep better at night 夜间模式能帮助您阻挡蓝光 Schedule Redshift 安排夜间模式时间 Intensity 强度 Follow Sunlight Cycle 跟随日光周期 Start at 开始于 End at 结束于 SCREENS 屏幕 Change the resolution of your display and arrange your displays 更改和整理你的屏幕分辨率 Arrange and Resize Displays 整理和更改显示器大小 Your physical location will be sent to MET Norway to determine sunrise and sunset times. 你的设备地点将会被发送到MET Norway。 SCALING 缩放 If items on the screen are too small, you can scale them up to make them easier to see. 如果屏幕上的物品太小, 你可以将其放大。 100% (96 DPI) 100% (96 DPI) 125% (120 DPI) 125% (120 DPI) 150% (144 DPI) 150% (144 DPI) 200% (192 DPI) 200% (192 DPI) RedshiftDaemon Redshift Active Disable Redshift until tomorrow Display Settings ================================================ FILE: plugins/InputPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) cntp_find_pkgconfig(X11 x11) cntp_find_pkgconfig(X11_XI xi) cntp_find_pkgconfig(X11_XORG_LIBINPUT xorg-libinput) set(SOURCES backends/settingsbackend.cpp chunks/keyboardlayoutchunk.cpp daemons/keyboarddaemon.cpp models/selectedkeyboardlayoutsmodel.cpp plugin.cpp settings/inputsettingsleftpane.cpp settings/inputsettingspane.cpp settings/keyboardsettings.cpp settings/mousesettings.cpp chunks/keyboardlayoutchunk.ui settings/inputsettingsleftpane.ui settings/inputsettingspane.ui settings/keyboardsettings.ui settings/mousesettings.ui ) set(HEADERS backends/settingsbackend.h chunks/keyboardlayoutchunk.h daemons/keyboarddaemon.h models/selectedkeyboardlayoutsmodel.h plugin.h settings/inputsettingsleftpane.h settings/inputsettingspane.h settings/keyboardsettings.h settings/mousesettings.h ) set(PLUGIN_NAME input) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-input.conf) IF(${X11_FOUND}) target_link_libraries(plugin-${PLUGIN_NAME} PkgConfig::X11) target_compile_definitions(plugin-${PLUGIN_NAME} PRIVATE HAVE_X11) IF(${X11_XI_FOUND} AND ${X11_XORG_LIBINPUT_FOUND}) target_link_libraries(plugin-${PLUGIN_NAME} PkgConfig::X11_XI PkgConfig::X11_XORG_LIBINPUT) target_compile_definitions(plugin-${PLUGIN_NAME} PRIVATE HAVE_XI) target_sources(plugin-${PLUGIN_NAME} PRIVATE backends/xinputbackend.cpp backends/xinputbackend.h ) ENDIF() ENDIF() target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets libcontemporary libthedesk) ================================================ FILE: plugins/InputPlugin/InputPlugin.pro ================================================ QT += gui widgets TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) CONFIG += link_pkgconfig packagesExist(x11) { message("Building with X11 support"); PKGCONFIG += x11 DEFINES += HAVE_X11 QT += x11extras packagesExist(xi) : packagesExist(xorg-libinput) { PKGCONFIG += xi xorg-libinput DEFINES += HAVE_XI message("Building with XInput support"); SOURCES += \ backends/xinputbackend.cpp HEADERS += \ backends/xinputbackend.h \ } } # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ backends/settingsbackend.cpp \ chunks/keyboardlayoutchunk.cpp \ daemons/keyboarddaemon.cpp \ models/selectedkeyboardlayoutsmodel.cpp \ plugin.cpp \ settings/inputsettingsleftpane.cpp \ settings/inputsettingspane.cpp \ settings/keyboardsettings.cpp \ settings/mousesettings.cpp HEADERS += \ backends/settingsbackend.h \ chunks/keyboardlayoutchunk.h \ daemons/keyboarddaemon.h \ models/selectedkeyboardlayoutsmodel.h \ plugin.h \ settings/inputsettingsleftpane.h \ settings/inputsettingspane.h \ settings/keyboardsettings.h \ settings/mousesettings.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/InputPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/InputPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ chunks/keyboardlayoutchunk.ui \ settings/inputsettingsleftpane.ui \ settings/inputsettingspane.ui \ settings/keyboardsettings.ui \ settings/mousesettings.ui ================================================ FILE: plugins/InputPlugin/Plugin.json ================================================ { "name": "Input Devices", "icon": "preferences-desktop-input", "uuid": "b20834e9-e270-489e-801b-9bd6413c427b", "vi": { "name": "Thiết bị đầu vào" } } ================================================ FILE: plugins/InputPlugin/backends/settingsbackend.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "settingsbackend.h" #ifdef HAVE_X11 #include #include #endif #ifdef HAVE_XI #include "xinputbackend.h" #include #endif SettingsBackend::SettingsBackend(QObject* parent) : QObject(parent) { } SettingsBackend* SettingsBackend::backendForPlatform() { #ifdef HAVE_X11 if (tX11Info::isPlatformX11()) { #ifdef HAVE_XI if (XInternAtom(tX11Info::display(), LIBINPUT_PROP_ACCEL, True)) { return new XInputBackend(); } #endif } #endif return nullptr; } ================================================ FILE: plugins/InputPlugin/backends/settingsbackend.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SETTINGSBACKEND_H #define SETTINGSBACKEND_H #include class SettingsBackend : public QObject { Q_OBJECT public: enum MousePrimaryButton { LeftMouseButton, RightMouseButton }; explicit SettingsBackend(QObject* parent = nullptr); static SettingsBackend* backendForPlatform(); virtual void setPrimaryMouseButton(MousePrimaryButton button) = 0; virtual void setPrimaryTouchpadButton(MousePrimaryButton button) = 0; virtual void setTapToClick(bool tapToClick) = 0; virtual void setNaturalScrolling(bool naturalScrolling) = 0; signals: }; #endif // SETTINGSBACKEND_H ================================================ FILE: plugins/InputPlugin/backends/xinputbackend.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "xinputbackend.h" #include #include #include #include #include #include #include #undef Bool XInputBackend::XInputBackend(QObject* parent) : SettingsBackend(parent) { } void XInputBackend::writeXiSetting(const char* atom, QVariantList value, WriteFor writeFor) { int devices; XDeviceInfo* info = XListInputDevices(tX11Info::display(), &devices); if (info == nullptr) return; Atom mouseAtom = XInternAtom(tX11Info::display(), XI_MOUSE, True); Atom touchpadAtom = XInternAtom(tX11Info::display(), XI_TOUCHPAD, True); Atom trackballAtom = XInternAtom(tX11Info::display(), XI_TRACKBALL, True); for (int i = 0; i < devices; i++) { XDeviceInfo* d = info + i; if ((d->type == mouseAtom && writeFor & Mice) || (d->type == touchpadAtom && writeFor & Touchpads) || (d->type == trackballAtom && writeFor & Mice)) { Atom valAtom = XInternAtom(tX11Info::display(), atom, True); Atom type; if (value.first().type() == QVariant::Bool || value.first().type() == QVariant::Int || value.first().type() == QVariant::Char) { type = XA_INTEGER; } else if (value.first().type() == QVariant::Double) { type = XInternAtom(tX11Info::display(), "FLOAT", False); } else { return; } Atom typeReturn; int formatReturn; unsigned long itemCount; unsigned long bytesAfter; unsigned char* data = nullptr; Status s = XIGetProperty(tX11Info::display(), d->id, valAtom, 0, 32, False, type, &typeReturn, &formatReturn, &itemCount, &bytesAfter, &data); if (s != Success) continue; if (typeReturn != type || data == nullptr || itemCount != value.count()) { if (data != nullptr) { XFree(data); } continue; } if (value.first().type() == QVariant::Bool && formatReturn != 8) { XFree(data); continue; } else if (value.first().type() == QVariant::Double && formatReturn != 32) { XFree(data); continue; } else if (value.first().type() == QVariant::Char && formatReturn != 8) { XFree(data); continue; } else if (value.first().type() == QVariant::Int && formatReturn != 32) { XFree(data); continue; } if (value.first().type() == QVariant::Bool) { unsigned char v[64]; for (int i = 0; i < value.count(); i++) { v[i] = value.at(i).toBool() ? 1 : 0; } XIChangeProperty(tX11Info::display(), d->id, valAtom, type, 8, XIPropModeReplace, v, value.count()); } else if (value.first().type() == QVariant::Double) { float v[64]; for (int i = 0; i < value.count(); i++) { v[i] = static_cast(value.at(i).toDouble()); } XIChangeProperty(tX11Info::display(), d->id, valAtom, type, 32, XIPropModeReplace, reinterpret_cast(v), value.count()); } else if (value.first().type() == QVariant::Char) { unsigned char v[64]; for (int i = 0; i < value.count(); i++) { v[i] = value.at(i).toChar().toLatin1(); } XIChangeProperty(tX11Info::display(), d->id, valAtom, type, 8, XIPropModeReplace, v, value.count()); } else if (value.first().type() == QVariant::Int) { int v[64]; for (int i = 0; i < value.count(); i++) { v[i] = value.at(i).toInt(); } XIChangeProperty(tX11Info::display(), d->id, valAtom, type, 32, XIPropModeReplace, reinterpret_cast(v), value.count()); } XFree(data); } } XFreeDeviceList(info); } void XInputBackend::setPrimaryMouseButton(MousePrimaryButton button) { writeXiSetting(LIBINPUT_PROP_LEFT_HANDED, {button == RightMouseButton}, Mice); } void XInputBackend::setPrimaryTouchpadButton(MousePrimaryButton button) { writeXiSetting(LIBINPUT_PROP_LEFT_HANDED, {button == RightMouseButton}, Touchpads); } void XInputBackend::setTapToClick(bool tapToClick) { writeXiSetting(LIBINPUT_PROP_TAP, {tapToClick}, Touchpads); } void XInputBackend::setNaturalScrolling(bool naturalScrolling) { writeXiSetting(LIBINPUT_PROP_NATURAL_SCROLL, {naturalScrolling}, Touchpads); } ================================================ FILE: plugins/InputPlugin/backends/xinputbackend.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef XINPUTBACKEND_H #define XINPUTBACKEND_H #include "settingsbackend.h" class XInputBackend : public SettingsBackend { Q_OBJECT public: explicit XInputBackend(QObject* parent = nullptr); signals: private: enum WriteFor { Mice = 1, Touchpads = 2, AllDevices = Mice | Touchpads }; void writeXiSetting(const char* atom, QVariantList value, WriteFor writeFor = AllDevices); // SettingsBackend interface public: void setPrimaryMouseButton(MousePrimaryButton button); void setPrimaryTouchpadButton(MousePrimaryButton button); void setTapToClick(bool tapToClick); void setNaturalScrolling(bool naturalScrolling); }; #endif // XINPUTBACKEND_H ================================================ FILE: plugins/InputPlugin/chunks/keyboardlayoutchunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "keyboardlayoutchunk.h" #include "ui_keyboardlayoutchunk.h" #include #include #include #include #include struct KeyboardLayoutChunkPrivate { tSettings settings; QMenu* layoutSelectMenu; QList layoutsActions; BarManager::BarLockPtr barLocker; }; KeyboardLayoutChunk::KeyboardLayoutChunk() : Chunk(), ui(new Ui::KeyboardLayoutChunk) { ui->setupUi(this); d = new KeyboardLayoutChunkPrivate(); d->layoutSelectMenu = new QMenu(); ui->layoutSelectButton->setIconSize(SC_DPI_T(QSize(16, 16), QSize)); connect(&d->settings, &tSettings::settingChanged, this, [ = ](QString key) { if (key == "Input/keyboard.layouts") updateLayouts(); }); updateLayouts(); connect(DesktopWm::instance(), &DesktopWm::currentKeyboardLayoutChanged, this, &KeyboardLayoutChunk::updateCurrentLayout); updateCurrentLayout(); connect(d->layoutSelectMenu, &QMenu::aboutToShow, this, [ = ] { d->barLocker = StateManager::barManager()->acquireLock(); }); connect(d->layoutSelectMenu, &QMenu::aboutToHide, this, [ = ] { d->barLocker->unlock(); }); ui->layoutSelectButton->setMenu(d->layoutSelectMenu); } KeyboardLayoutChunk::~KeyboardLayoutChunk() { delete ui; delete d; } void KeyboardLayoutChunk::updateLayouts() { for (QAction* action : d->layoutsActions) { d->layoutSelectMenu->removeAction(action); action->deleteLater(); } d->layoutsActions.clear(); d->layoutsActions.append(d->layoutSelectMenu->addSection(tr("Select Keyboard Layout"))); for (QString layout : d->settings.delimitedList("Input/keyboard.layouts")) { QAction* action = new QAction(this); action->setText(DesktopWm::keyboardLayoutDescription(layout)); action->setCheckable(true); connect(DesktopWm::instance(), &DesktopWm::currentKeyboardLayoutChanged, action, [ = ] { action->setChecked(layout == DesktopWm::currentKeyboardLayout()); }); action->setChecked(layout == DesktopWm::currentKeyboardLayout()); connect(action, &QAction::triggered, this, [ = ] { DesktopWm::setCurrentKeyboardLayout(layout); }); d->layoutSelectMenu->addAction(action); d->layoutsActions.append(action); } } void KeyboardLayoutChunk::updateCurrentLayout() { ui->layoutSelectButton->setText(DesktopWm::currentKeyboardLayout()); } QString KeyboardLayoutChunk::name() { return "keyboardlayout"; } int KeyboardLayoutChunk::expandedHeight() { return this->sizeHint().height(); } int KeyboardLayoutChunk::statusBarHeight() { return SC_DPI(16); } ================================================ FILE: plugins/InputPlugin/chunks/keyboardlayoutchunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYBOARDLAYOUTCHUNK_H #define KEYBOARDLAYOUTCHUNK_H #include #include namespace Ui { class KeyboardLayoutChunk; } struct KeyboardLayoutChunkPrivate; class KeyboardLayoutChunk : public Chunk { Q_OBJECT public: explicit KeyboardLayoutChunk(); ~KeyboardLayoutChunk(); private: Ui::KeyboardLayoutChunk* ui; KeyboardLayoutChunkPrivate* d; void updateLayouts(); void updateCurrentLayout(); // Chunk interface public: QString name(); int expandedHeight(); int statusBarHeight(); }; #endif // KEYBOARDLAYOUTCHUNK_H ================================================ FILE: plugins/InputPlugin/chunks/keyboardlayoutchunk.ui ================================================ KeyboardLayoutChunk 0 0 400 300 Form 0 0 0 0 0 0 0 .. QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon ================================================ FILE: plugins/InputPlugin/daemons/keyboarddaemon.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "keyboarddaemon.h" #include #include #include #include #include #include #include #include "chunks/keyboardlayoutchunk.h" struct KeyboardDaemonPrivate { tSettings settings; KeyboardLayoutChunk* chunk; }; KeyboardDaemon::KeyboardDaemon(QObject* parent) : QObject{parent} { d = new KeyboardDaemonPrivate(); d->chunk = new KeyboardLayoutChunk(); KeyGrab* nextLayoutGrab = new KeyGrab(QKeySequence(Qt::MetaModifier | Qt::Key_Space), "nextlayout", this); connect(nextLayoutGrab, &KeyGrab::activated, this, &KeyboardDaemon::setNextKeyboardLayout); KeyGrab* nextLayoutGrabAlternate = new KeyGrab(QKeySequence(Qt::MetaModifier | Qt::Key_Return), this); connect(nextLayoutGrabAlternate, &KeyGrab::activated, this, &KeyboardDaemon::setNextKeyboardLayout); connect(&d->settings, &tSettings::settingChanged, this, [ = ](QString key) { if (key == "Input/keyboard.layouts") { updateChunkVisibility(); //Ensure that we have a valid keyboard layout QStringList layouts = d->settings.delimitedList("Input/keyboard.layouts"); //Failsafe if (layouts.isEmpty()) return; if (!layouts.contains(DesktopWm::currentKeyboardLayout())) { //Set the first desktop layout DesktopWm::setCurrentKeyboardLayout(layouts.at(0)); } } }); updateChunkVisibility(); } KeyboardDaemon::~KeyboardDaemon() { d->chunk->deleteLater(); delete d; } void KeyboardDaemon::setNextKeyboardLayout() { QStringList layouts = d->settings.delimitedList("Input/keyboard.layouts"); if (layouts.length() <= 1) return; int nextLayout = layouts.indexOf(DesktopWm::currentKeyboardLayout()) + 1; if (nextLayout >= layouts.length()) nextLayout = 0; QString layout = layouts.at(nextLayout); DesktopWm::setCurrentKeyboardLayout(layout); StateManager::instance()->hudManager()->showHud({ {"icon", "input-keyboard"}, {"title", tr("Keyboard Layout")}, {"text", DesktopWm::keyboardLayoutDescription(layout)} }); } void KeyboardDaemon::updateChunkVisibility() { bool shouldBeVisible = d->settings.delimitedList("Input/keyboard.layouts").length() > 1; if (shouldBeVisible && !d->chunk->chunkRegistered()) { StateManager::barManager()->addChunk(d->chunk); } else if (!shouldBeVisible && d->chunk->chunkRegistered()) { StateManager::barManager()->removeChunk(d->chunk); } } ================================================ FILE: plugins/InputPlugin/daemons/keyboarddaemon.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYBOARDDAEMON_H #define KEYBOARDDAEMON_H #include struct KeyboardDaemonPrivate; class KeyboardDaemon : public QObject { Q_OBJECT public: explicit KeyboardDaemon(QObject* parent = nullptr); ~KeyboardDaemon(); signals: private: KeyboardDaemonPrivate* d; void setNextKeyboardLayout(); void updateChunkVisibility(); }; #endif // KEYBOARDDAEMON_H ================================================ FILE: plugins/InputPlugin/models/selectedkeyboardlayoutsmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "selectedkeyboardlayoutsmodel.h" #include #include struct SelectedKeyboardLayoutsModelPrivate { tSettings settings; }; SelectedKeyboardLayoutsModel::SelectedKeyboardLayoutsModel(QObject* parent) : QAbstractListModel(parent) { d = new SelectedKeyboardLayoutsModelPrivate(); connect(&d->settings, &tSettings::settingChanged, this, [ = ](QString key) { if (key == "Input/keyboard.layouts") emit dataChanged(index(0), index(rowCount())); }); } SelectedKeyboardLayoutsModel::~SelectedKeyboardLayoutsModel() { delete d; } int SelectedKeyboardLayoutsModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return d->settings.delimitedList("Input/keyboard.layouts").length(); } QVariant SelectedKeyboardLayoutsModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= rowCount()) return QVariant(); QString layout = d->settings.delimitedList("Input/keyboard.layouts").at(index.row()); switch (role) { case Qt::DisplayRole: return DesktopWm::keyboardLayoutDescription(layout); case Qt::UserRole: return layout; } return QVariant(); } void SelectedKeyboardLayoutsModel::addLayout(QString layout) { QStringList layouts = d->settings.delimitedList("Input/keyboard.layouts"); if (layouts.contains(layout)) return; layouts.append(layout); layouts.removeAll(""); d->settings.setDelimitedList("Input/keyboard.layouts", layouts); } void SelectedKeyboardLayoutsModel::moveUp(QString layout) { QStringList layouts = d->settings.delimitedList("Input/keyboard.layouts"); if (!layouts.contains(layout)) return; int index = layouts.indexOf(layout); if (index != 0) { layouts.removeAt(index); layouts.insert(index - 1, layout); d->settings.setDelimitedList("Input/keyboard.layouts", layouts); } } void SelectedKeyboardLayoutsModel::moveDown(QString layout) { QStringList layouts = d->settings.delimitedList("Input/keyboard.layouts"); if (!layouts.contains(layout)) return; int index = layouts.indexOf(layout); if (index != 0) { layouts.removeAt(index); layouts.insert(index + 1, layout); d->settings.setDelimitedList("Input/keyboard.layouts", layouts); } } void SelectedKeyboardLayoutsModel::removeLayout(QString layout) { QStringList layouts = d->settings.delimitedList("Input/keyboard.layouts"); layouts.removeAll(layout); d->settings.setDelimitedList("Input/keyboard.layouts", layouts); } ================================================ FILE: plugins/InputPlugin/models/selectedkeyboardlayoutsmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SELECTEDKEYBOARDLAYOUTSMODEL_H #define SELECTEDKEYBOARDLAYOUTSMODEL_H #include struct SelectedKeyboardLayoutsModelPrivate; class SelectedKeyboardLayoutsModel : public QAbstractListModel { Q_OBJECT public: explicit SelectedKeyboardLayoutsModel(QObject* parent = nullptr); ~SelectedKeyboardLayoutsModel(); // Basic functionality: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; void addLayout(QString layout); void moveUp(QString layout); void moveDown(QString layout); void removeLayout(QString layout); private: SelectedKeyboardLayoutsModelPrivate* d; }; #endif // SELECTEDKEYBOARDLAYOUTSMODEL_H ================================================ FILE: plugins/InputPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "daemons/keyboarddaemon.h" #include "settings/inputsettingspane.h" #include #include #include #include #include #include #include #include struct PluginPrivate { InputSettingsPane* settings; KeyboardDaemon* keyboardDaemon; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/InputPlugin/thedesk-input.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-input.conf"); d->settings = new InputSettingsPane(); StateManager::statusCenterManager()->addPane(d->settings, StatusCenterManager::SystemSettings); d->keyboardDaemon = new KeyboardDaemon(); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->settings); d->settings->deleteLater(); delete d->keyboardDaemon; tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/InputPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/InputPlugin/settings/inputsettingsleftpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "inputsettingsleftpane.h" #include "ui_inputsettingsleftpane.h" #include #include InputSettingsLeftPane::InputSettingsLeftPane(QWidget* parent) : QWidget(parent), ui(new Ui::InputSettingsLeftPane) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); ui->listWidget->setIconSize(SC_DPI_T(QSize(32, 32), QSize)); } InputSettingsLeftPane::~InputSettingsLeftPane() { delete ui; } void InputSettingsLeftPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->returnToRootMenu(); } void InputSettingsLeftPane::on_listWidget_currentRowChanged(int currentRow) { emit currentPaneChanged(currentRow); } void InputSettingsLeftPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } ================================================ FILE: plugins/InputPlugin/settings/inputsettingsleftpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef INPUTSETTINGSLEFTPANE_H #define INPUTSETTINGSLEFTPANE_H #include namespace Ui { class InputSettingsLeftPane; } class InputSettingsLeftPane : public QWidget { Q_OBJECT public: explicit InputSettingsLeftPane(QWidget* parent = nullptr); ~InputSettingsLeftPane(); private slots: void on_titleLabel_backButtonClicked(); void on_listWidget_currentRowChanged(int currentRow); signals: void currentPaneChanged(int pane); private: Ui::InputSettingsLeftPane* ui; // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // INPUTSETTINGSLEFTPANE_H ================================================ FILE: plugins/InputPlugin/settings/inputsettingsleftpane.ui ================================================ InputSettingsLeftPane 0 0 400 300 Form 0 0 0 0 0 Input QFrame::NoFrame Mouse and Touchpad .. Keyboard tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/InputPlugin/settings/inputsettingspane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "inputsettingspane.h" #include "ui_inputsettingspane.h" #include #include "inputsettingsleftpane.h" struct InputSettingsPanePrivate { InputSettingsLeftPane* leftPane; }; InputSettingsPane::InputSettingsPane() : StatusCenterPane(), ui(new Ui::InputSettingsPane) { ui->setupUi(this); d = new InputSettingsPanePrivate(); d->leftPane = new InputSettingsLeftPane(); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Lift); connect(d->leftPane, &InputSettingsLeftPane::currentPaneChanged, this, [ = ](int row) { ui->stackedWidget->setCurrentIndex(row); }); } InputSettingsPane::~InputSettingsPane() { d->leftPane->deleteLater(); delete d; delete ui; } QString InputSettingsPane::name() { return "InputSettings"; } QString InputSettingsPane::displayName() { return tr("Input"); } QIcon InputSettingsPane::icon() { return QIcon::fromTheme("preferences-desktop-input"); } QWidget* InputSettingsPane::leftPane() { return d->leftPane; } void InputSettingsPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/InputPlugin/settings/inputsettingspane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef INPUTSETTINGSPANE_H #define INPUTSETTINGSPANE_H #include namespace Ui { class InputSettingsPane; } struct InputSettingsPanePrivate; class InputSettingsPane : public StatusCenterPane { Q_OBJECT public: explicit InputSettingsPane(); ~InputSettingsPane(); private: Ui::InputSettingsPane* ui; InputSettingsPanePrivate* d; // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // INPUTSETTINGSPANE_H ================================================ FILE: plugins/InputPlugin/settings/inputsettingspane.ui ================================================ InputSettingsPane 0 0 400 300 Form 0 0 0 0 0 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
MouseSettings QWidget
settings/mousesettings.h
1
KeyboardSettings QWidget
settings/keyboardsettings.h
1
================================================ FILE: plugins/InputPlugin/settings/keyboardsettings.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "keyboardsettings.h" #include "ui_keyboardsettings.h" #include #include #include #include #include #include "models/selectedkeyboardlayoutsmodel.h" struct KeyboardSettingsPrivate { SelectedKeyboardLayoutsModel* layoutsModel; }; KeyboardSettings::KeyboardSettings(QWidget* parent) : QWidget(parent), ui(new Ui::KeyboardSettings) { ui->setupUi(this); d = new KeyboardSettingsPrivate(); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->layoutsWidget->setFixedWidth(contentWidth); d->layoutsModel = new SelectedKeyboardLayoutsModel(); ui->layoutsList->setModel(d->layoutsModel); } KeyboardSettings::~KeyboardSettings() { delete d; delete ui; } void KeyboardSettings::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void KeyboardSettings::on_addLayoutButton_clicked() { bool ok; QString newLayout = StateManager::localeManager()->showKeyboardLayoutSelector(this->window(), &ok); if (!ok) return; d->layoutsModel->addLayout(newLayout); } void KeyboardSettings::on_layoutsList_customContextMenuRequested(const QPoint& pos) { if (d->layoutsModel->rowCount() == 1) return; QModelIndex index = ui->layoutsList->indexAt(pos); if (index.isValid()) { QMenu* menu = new QMenu(); menu->addSection(tr("For this layout")); if (index.row() != 0) menu->addAction(QIcon::fromTheme("go-up"), tr("Move Up"), [ = ] { d->layoutsModel->moveUp(index.data(Qt::UserRole).toString()); }); if (index.row() != d->layoutsModel->rowCount() - 1) menu->addAction(QIcon::fromTheme("go-down"), tr("Move Down"), [ = ] { d->layoutsModel->moveDown(index.data(Qt::UserRole).toString()); }); menu->addAction(QIcon::fromTheme("list-remove"), tr("Remove"), [ = ] { d->layoutsModel->removeLayout(index.data(Qt::UserRole).toString()); }); connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); menu->popup(ui->layoutsList->mapToGlobal(pos)); } } void KeyboardSettings::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } ================================================ FILE: plugins/InputPlugin/settings/keyboardsettings.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYBOARDSETTINGS_H #define KEYBOARDSETTINGS_H #include namespace Ui { class KeyboardSettings; } struct KeyboardSettingsPrivate; class KeyboardSettings : public QWidget { Q_OBJECT public: explicit KeyboardSettings(QWidget* parent = nullptr); ~KeyboardSettings(); private slots: void on_titleLabel_backButtonClicked(); void on_addLayoutButton_clicked(); void on_layoutsList_customContextMenuRequested(const QPoint& pos); private: Ui::KeyboardSettings* ui; KeyboardSettingsPrivate* d; // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // KEYBOARDSETTINGS_H ================================================ FILE: plugins/InputPlugin/settings/keyboardsettings.ui ================================================ KeyboardSettings 0 0 901 655 Form 0 0 0 0 0 Keyboard QFrame::NoFrame true 0 0 901 641 0 0 0 0 0 0 0 0 9 9 9 9 true LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space true Qt::CustomContextMenu QFrame::NoFrame Add Layout ../../LocalePlugin/settings../../LocalePlugin/settings Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/InputPlugin/settings/mousesettings.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "mousesettings.h" #include "ui_mousesettings.h" #include #include #include #include "../backends/settingsbackend.h" struct MouseSettingsPrivate { SettingsBackend* backend; tSettings settings; }; MouseSettings::MouseSettings(QWidget* parent) : QWidget(parent), ui(new Ui::MouseSettings) { ui->setupUi(this); d = new MouseSettingsPrivate(); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->clickingWidget->setFixedWidth(contentWidth); ui->scrollingWidget->setFixedWidth(contentWidth); d->backend = SettingsBackend::backendForPlatform(); if (!d->backend) { ui->stackedWidget->setCurrentIndex(1); } else { ui->stackedWidget->setCurrentIndex(0); connect(&d->settings, &tSettings::settingChanged, this, [ = ](QString key, QVariant value) { Q_UNUSED(value); updateSettings(key); }); updateAllSettings(); } } MouseSettings::~MouseSettings() { delete d; delete ui; } void MouseSettings::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void MouseSettings::on_leftPrimaryButton_toggled(bool checked) { if (checked) { d->settings.setValue("Input/mouse.primary", "left"); } } void MouseSettings::on_rightPrimaryButton_toggled(bool checked) { if (checked) { d->settings.setValue("Input/mouse.primary", "right"); } } void MouseSettings::updateSettings(QString key) { QVariant value = d->settings.value(key); if (key == "Input/mouse.primary") { if (value == "right") { d->backend->setPrimaryMouseButton(SettingsBackend::RightMouseButton); d->backend->setPrimaryTouchpadButton(SettingsBackend::RightMouseButton); ui->rightPrimaryButton->setChecked(true); } else { d->backend->setPrimaryMouseButton(SettingsBackend::LeftMouseButton); d->backend->setPrimaryTouchpadButton(SettingsBackend::LeftMouseButton); ui->leftPrimaryButton->setChecked(true); } } else if (key == "Input/touchpad.tapClick") { d->backend->setTapToClick(value.toBool()); ui->tapToClickSwitch->setChecked(value.toBool()); } else if (key == "Input/touchpad.naturalScroll") { d->backend->setNaturalScrolling(value.toBool()); ui->naturalScrollingSwitch->setChecked(value.toBool()); } } void MouseSettings::updateAllSettings() { updateSettings("Input/mouse.primary"); updateSettings("Input/touchpad.tapClick"); updateSettings("Input/touchpad.naturalScroll"); } void MouseSettings::on_tapToClickSwitch_toggled(bool checked) { d->settings.setValue("Input/touchpad.tapClick", checked); } void MouseSettings::on_naturalScrollingSwitch_toggled(bool checked) { d->settings.setValue("Input/touchpad.naturalScroll", checked); } void MouseSettings::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } ================================================ FILE: plugins/InputPlugin/settings/mousesettings.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MOUSESETTINGS_H #define MOUSESETTINGS_H #include namespace Ui { class MouseSettings; } struct MouseSettingsPrivate; class MouseSettings : public QWidget { Q_OBJECT public: explicit MouseSettings(QWidget* parent = nullptr); ~MouseSettings(); private slots: void on_titleLabel_backButtonClicked(); void on_leftPrimaryButton_toggled(bool checked); void on_rightPrimaryButton_toggled(bool checked); void on_tapToClickSwitch_toggled(bool checked); void on_naturalScrollingSwitch_toggled(bool checked); private: Ui::MouseSettings* ui; MouseSettingsPrivate* d; void updateSettings(QString key); void updateAllSettings(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // MOUSESETTINGS_H ================================================ FILE: plugins/InputPlugin/settings/mousesettings.ui ================================================ MouseSettings 0 0 400 300 Form 0 0 0 0 0 Mouse and Touchpad 0 0 0 0 0 0 QFrame::NoFrame true 0 0 386 366 0 0 0 0 0 true CLICKING 0 Left true true Right true true 0 0 Primary Button Tap to Click TapToClick 16777215 1 Qt::Horizontal NaturalScrolling 0 0 Natural Scrolling true SCROLLING false Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. true Qt::Vertical 20 181 Qt::Vertical 20 96 20 Settings Unavailable Qt::AlignCenter Mouse settings can't be changed on this platform. Qt::AlignCenter Qt::Vertical 20 95 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tSwitch QPushButton
tswitch.h
================================================ FILE: plugins/InputPlugin/thedesk-input.conf ================================================ [Input] mouse.primary=left touchpad.tapClick=true touchpad.naturalScroll=true keyboard.layouts=us(basic) ================================================ FILE: plugins/InputPlugin/translations/ar_SA.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/au_AU.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/cy.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/da.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/de.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/en_US.qm ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/es.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/es_VE.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/id.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/nl.ts ================================================ InputSettingsLeftPane Input Input Mouse and Touchpad Muis en Touchpad Keyboard Toetsenbord InputSettingsPane Input Input KeyboardDaemon Keyboard Layout Toetsenbordindeling KeyboardLayoutChunk Select Keyboard Layout Toetsenbordindeling Selecteren KeyboardSettings Keyboard Toetsenbord LAYOUTS INDELINGEN Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Geef de toetsenbordindelingen die je op je apparaat wil gebruiken prioriteit. Je kunt tussen indelingen wisselen met SUPER+Spatie Add Layout Indeling Toevoegen For this layout Voor deze indeling Move Up Omhoog Move Down Omlaag Remove Weghalen MouseSettings Mouse and Touchpad Muis en Touchpad CLICKING KLIKKEN Left Links Right Rechts Primary Button Primaire Knop Tap to Click Aanraken om te Klikken Natural Scrolling Natuurlijk Scrollen SCROLLING SCROLLEN Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Draai de richting waarin je scrolt om, zodat de inhoud dezelfde kant op beweegt als je vingers. Settings Unavailable Instellingen Niet Beschikbaar Mouse settings can't be changed on this platform. Muisinstellingen kunnen niet worden aangepast om dit platform. ================================================ FILE: plugins/InputPlugin/translations/pt_BR.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/ro.ts ================================================ InputSettingsLeftPane Input Intrare Mouse and Touchpad Mouse și tastatură Keyboard InputSettingsPane Input Intrare KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad Mouse și tastatură CLICKING APĂSARE Left Stânga Right Dreapta Primary Button Butonul principal Tap to Click Atingeți pentru click Natural Scrolling Derulare naturală SCROLLING DERULARE Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Inversează direcția în care derulați astfel încât conținutul se mișcă în aceași direcție ca degetele. Settings Unavailable Setări indisponibile Mouse settings can't be changed on this platform. Setările mouse-ului nu pot fi schimbate pe această platformă. ================================================ FILE: plugins/InputPlugin/translations/sv.ts ================================================ InputSettingsLeftPane Input Mouse and Touchpad Keyboard InputSettingsPane Input KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad CLICKING Left Right Primary Button Tap to Click Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Mouse settings can't be changed on this platform. ================================================ FILE: plugins/InputPlugin/translations/tr.ts ================================================ InputSettingsLeftPane Input Giriş Mouse and Touchpad Mouse ve Dokunmatik Yüzey Keyboard InputSettingsPane Input Giriş KeyboardDaemon Keyboard Layout KeyboardLayoutChunk Select Keyboard Layout KeyboardSettings Keyboard LAYOUTS Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Add Layout For this layout Move Up Move Down Remove MouseSettings Mouse and Touchpad Mouse ve Dokunmatik Yüzey CLICKING TIKLAMA Left Sol Right Sağ Primary Button Birincil Düğme Tap to Click Tıklamak için Dokunun Natural Scrolling SCROLLING Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Settings Unavailable Ayarlar Kullanılamıyor Mouse settings can't be changed on this platform. Bu platformda mouse ayarları değiştirilemez. ================================================ FILE: plugins/InputPlugin/translations/vi.ts ================================================ InputSettingsLeftPane Input Thiết bị đầu vào Mouse and Touchpad Chuột và bàn di chuột Keyboard Bàn phím InputSettingsPane Input Thiết bị đầu vào KeyboardDaemon Keyboard Layout Bố cục bàn phím KeyboardLayoutChunk Select Keyboard Layout Chọn bố cục bàn phím KeyboardSettings Keyboard Bàn phím LAYOUTS BỐ CỤC Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Xếp hạng các bố cục bàn phím bạn muốn sử dụng. Bạn có thể chuyển đổi giữa các bố cục bàn phím với SUPER+Space Add Layout Thêm bố cục For this layout Cho bố cục này Move Up Chuyển lên Move Down Chuyển xuống Remove Xóa MouseSettings Mouse and Touchpad Chuột và bàn di chuột CLICKING NHẤP CHUỘT Left Trái Right Phải Primary Button Nút chính Tap to Click Chạm để nhấp chuột Natural Scrolling Cuộn tự nhiên SCROLLING CUỘN Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Đảo ngược hướng cuộn để cho nội dung di chuyển cùng hướng với ngón tay của bạn. Settings Unavailable Cài đặt không có sẵn Mouse settings can't be changed on this platform. Cài đặt chuột không thể bị đổi ngay bây giờ. ================================================ FILE: plugins/InputPlugin/translations/vi_VN.ts ================================================ InputSettingsLeftPane Input Đầu vào Mouse and Touchpad Chuột bà bàn di chuột Keyboard Bàn phím InputSettingsPane Input Đầu vào KeyboardDaemon Keyboard Layout Bố cục bàn phím KeyboardLayoutChunk Select Keyboard Layout Chọn bố cục bàn phím KeyboardSettings Keyboard Bàn phím LAYOUTS BỐ CỤC Prioritise the keyboard layouts you'd like to use on your device. You can switch between keyboard layouts with SUPER+Space Ưu tiên các bố cục bàn phím bạn muốn sử dụng trên thiết bị này. Bạn có thể đổi sang các bố cục với SUPER+Dấu cách Add Layout Thêm bố cục For this layout Cho bố cục này Move Up Chuyển lên Move Down Chuyển xuống Remove Xóa MouseSettings Mouse and Touchpad Chuột và bàn di chuột CLICKING NHẤP Left Bên phải Right Bên trái Primary Button Nút chính Tap to Click Chạm để nhấn Natural Scrolling Cuộn tự nhiên SCROLLING CUỘN Reverse the direction that you scroll in so that the content moves in the same direction as your fingers. Đảo ngược hướng cuộn để cho nội dung di chuyển theo hướng ngón tay của bạn. Settings Unavailable Cài đặt không có sẵn Mouse settings can't be changed on this platform. Cài đặt chuột không có thể bị đặt trên nền tảng này. ================================================ FILE: plugins/LocalePlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) set(SOURCES localeplugincommon.cpp onboarding/onboardingregion.cpp plugin.cpp settings/localesettingspane.cpp onboarding/onboardingregion.ui settings/localesettingspane.ui ) set(HEADERS localeplugincommon.h onboarding/onboardingregion.h plugin.h settings/localesettingspane.h ) set(PLUGIN_NAME locale) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-locale.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets libcontemporary libthedesk) ================================================ FILE: plugins/LocalePlugin/LocalePlugin.pro ================================================ QT += gui widgets TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ common.cpp \ onboarding/onboardingregion.cpp \ plugin.cpp \ settings/localesettingspane.cpp HEADERS += \ common.h \ onboarding/onboardingregion.h \ plugin.h \ settings/localesettingspane.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/LocalePlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/LocalePlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ onboarding/onboardingregion.ui \ settings/localesettingspane.ui ================================================ FILE: plugins/LocalePlugin/Plugin.json ================================================ { "name": "Locale Management", "icon": "preferences-system-locale", "uuid": "9d637cab-fdbe-404e-8361-4a4a77936847", "vi": { "name": "Quản lý ngôn ngữ" } } ================================================ FILE: plugins/LocalePlugin/localeplugincommon.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "localeplugincommon.h" #include #include using namespace LocalePluginCommon; QList LocalePluginCommon::countries() { QLocale::Country current = StateManager::localeManager()->formatCountry(); QList countries; for (int i = QLocale::Afghanistan + 1; i < QLocale::LastCountry; i++) { if (i == QLocale::World) continue; countries.append({static_cast(i), QLocale::countryToString(static_cast(i)), current == i}); } std::sort(countries.begin(), countries.end(), [=](const Country& first, const Country& second) { return first.text.localeAwareCompare(second.text) < 0; }); return countries; } ================================================ FILE: plugins/LocalePlugin/localeplugincommon.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef LOCALEPLUGINCOMMON_H #define LOCALEPLUGINCOMMON_H #include namespace LocalePluginCommon { struct Country { QLocale::Country country; QString text; bool isCurrent; }; QList countries(); } #endif // LOCALEPLUGINCOMMON_H ================================================ FILE: plugins/LocalePlugin/onboarding/onboardingregion.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingregion.h" #include "ui_onboardingregion.h" #include #include #include #include #include "localeplugincommon.h" OnboardingRegion::OnboardingRegion(QWidget* parent) : OnboardingPage(parent), ui(new Ui::OnboardingRegion) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); search(""); } OnboardingRegion::~OnboardingRegion() { delete ui; } void OnboardingRegion::on_nextButton_clicked() { StateManager::onboardingManager()->nextStep(); } QString OnboardingRegion::name() { return "OnboardingRegion"; } QString OnboardingRegion::displayName() { return tr("Region"); } void OnboardingRegion::on_titleLabel_backButtonClicked() { StateManager::onboardingManager()->previousStep(); } void OnboardingRegion::on_countriesWidget_currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous) { if (current) { StateManager::localeManager()->setFormatCountry(current->data(Qt::UserRole).value()); } } void OnboardingRegion::on_searchEdit_textChanged(const QString& arg1) { search(arg1); } void OnboardingRegion::search(QString query) { ui->countriesWidget->clear(); QList countries = LocalePluginCommon::countries(); for (const LocalePluginCommon::Country& country : qAsConst(countries)) { if (!country.text.contains(query, Qt::CaseInsensitive)) continue; QListWidgetItem* item = new QListWidgetItem(); item->setText(country.text); item->setData(Qt::UserRole, country.country); ui->countriesWidget->addItem(item); if (country.isCurrent) ui->countriesWidget->setCurrentItem(item); } } ================================================ FILE: plugins/LocalePlugin/onboarding/onboardingregion.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGREGION_H #define ONBOARDINGREGION_H #include #include namespace Ui { class OnboardingRegion; } class OnboardingRegion : public OnboardingPage { Q_OBJECT public: explicit OnboardingRegion(QWidget* parent = nullptr); ~OnboardingRegion(); private slots: void on_nextButton_clicked(); void on_titleLabel_backButtonClicked(); void on_countriesWidget_currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous); void on_searchEdit_textChanged(const QString& arg1); private: Ui::OnboardingRegion* ui; void search(QString query); // OnboardingPage interface public: QString name(); QString displayName(); }; #endif // ONBOARDINGREGION_H ================================================ FILE: plugins/LocalePlugin/onboarding/onboardingregion.ui ================================================ OnboardingRegion 0 0 400 300 Form 0 0 0 0 0 Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. true 9 16777215 1 Qt::Horizontal false Search... 16777215 1 Qt::Horizontal QFrame::NoFrame 16777215 1 Qt::Horizontal 9 9 9 9 Qt::Horizontal 40 20 Next .. tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/LocalePlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "tsettings.h" #include #include #include #include #include #include #include #include #include "onboarding/onboardingregion.h" #include "settings/localesettingspane.h" struct PluginPrivate { LocaleSettingsPane* localeSettingsPane; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/LocalePlugin/thedesk-locale.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-locale.conf"); d->localeSettingsPane = new LocaleSettingsPane(); StateManager::statusCenterManager()->addPane(d->localeSettingsPane, StatusCenterManager::SystemSettings); connect(StateManager::onboardingManager(), &OnboardingManager::onboardingRequired, this, [=] { StateManager::onboardingManager()->addOnboardingStep(new OnboardingRegion); }); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->localeSettingsPane); d->localeSettingsPane->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/LocalePlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/LocalePlugin/settings/localesettingspane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "localesettingspane.h" #include "ui_localesettingspane.h" #include #include #include #include #include #include #include "localeplugincommon.h" LocaleSettingsPane::LocaleSettingsPane() : StatusCenterPane(), ui(new Ui::LocaleSettingsPane) { ui->setupUi(this); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->languageWidget->setFixedWidth(contentWidth); ui->regionWidget->setFixedWidth(contentWidth); QList countries = LocalePluginCommon::countries(); for (LocalePluginCommon::Country country : countries) { ui->countryBox->addItem(country.text, country.country); if (country.isCurrent) ui->countryBox->setCurrentIndex(ui->countryBox->count() - 1); } connect(StateManager::localeManager(), &LocaleManager::localesChanged, this, [=] { this->updateLanguages(); StateManager::statusCenterManager()->requestLogout(); }); connect(StateManager::localeManager(), &LocaleManager::formatCountryChanged, this, [=] { this->updateRegionalFormats(); StateManager::statusCenterManager()->requestLogout(); }); this->updateLanguages(); this->updateRegionalFormats(); DesktopTimeDate::makeTimeLabel(ui->timeLabel, DesktopTimeDate::FullTime); DesktopTimeDate::makeTimeLabel(ui->dateLabel, DesktopTimeDate::StandardDate); } LocaleSettingsPane::~LocaleSettingsPane() { delete ui; } void LocaleSettingsPane::updateLanguages() { ui->languagesList->clear(); for (QLocale locale : StateManager::localeManager()->locales()) { QListWidgetItem* item = new QListWidgetItem(); QString text = QStringLiteral("%1 (%2)").arg(QLocale::languageToString(locale.language())).arg(locale.nativeLanguageName()); if (locale == StateManager::localeManager()->locales().first()) text.append(" · " + tr("Primary")); item->setText(text); item->setData(Qt::UserRole, locale); ui->languagesList->addItem(item); } } void LocaleSettingsPane::updateRegionalFormats() { QLocale locale; QLocale formatLocale = StateManager::localeManager()->formatLocale(); ui->dayOfWeekLabel->setText(locale.dayName(formatLocale.firstDayOfWeek())); ui->numbersLabel->setText(formatLocale.toString(123456789.00, 'f', 2)); ui->currencyLabel->setText(formatLocale.toCurrencyString(1234.56)); switch (formatLocale.measurementSystem()) { case QLocale::MetricSystem: ui->measurementLabel->setText(tr("Metric")); break; case QLocale::ImperialUSSystem: ui->measurementLabel->setText(tr("Imperial")); break; case QLocale::ImperialUKSystem: ui->measurementLabel->setText(tr("Imperial (United Kingdom)")); break; } } void LocaleSettingsPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } QString LocaleSettingsPane::name() { return "LocaleSettings"; } QString LocaleSettingsPane::displayName() { return tr("Locale"); } QIcon LocaleSettingsPane::icon() { return QIcon::fromTheme("preferences-system-locale"); } QWidget* LocaleSettingsPane::leftPane() { return nullptr; } void LocaleSettingsPane::on_countryBox_currentIndexChanged(int index) { QLocale::Country country = ui->countryBox->itemData(index).value(); StateManager::localeManager()->setFormatCountry(country); } void LocaleSettingsPane::on_addLanguageButton_clicked() { LocaleManager* manager = StateManager::localeManager(); bool ok; QLocale locale = manager->showLocaleSelector(this->window(), &ok); if (ok) { if (!manager->locales().contains(locale)) { manager->addLocale(locale); } } } void LocaleSettingsPane::on_languagesList_customContextMenuRequested(const QPoint& pos) { if (ui->languagesList->count() == 1) return; QListWidgetItem* item = ui->languagesList->itemAt(pos); if (item) { QMenu* menu = new QMenu(); menu->addSection(tr("For this language")); if (ui->languagesList->row(item) != 0) menu->addAction(QIcon::fromTheme("go-up"), tr("Move Up"), [=] { StateManager::localeManager()->moveLocaleUp(item->data(Qt::UserRole).toLocale()); }); if (ui->languagesList->row(item) != ui->languagesList->count() - 1) menu->addAction(QIcon::fromTheme("go-down"), tr("Move Down"), [=] { StateManager::localeManager()->moveLocaleDown(item->data(Qt::UserRole).toLocale()); }); menu->addAction(QIcon::fromTheme("list-remove"), tr("Remove"), [=] { StateManager::localeManager()->removeLocale(item->data(Qt::UserRole).toLocale()); }); connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); menu->popup(ui->languagesList->mapToGlobal(pos)); } } void LocaleSettingsPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } ================================================ FILE: plugins/LocalePlugin/settings/localesettingspane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef LOCALESETTINGSPANE_H #define LOCALESETTINGSPANE_H #include namespace Ui { class LocaleSettingsPane; } class LocaleSettingsPane : public StatusCenterPane { Q_OBJECT public: explicit LocaleSettingsPane(); ~LocaleSettingsPane(); private: Ui::LocaleSettingsPane* ui; void updateLanguages(); void updateRegionalFormats(); void changeEvent(QEvent* event); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); private slots: void on_countryBox_currentIndexChanged(int index); void on_addLanguageButton_clicked(); void on_languagesList_customContextMenuRequested(const QPoint& pos); void on_titleLabel_backButtonClicked(); }; #endif // LOCALESETTINGSPANE_H ================================================ FILE: plugins/LocalePlugin/settings/localesettingspane.ui ================================================ LocaleSettingsPane 0 0 578 661 Form 0 0 0 0 0 Locale QFrame::NoFrame true 0 0 578 644 0 0 0 0 0 0 0 0 9 9 9 9 75 true LANGUAGE Prioritise the languages you'd like to use on your device. Qt::CustomContextMenu QFrame::NoFrame Add Language .. 16777215 1 Qt::Horizontal TextLabel Tableday Numbers Select your preferred regional formats 0 0 75 true REGION TextLabel Time First day of week TextLabel Measurement TextLabel Date Country TextLabel Currency Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/LocalePlugin/thedesk-locale.conf ================================================ ================================================ FILE: plugins/LocalePlugin/translations/ar_SA.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/au_AU.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/cy.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/da.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/de.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/en_GB.ts ================================================ LocaleSettingsPane Locale Locale LANGUAGE LANGUAGE Prioritise the languages you'd like to use on your device. Prioritise the languages you would like to use on your device. Add Language Add Language Currency Currency Time Time Measurement Measurement Country Country Select your preferred regional formats Select your preferred regional formats Numbers Numbers First day of week First day of week REGION REGION Date Date Primary Primary Metric Metric Imperial Imperial Imperial (United Kingdom) Imperial (United Kingdom) For this language For this language Move Up Move Up Move Down Move Down Remove Remove OnboardingRegion Region Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next Next ================================================ FILE: plugins/LocalePlugin/translations/en_US.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Prioritize what languages you'd like on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Select your regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Where are you located? This'll format your dates, numbers, and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/es.ts ================================================ LocaleSettingsPane Locale Lugar LANGUAGE IDIOMA Prioritise the languages you'd like to use on your device. Add Language Agregar idioma Currency Time Tiempo Measurement Country País Select your preferred regional formats Numbers Numeros First day of week Primer día de la semana REGION REGIÓN Date Fecha Primary Primario Metric Métrico Imperial Imperial Imperial (United Kingdom) Imperial (Reino Unido) For this language Para este idioma Move Up Move Down Remove Retirar OnboardingRegion Region Región Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next Siguiente ================================================ FILE: plugins/LocalePlugin/translations/es_VE.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/id.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/nl.ts ================================================ LocaleSettingsPane Locale Taal LANGUAGE TAAL Prioritise the languages you'd like to use on your device. Geef de talen die je op te apparaat wil gebruiken prioriteit. Add Language Taal Toevoegen Currency Munteenheid Time Tijd Measurement Lengtes Country Land Select your preferred regional formats Selecteer de regionale formaten van je voorkeur Numbers Getallen First day of week Eerste dag van de week REGION REGIO Date Datum Primary Primair Metric Metriek Imperial Amerikaans Imperial (United Kingdom) Brits For this language Voor deze taal Move Up Omhoog Move Down Omlaag Remove Weghalen OnboardingRegion Region Regio Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Wat is je verblijfplaats? Deze informatie gebruiken we om je data, getallen en andere dingen juist weer te geven. Search... Zoeken... Next Volgende ================================================ FILE: plugins/LocalePlugin/translations/pt_BR.ts ================================================ LocaleSettingsPane Locale Localidade LANGUAGE IDIOMA Prioritise the languages you'd like to use on your device. Escolha as línguas que gostaria de usar no seu dispositivo. Add Language Adicionar idioma Currency Moeda Time Hora Measurement Unidades de medida Country País Select your preferred regional formats Selecione seus formatos regionais preferidos Numbers Números First day of week Primeiro dia da semana REGION REGIÃO Date Data Primary Primário Metric Métrico Imperial Imperial Imperial (United Kingdom) Imperial (Reino Unido) For this language Para essa língua Move Up Mover para cima Move Down Mover para baixo Remove Remover OnboardingRegion Region Região Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Onde você está localizado? Utilizaremos esta informação para formatar datas, números e outros itens corretamente. Search... Pesquisar… Next Próximo ================================================ FILE: plugins/LocalePlugin/translations/ro_RO.ts ================================================ LocaleSettingsPane Locale Limbă și regiune LANGUAGE Limbă Prioritise the languages you'd like to use on your device. Ordonați limbile pe care le folosiți pe dispozitiv. Add Language Adaugă o limbă Currency Moneda Time Ora Measurement Sistemul de măsurători Country Țară Select your preferred regional formats Selectați formatele regionale pe care le folosiți Numbers Numere First day of week Prima zi din săptămână REGION Regiune Date Dată Primary Principal Metric Metric Imperial Imperial Imperial (United Kingdom) Imperial (Regatul Unit) For this language Pentru această limbă Move Up Mută sus Move Down Mută jos Remove Elimină OnboardingRegion Region Regiune Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Unde vă aflați? Vom folosi informația să aranjăm datele calendaristice, numerele și alte lucruri corect. Search... Next Următorul ================================================ FILE: plugins/LocalePlugin/translations/sv.ts ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/LocalePlugin/translations/tr_TR.ts ================================================ LocaleSettingsPane Locale Yerel LANGUAGE DİL Prioritise the languages you'd like to use on your device. Cihazınızda kullanmak istediğiniz dillere öncelik verin. Add Language Dil Ekle Currency Para birimi Time Zaman Measurement Ölçüm Country Ülke Select your preferred regional formats Tercih ettiğiniz bölgesel biçimleri seçin Numbers Sayılar First day of week Haftanın ilk günü REGION BÖLGE Date Tarih Primary Birincil Metric Metrik Imperial İmparatorluk Imperial (United Kingdom) İmparatorluk (Birleşik Krallık) For this language Bu dil için Move Up Yukarı Taşı Move Down Aşağı inmek Remove Kaldırmak OnboardingRegion Region Bölge Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Nerelerde bulunuyorsunuz? Bu bilgileri tarihlerinizi, sayılarınızı ve diğer öğelerinizi doğru şekilde biçimlendirmek için kullanacağız. Search... Next Sonraki ================================================ FILE: plugins/LocalePlugin/translations/vi_VN.ts ================================================ LocaleSettingsPane Locale Ngôn Ngữ và Lãnh Thổ LANGUAGE NGÔN NGỮ Prioritise the languages you'd like to use on your device. Đặt ưu tiên cho ngôn ngữ bạn muốn sử dụng trên thiết bị này. Add Language Thêm ngôn ngữ Currency Tiền tệ Time Thời gian Measurement Hệ đo lường Country Quốc gia Select your preferred regional formats Chọn định dạng lãnh thổ của bạn Numbers Cách ghi số First day of week Ngày đầu tuần REGION LÃNH THỔ Date Ngày và tháng Primary Chính Metric Hệ mét Imperial Hệ Imperial Imperial (United Kingdom) Hệ Imperial (Vương quốc Anh) For this language Cho ngôn ngữ này Move Up Chuyển lên Move Down Chuyển xuống Remove Xóa OnboardingRegion Region Khu vực Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Bạn đang ở đâu? Chúng tôi sẽ sử dụng thông tin này để định dạng các ngày, số và điều khác. Search... Tìm kiếm... Next Tiếp ================================================ FILE: plugins/LocalePlugin/translations/zh_CN.ts ================================================ LocaleSettingsPane Locale 地区 LANGUAGE 语言 Prioritise the languages you'd like to use on your device. 优先选择设备语言。 Add Language 增加语言 Currency 货币 Time 时间 Measurement 测量 Country 国家 Select your preferred regional formats 选择你的区域格式 Numbers 数字 First day of week 周的第一天 REGION 地区 Date 日期 Primary 主选项 Metric 公制 Imperial 英制 Imperial (United Kingdom) 英制 For this language 此语言 Move Up 选上 Move Down 选下 Remove 移除 OnboardingRegion Region 地区 Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. 你在哪里? 我们会用这个信息来定制您的日期, 数字和其它数据。 Search... Next 下一个 ================================================ FILE: plugins/LocalePlugin/translations/zu_ZA.qm ================================================ LocaleSettingsPane Locale LANGUAGE Prioritise the languages you'd like to use on your device. Add Language Currency Time Measurement Country Select your preferred regional formats Numbers First day of week REGION Date Primary Metric Imperial Imperial (United Kingdom) For this language Move Up Move Down Remove OnboardingRegion Region Whereabouts are you located? We'll use this information to format your dates, numbers and other items correctly. Search... Next ================================================ FILE: plugins/NetworkPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets DBus) find_package(libcontemporary) find_package(KF${KF_VERSION_MAJOR}NetworkManagerQt REQUIRED) find_package(KF${KF_VERSION_MAJOR}ModemManagerQt REQUIRED) cntp_find_pkgconfig(qrencode libqrencode REQUIRED) set(SOURCES chunk/chunkupdater.cpp chunk/genericchunkupdater.cpp chunk/networkchunk.cpp chunk/wiredchunkupdater.cpp chunk/wirelesschunkupdater.cpp networkplugincommon.cpp models/deviceconnectionlistmodel.cpp models/wirelessaccesspointsmodel.cpp models/wirelessconnectionlistmodel.cpp models/wirelessnetworklistdelegate.cpp onboarding/onboardingnetwork.cpp onboarding/wiredonboardingsetup.cpp onboarding/wirelessonboardingsetup.cpp plugin.cpp statusCenter/connectionEditor/connectioneditorpane.cpp statusCenter/connectionEditor/ipv4connectioneditorpane.cpp statusCenter/connectionEditor/networkconnectioneditor.cpp statusCenter/connectionEditor/wificonnectioneditorpane.cpp statusCenter/devicePanes/abstractdevicepane.cpp statusCenter/devicePanes/cellularpane.cpp statusCenter/devicePanes/devicepane.cpp statusCenter/devicePanes/wifidevicepane.cpp statusCenter/devicePanes/wireddevicepane.cpp statusCenter/eap/securityeap.cpp statusCenter/eap/securityeappeap.cpp statusCenter/eap/securityeapunsupported.cpp statusCenter/networkstatuscenterleftpane.cpp statusCenter/networkstatuscenterpane.cpp statusCenter/popovers/connectionselectionpopover.cpp statusCenter/popovers/simsettingspopover.cpp statusCenter/popovers/tetheringsettingspopover.cpp statusCenter/popovers/unlockmodempopover.cpp statusCenter/popovers/wirelessnetworkselectionpopover.cpp switchmanager.cpp onboarding/onboardingnetwork.ui onboarding/wiredonboardingsetup.ui onboarding/wirelessonboardingsetup.ui statusCenter/connectionEditor/ipv4connectioneditorpane.ui statusCenter/connectionEditor/networkconnectioneditor.ui statusCenter/connectionEditor/wificonnectioneditorpane.ui statusCenter/devicePanes/cellularpane.ui statusCenter/devicePanes/devicepane.ui statusCenter/devicePanes/wifidevicepane.ui statusCenter/devicePanes/wireddevicepane.ui statusCenter/eap/securityeappeap.ui statusCenter/eap/securityeapunsupported.ui statusCenter/networkstatuscenterleftpane.ui statusCenter/networkstatuscenterpane.ui statusCenter/popovers/connectionselectionpopover.ui statusCenter/popovers/simsettingspopover.ui statusCenter/popovers/tetheringsettingspopover.ui statusCenter/popovers/unlockmodempopover.ui statusCenter/popovers/wirelessnetworkselectionpopover.ui ) set(HEADERS chunk/chunkupdater.h chunk/genericchunkupdater.h chunk/networkchunk.h chunk/wiredchunkupdater.h chunk/wirelesschunkupdater.h networkplugincommon.h models/deviceconnectionlistmodel.h models/wirelessaccesspointsmodel.h models/wirelessconnectionlistmodel.h models/wirelessnetworklistdelegate.h onboarding/onboardingnetwork.h onboarding/wiredonboardingsetup.h onboarding/wirelessonboardingsetup.h plugin.h statusCenter/connectionEditor/connectioneditorpane.h statusCenter/connectionEditor/ipv4connectioneditorpane.h statusCenter/connectionEditor/networkconnectioneditor.h statusCenter/connectionEditor/wificonnectioneditorpane.h statusCenter/devicePanes/abstractdevicepane.h statusCenter/devicePanes/cellularpane.h statusCenter/devicePanes/devicepane.h statusCenter/devicePanes/wifidevicepane.h statusCenter/devicePanes/wireddevicepane.h statusCenter/eap/securityeap.h statusCenter/eap/securityeappeap.h statusCenter/eap/securityeapunsupported.h statusCenter/networkstatuscenterleftpane.h statusCenter/networkstatuscenterpane.h statusCenter/popovers/connectionselectionpopover.h statusCenter/popovers/simsettingspopover.h statusCenter/popovers/tetheringsettingspopover.h statusCenter/popovers/unlockmodempopover.h statusCenter/popovers/wirelessnetworkselectionpopover.h switchmanager.h ) set(PLUGIN_NAME network) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-network.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets Qt::Multimedia KF${KF_VERSION_MAJOR}::NetworkManagerQt KF${KF_VERSION_MAJOR}::ModemManagerQt PkgConfig::qrencode libcontemporary libthedesk) ================================================ FILE: plugins/NetworkPlugin/NetworkPlugin.pro ================================================ QT += gui widgets network concurrent TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) #For some reason they got rid of QMake support, so we'll have to hack this in for now qtHaveModule(ModemManagerQt) { QT += ModemManagerQt } else { INCLUDEPATH += /usr/include/KF5/ModemManagerQt/ /usr/include/ModemManager/ LIBS += -lKF5ModemManagerQt } qtHaveModule(NetworkManagerQt) { QT += NetworkManagerQt } else { INCLUDEPATH += /usr/include/KF5/NetworkManagerQt/ LIBS += -lKF5NetworkManagerQt } # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ chunk/chunkupdater.cpp \ chunk/genericchunkupdater.cpp \ chunk/networkchunk.cpp \ chunk/wiredchunkupdater.cpp \ chunk/wirelesschunkupdater.cpp \ common.cpp \ models/deviceconnectionlistmodel.cpp \ models/wirelessaccesspointsmodel.cpp \ models/wirelessconnectionlistmodel.cpp \ models/wirelessnetworklistdelegate.cpp \ onboarding/onboardingnetwork.cpp \ onboarding/wiredonboardingsetup.cpp \ onboarding/wirelessonboardingsetup.cpp \ plugin.cpp \ statusCenter/connectionEditor/connectioneditorpane.cpp \ statusCenter/connectionEditor/ipv4connectioneditorpane.cpp \ statusCenter/connectionEditor/networkconnectioneditor.cpp \ statusCenter/connectionEditor/wificonnectioneditorpane.cpp \ statusCenter/devicePanes/abstractdevicepane.cpp \ statusCenter/devicePanes/cellularpane.cpp \ statusCenter/devicePanes/devicepane.cpp \ statusCenter/devicePanes/wifidevicepane.cpp \ statusCenter/devicePanes/wireddevicepane.cpp \ statusCenter/eap/securityeap.cpp \ statusCenter/eap/securityeappeap.cpp \ statusCenter/eap/securityeapunsupported.cpp \ statusCenter/networkstatuscenterleftpane.cpp \ statusCenter/networkstatuscenterpane.cpp \ statusCenter/popovers/connectionselectionpopover.cpp \ statusCenter/popovers/simsettingspopover.cpp \ statusCenter/popovers/tetheringsettingspopover.cpp \ statusCenter/popovers/unlockmodempopover.cpp \ statusCenter/popovers/wirelessnetworkselectionpopover.cpp \ switchmanager.cpp HEADERS += \ chunk/chunkupdater.h \ chunk/genericchunkupdater.h \ chunk/networkchunk.h \ chunk/wiredchunkupdater.h \ chunk/wirelesschunkupdater.h \ common.h \ models/deviceconnectionlistmodel.h \ models/wirelessaccesspointsmodel.h \ models/wirelessconnectionlistmodel.h \ models/wirelessnetworklistdelegate.h \ onboarding/onboardingnetwork.h \ onboarding/wiredonboardingsetup.h \ onboarding/wirelessonboardingsetup.h \ plugin.h \ statusCenter/connectionEditor/connectioneditorpane.h \ statusCenter/connectionEditor/ipv4connectioneditorpane.h \ statusCenter/connectionEditor/networkconnectioneditor.h \ statusCenter/connectionEditor/wificonnectioneditorpane.h \ statusCenter/devicePanes/abstractdevicepane.h \ statusCenter/devicePanes/cellularpane.h \ statusCenter/devicePanes/devicepane.h \ statusCenter/devicePanes/wifidevicepane.h \ statusCenter/devicePanes/wireddevicepane.h \ statusCenter/eap/securityeap.h \ statusCenter/eap/securityeappeap.h \ statusCenter/eap/securityeapunsupported.h \ statusCenter/networkstatuscenterleftpane.h \ statusCenter/networkstatuscenterpane.h \ statusCenter/popovers/connectionselectionpopover.h \ statusCenter/popovers/simsettingspopover.h \ statusCenter/popovers/tetheringsettingspopover.h \ statusCenter/popovers/unlockmodempopover.h \ statusCenter/popovers/wirelessnetworkselectionpopover.h \ switchmanager.h DISTFILES += \ Plugin.json \ defaults.conf unix { CONFIG += link_pkgconfig PKGCONFIG += libnm libqrencode translations.files = translations/*.qm translations.path = /usr/share/thedesk/NetworkPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/NetworkPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ onboarding/onboardingnetwork.ui \ onboarding/wiredonboardingsetup.ui \ onboarding/wirelessonboardingsetup.ui \ statusCenter/connectionEditor/ipv4connectioneditorpane.ui \ statusCenter/connectionEditor/networkconnectioneditor.ui \ statusCenter/connectionEditor/wificonnectioneditorpane.ui \ statusCenter/devicePanes/cellularpane.ui \ statusCenter/devicePanes/devicepane.ui \ statusCenter/devicePanes/wifidevicepane.ui \ statusCenter/devicePanes/wireddevicepane.ui \ statusCenter/eap/securityeappeap.ui \ statusCenter/eap/securityeapunsupported.ui \ statusCenter/networkstatuscenterleftpane.ui \ statusCenter/networkstatuscenterpane.ui \ statusCenter/popovers/connectionselectionpopover.ui \ statusCenter/popovers/simsettingspopover.ui \ statusCenter/popovers/tetheringsettingspopover.ui \ statusCenter/popovers/unlockmodempopover.ui \ statusCenter/popovers/wirelessnetworkselectionpopover.ui ================================================ FILE: plugins/NetworkPlugin/Plugin.json ================================================ { "name": "Network Management", "icon": "preferences-system-network", "uuid": "238083b1-2952-4000-8c13-cb585487cc1a", "vi": { "name": "Quản lý mạng" } } ================================================ FILE: plugins/NetworkPlugin/chunk/chunkupdater.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "chunkupdater.h" struct ChunkUpdaterPrivate { QIcon icon; QString text; }; ChunkUpdater::ChunkUpdater(QObject* parent) : QObject(parent) { d = new ChunkUpdaterPrivate(); } ChunkUpdater::~ChunkUpdater() { delete d; } QIcon ChunkUpdater::icon() { return d->icon; } QString ChunkUpdater::text() { return d->text; } void ChunkUpdater::setText(QString text) { d->text = text; emit textChanged(text); } void ChunkUpdater::setIcon(QIcon icon) { d->icon = icon; emit iconChanged(icon); } ================================================ FILE: plugins/NetworkPlugin/chunk/chunkupdater.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CHUNKUPDATER_H #define CHUNKUPDATER_H #include #include struct ChunkUpdaterPrivate; class ChunkUpdater : public QObject { Q_OBJECT public: explicit ChunkUpdater(QObject* parent = nullptr); ~ChunkUpdater(); QIcon icon(); QString text(); signals: void iconChanged(QIcon icon); void textChanged(QString text); protected: void setText(QString text); void setIcon(QIcon icon); private: ChunkUpdaterPrivate* d; }; #endif // CHUNKUPDATER_H ================================================ FILE: plugins/NetworkPlugin/chunk/genericchunkupdater.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "genericchunkupdater.h" GenericChunkUpdater::GenericChunkUpdater(QObject* parent) : ChunkUpdater(parent) { this->setIcon(QIcon::fromTheme("network-wired")); this->setText(tr("Connected")); } ================================================ FILE: plugins/NetworkPlugin/chunk/genericchunkupdater.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef GENERICCHUNKUPDATER_H #define GENERICCHUNKUPDATER_H #include "chunkupdater.h" class GenericChunkUpdater : public ChunkUpdater { Q_OBJECT public: explicit GenericChunkUpdater(QObject* parent = nullptr); signals: }; #endif // GENERICCHUNKUPDATER_H ================================================ FILE: plugins/NetworkPlugin/chunk/networkchunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "networkchunk.h" #include #include #include #include #include #include #include #include #include #include #include #include "genericchunkupdater.h" #include "wiredchunkupdater.h" #include "wirelesschunkupdater.h" struct NetworkChunkPrivate { bool chunkShown = false; QDBusServiceWatcher* nmWatcher; NetworkManager::ActiveConnection::Ptr primary; ChunkUpdater* updater = nullptr; NetworkManager::AccessPoint::Ptr ap; }; NetworkChunk::NetworkChunk() : IconTextChunk("Network") { d = new NetworkChunkPrivate(); d->nmWatcher = new QDBusServiceWatcher("org.freedesktop.NetworkManager", QDBusConnection::systemBus()); connect(d->nmWatcher, &QDBusServiceWatcher::serviceRegistered, this, &NetworkChunk::networkManagerRunning); connect(d->nmWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &NetworkChunk::networkManagerGone); if (QDBusConnection::systemBus().interface()->registeredServiceNames().value().contains("org.freedesktop.NetworkManager")) networkManagerRunning(); connect(NetworkManager::notifier(), &NetworkManager::Notifier::primaryConnectionChanged, this, &NetworkChunk::updatePrimaryConnection); connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &NetworkChunk::updateText); ActionQuickWidget* quickWidget = new ActionQuickWidget(this); quickWidget->addAction(QIcon::fromTheme("configure"), tr("Network Settings"), [=] { StateManager::statusCenterManager()->showWithPane("NetworkManagerPane"); }); this->setQuickWidget(quickWidget); } NetworkChunk::~NetworkChunk() { networkManagerGone(); delete d; } void NetworkChunk::networkManagerRunning() { if (!d->chunkShown) { StateManager::barManager()->addChunk(this); d->chunkShown = true; updatePrimaryConnection(); } } void NetworkChunk::networkManagerGone() { if (d->chunkShown) { StateManager::barManager()->removeChunk(this); d->chunkShown = false; } } void NetworkChunk::updatePrimaryConnection() { if (d->updater) { d->updater->deleteLater(); d->updater = nullptr; } d->primary = NetworkManager::primaryConnection(); if (d->primary.isNull()) { // No primary connection exists QTimer::singleShot(0, [=] { this->setIcon(QIcon::fromTheme("network-wired-unavailable")); this->setText(tr("Disconnected")); }); return; } connect(d->primary.data(), &NetworkManager::ActiveConnection::specificObjectChanged, this, &NetworkChunk::updatePrimaryConnection); switch (d->primary->type()) { case NetworkManager::ConnectionSettings::Wireless: d->updater = new WirelessChunkUpdater(this); break; case NetworkManager::ConnectionSettings::Wired: d->updater = new WiredChunkUpdater(this); break; default: d->updater = new GenericChunkUpdater(this); break; } connect(d->updater, &ChunkUpdater::iconChanged, this, &NetworkChunk::setIcon); connect(d->updater, &ChunkUpdater::textChanged, this, &NetworkChunk::updateText); this->setIcon(d->updater->icon()); this->setText(d->updater->text()); } void NetworkChunk::updateText() { // Keep the text as is if there is no updater; we're disconnected! if (!d->updater) return; QStringList text; text.append(d->updater->text()); switch (NetworkManager::connectivity()) { case NetworkManager::Portal: text.append(tr("Login Required")); break; case NetworkManager::Limited: text.append(tr("Can't get to the Internet")); break; case NetworkManager::NoConnectivity: case NetworkManager::UnknownConnectivity: case NetworkManager::Full: break; } this->setText(text.join(" · ")); } ================================================ FILE: plugins/NetworkPlugin/chunk/networkchunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NETWORKCHUNK_H #define NETWORKCHUNK_H #include struct NetworkChunkPrivate; class NetworkChunk : public IconTextChunk { Q_OBJECT public: explicit NetworkChunk(); ~NetworkChunk(); signals: private: NetworkChunkPrivate* d; void networkManagerRunning(); void networkManagerGone(); void updatePrimaryConnection(); void updateText(); }; #endif // NETWORKCHUNK_H ================================================ FILE: plugins/NetworkPlugin/chunk/wiredchunkupdater.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wiredchunkupdater.h" #include WiredChunkUpdater::WiredChunkUpdater(QObject* parent) : ChunkUpdater(parent) { this->setText(tr("Wired")); connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &WiredChunkUpdater::updateChunk); updateChunk(); } void WiredChunkUpdater::updateChunk() { if (NetworkManager::connectivity() != NetworkManager::Connectivity::Full) { this->setIcon(QIcon::fromTheme("network-wired-error")); } else { this->setIcon(QIcon::fromTheme("network-wired-activated")); } } ================================================ FILE: plugins/NetworkPlugin/chunk/wiredchunkupdater.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIREDCHUNKUPDATER_H #define WIREDCHUNKUPDATER_H #include "chunkupdater.h" class WiredChunkUpdater : public ChunkUpdater { Q_OBJECT public: explicit WiredChunkUpdater(QObject* parent = nullptr); signals: private: void updateChunk(); }; #endif // WIREDCHUNKUPDATER_H ================================================ FILE: plugins/NetworkPlugin/chunk/wirelesschunkupdater.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wirelesschunkupdater.h" #include #include #include #include "networkplugincommon.h" struct WirelessChunkUpdaterPrivate { NetworkManager::AccessPoint::Ptr ap; }; WirelessChunkUpdater::WirelessChunkUpdater(QObject* parent) : ChunkUpdater(parent) { d = new WirelessChunkUpdaterPrivate(); NetworkManager::ActiveConnection::Ptr connection = NetworkManager::primaryConnection(); d->ap.reset(new NetworkManager::AccessPoint(connection->specificObject())); connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &WirelessChunkUpdater::updateChunk); connect(d->ap.data(), &NetworkManager::AccessPoint::ssidChanged, this, &WirelessChunkUpdater::updateChunk); connect(d->ap.data(), &NetworkManager::AccessPoint::signalStrengthChanged, this, &WirelessChunkUpdater::updateChunk); updateChunk(); } WirelessChunkUpdater::~WirelessChunkUpdater() { delete d; } void WirelessChunkUpdater::updateChunk() { this->setText(d->ap->ssid()); NetworkPluginCommon::WirelessType type = NetworkPluginCommon::WiFi; if (NetworkManager::connectivity() != NetworkManager::Full) type = NetworkPluginCommon::WiFiError; this->setIcon(QIcon::fromTheme(NetworkPluginCommon::iconForSignalStrength(d->ap->signalStrength(), type))); } ================================================ FILE: plugins/NetworkPlugin/chunk/wirelesschunkupdater.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIRELESSCHUNKUPDATER_H #define WIRELESSCHUNKUPDATER_H #include "chunkupdater.h" struct WirelessChunkUpdaterPrivate; class WirelessChunkUpdater : public ChunkUpdater { Q_OBJECT public: explicit WirelessChunkUpdater(QObject* parent = nullptr); ~WirelessChunkUpdater(); signals: private: WirelessChunkUpdaterPrivate* d; void updateChunk(); }; #endif // WIRELESSCHUNKUPDATER_H ================================================ FILE: plugins/NetworkPlugin/models/deviceconnectionlistmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "deviceconnectionlistmodel.h" #include #include #include struct DeviceConnectionListModelPrivate { NetworkManager::Device::Ptr device; }; DeviceConnectionListModel::DeviceConnectionListModel(QString deviceUni, QObject* parent) : QAbstractListModel(parent) { d = new DeviceConnectionListModelPrivate(); d->device = NetworkManager::findNetworkInterface(deviceUni); } DeviceConnectionListModel::~DeviceConnectionListModel() { delete d; } int DeviceConnectionListModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return d->device->availableConnections().count(); } QVariant DeviceConnectionListModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); NetworkManager::Connection::Ptr connection = d->device->availableConnections().at(index.row()); switch (role) { case Qt::DisplayRole: return connection->name(); case Qt::UserRole: return QVariant::fromValue(connection); case Qt::UserRole + 1: return "connection"; } return QVariant(); } ================================================ FILE: plugins/NetworkPlugin/models/deviceconnectionlistmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef DEVICECONNECTIONLISTMODEL_H #define DEVICECONNECTIONLISTMODEL_H #include struct DeviceConnectionListModelPrivate; class DeviceConnectionListModel : public QAbstractListModel { Q_OBJECT public: explicit DeviceConnectionListModel(QString deviceUni, QObject* parent = nullptr); ~DeviceConnectionListModel(); // Basic functionality: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; private: DeviceConnectionListModelPrivate* d; }; #endif // DEVICECONNECTIONLISTMODEL_H ================================================ FILE: plugins/NetworkPlugin/models/wirelessaccesspointsmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wirelessaccesspointsmodel.h" #include #include #include #include #include struct WirelessAccessPointsModelPrivate { NetworkManager::WirelessDevice::Ptr device; QList displayedAPs; bool includeKnown; }; WirelessAccessPointsModel::WirelessAccessPointsModel(QString deviceUni, bool includeKnown, QObject* parent) : QAbstractListModel(parent) { d = new WirelessAccessPointsModelPrivate(); d->includeKnown = includeKnown; d->device = NetworkManager::findNetworkInterface(deviceUni).staticCast(); d->device->requestScan(); connect(d->device.data(), &NetworkManager::WirelessDevice::accessPointAppeared, this, &WirelessAccessPointsModel::addAp); connect(d->device.data(), &NetworkManager::WirelessDevice::accessPointDisappeared, this, &WirelessAccessPointsModel::removeAp); for (QString ap : d->device->accessPoints()) { this->addAp(ap); } } WirelessAccessPointsModel::~WirelessAccessPointsModel() { delete d; } int WirelessAccessPointsModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return d->displayedAPs.count(); } QVariant WirelessAccessPointsModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); NetworkManager::AccessPoint::Ptr ap = d->displayedAPs.at(index.row()); switch (role) { case Qt::DisplayRole: return ap->ssid(); case Qt::UserRole: return QVariant::fromValue(ap); case Qt::UserRole + 1: return "ap"; } return QVariant(); } void WirelessAccessPointsModel::addAp(QString ap) { NetworkManager::AccessPoint::Ptr accessPoint(new NetworkManager::AccessPoint(ap)); if (accessPoint->ssid().isEmpty()) return; for (NetworkManager::AccessPoint::Ptr oldAp : d->displayedAPs) { if (oldAp->uni() == ap) return; if (oldAp->ssid() == accessPoint->ssid()) return; } if (!d->includeKnown) { for (NetworkManager::Connection::Ptr connection : NetworkManager::listConnections()) { NetworkManager::WirelessSetting::Ptr wlSetting = connection->settings()->setting(NetworkManager::Setting::Wireless).staticCast(); if (wlSetting) { if (wlSetting->ssid() == accessPoint->ssid()) return; } } } d->displayedAPs.append(accessPoint); emit dataChanged(index(0), index(rowCount())); } void WirelessAccessPointsModel::removeAp(QString ap) { for (NetworkManager::AccessPoint::Ptr accessPoint : d->displayedAPs) { if (accessPoint->uni() == ap) { d->displayedAPs.removeOne(accessPoint); emit dataChanged(index(0), index(rowCount())); return; } } } ================================================ FILE: plugins/NetworkPlugin/models/wirelessaccesspointsmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIRELESSACCESSPOINTSMODEL_H #define WIRELESSACCESSPOINTSMODEL_H #include struct WirelessAccessPointsModelPrivate; class WirelessAccessPointsModel : public QAbstractListModel { Q_OBJECT public: explicit WirelessAccessPointsModel(QString deviceUni, bool includeKnown = true, QObject* parent = nullptr); ~WirelessAccessPointsModel(); // Basic functionality: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; private: WirelessAccessPointsModelPrivate* d; void addAp(QString ap); void removeAp(QString ap); }; #endif // WIRELESSACCESSPOINTSMODEL_H ================================================ FILE: plugins/NetworkPlugin/models/wirelessconnectionlistmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wirelessconnectionlistmodel.h" #include #include #include struct WirelessConnectionListModelPrivate { QList connections; }; WirelessConnectionListModel::WirelessConnectionListModel(QObject* parent) : QAbstractListModel(parent) { d = new WirelessConnectionListModelPrivate(); connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &WirelessConnectionListModel::newConnection); connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionRemoved, this, &WirelessConnectionListModel::removeConnection); for (NetworkManager::Connection::Ptr connection : NetworkManager::listConnections()) { this->newConnection(connection->path()); } } WirelessConnectionListModel::~WirelessConnectionListModel() { delete d; } int WirelessConnectionListModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return d->connections.count(); } QVariant WirelessConnectionListModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); NetworkManager::Connection::Ptr cn = d->connections.at(index.row()); switch (role) { case Qt::DisplayRole: return cn->name(); case Qt::UserRole: return QVariant::fromValue(cn); case Qt::UserRole + 1: return "connection"; } return QVariant(); } void WirelessConnectionListModel::newConnection(QString connection) { NetworkManager::Connection::Ptr cn(new NetworkManager::Connection(connection)); NetworkManager::WirelessSetting::Ptr wlSetting = cn->settings()->setting(NetworkManager::Setting::Wireless).staticCast(); if (!wlSetting) return; d->connections.append(cn); emit dataChanged(index(0), index(rowCount())); } void WirelessConnectionListModel::removeConnection(QString connection) { for (NetworkManager::Connection::Ptr cn : d->connections) { if (cn->path() == connection) { d->connections.removeOne(cn); emit dataChanged(index(0), index(rowCount())); return; } } } ================================================ FILE: plugins/NetworkPlugin/models/wirelessconnectionlistmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIRELESSCONNECTIONLISTMODEL_H #define WIRELESSCONNECTIONLISTMODEL_H #include struct WirelessConnectionListModelPrivate; class WirelessConnectionListModel : public QAbstractListModel { Q_OBJECT public: explicit WirelessConnectionListModel(QObject* parent = nullptr); ~WirelessConnectionListModel(); // Basic functionality: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; private: WirelessConnectionListModelPrivate* d; void newConnection(QString connection); void removeConnection(QString connection); }; #endif // WIRELESSCONNECTIONLISTMODEL_H ================================================ FILE: plugins/NetworkPlugin/models/wirelessnetworklistdelegate.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wirelessnetworklistdelegate.h" #include #include #include #include #include #include #include "networkplugincommon.h" struct WirelessNetworkListDelegatePrivate { NetworkManager::WirelessDevice::Ptr device; struct Rects { QRect iconRect; QRect textRect; QRect descRect; Rects(const QStyleOptionViewItem& option) { iconRect.setLeft(option.rect.left() + SC_DPI(6)); iconRect.setTop(option.rect.top() + SC_DPI(6)); iconRect.setBottom(iconRect.top() + SC_DPI(32)); iconRect.setRight(iconRect.left() + SC_DPI(32)); textRect.setLeft(iconRect.right() + SC_DPI(6)); textRect.setTop(option.rect.top() + SC_DPI(6)); textRect.setBottom(option.rect.top() + option.fontMetrics.height() + SC_DPI(6)); textRect.setRight(option.rect.right()); descRect.setLeft(iconRect.right() + SC_DPI(6)); descRect.setTop(option.rect.top() + option.fontMetrics.height() + SC_DPI(8)); descRect.setBottom(option.rect.top() + option.fontMetrics.height() * 2 + SC_DPI(6)); descRect.setRight(option.rect.right()); } }; }; WirelessNetworkListDelegate::WirelessNetworkListDelegate(QString deviceUni, QObject* parent) : QAbstractItemDelegate(parent) { d = new WirelessNetworkListDelegatePrivate(); d->device = NetworkManager::findNetworkInterface(deviceUni).staticCast(); } WirelessNetworkListDelegate::~WirelessNetworkListDelegate() { delete d; } void WirelessNetworkListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { painter->setFont(option.font); painter->setLayoutDirection(option.direction); WirelessNetworkListDelegatePrivate::Rects rects(option); QString text = index.data().toString(); QString desc; QIcon icon; QVariant networkInformation = index.data(Qt::UserRole); if (networkInformation.canConvert()) { NetworkManager::Connection::Ptr connection = networkInformation.value(); QString targetSsid = connection->settings()->setting(NetworkManager::Setting::Wireless).staticCast()->ssid(); for (QString apPath : d->device->accessPoints()) { NetworkManager::AccessPoint::Ptr ap(new NetworkManager::AccessPoint(apPath)); if (ap->ssid() == targetSsid) { if (d->device->activeAccessPoint() && ap->uni() == d->device->activeAccessPoint()->uni()) { desc = tr("Connected"); icon = QIcon::fromTheme(NetworkPluginCommon::iconForSignalStrength(ap->signalStrength(), NetworkPluginCommon::WiFi)); break; } else { desc = tr("In Range"); icon = QIcon::fromTheme(NetworkPluginCommon::iconForSignalStrength(ap->signalStrength(), NetworkPluginCommon::WiFi)); break; } } } if (desc.isEmpty()) { desc = tr("Out of range"); } } else if (networkInformation.canConvert()) { NetworkManager::AccessPoint::Ptr ap = networkInformation.value(); icon = QIcon::fromTheme(NetworkPluginCommon::iconForSignalStrength(ap->signalStrength(), NetworkPluginCommon::WiFi)); NetworkManager::WirelessSecurityType security = NetworkManager::findBestWirelessSecurity(d->device->wirelessCapabilities(), true, false, ap->capabilities(), ap->wpaFlags(), ap->rsnFlags()); switch (security) { case NetworkManager::UnknownSecurity: case NetworkManager::NoneSecurity: desc = tr("Not Secured"); break; case NetworkManager::StaticWep: desc = tr("Secured with Static WEP"); break; case NetworkManager::DynamicWep: desc = tr("Secured with Dynamic WEP"); break; case NetworkManager::Leap: desc = tr("Secured with LEAP"); break; case NetworkManager::WpaPsk: desc = tr("Secured with WPA-PSK"); break; case NetworkManager::WpaEap: desc = tr("Secured with WPA Enterprise"); break; case NetworkManager::Wpa2Psk: desc = tr("Secured with WPA2-PSK"); break; case NetworkManager::Wpa2Eap: desc = tr("Secured with WPA2 Enterprise"); break; case NetworkManager::SAE: desc = tr("Secured with WPA3"); break; } } if (option.direction == Qt::RightToLeft) { rects.iconRect.moveRight(option.rect.right() - SC_DPI(6)); rects.textRect.moveRight(rects.iconRect.left() - SC_DPI(6)); rects.descRect.moveRight(rects.iconRect.left() - SC_DPI(6)); } if (option.state & QStyle::State_Selected) { painter->setPen(Qt::transparent); painter->setBrush(option.palette.color(QPalette::Highlight)); painter->drawRect(option.rect); painter->setBrush(Qt::transparent); painter->setPen(option.palette.color(QPalette::HighlightedText)); painter->drawText(rects.textRect, Qt::AlignLeading, text); painter->drawText(rects.descRect, Qt::AlignLeading, desc); } else if (option.state & QStyle::State_MouseOver) { QColor col = option.palette.color(QPalette::Highlight); col.setAlpha(127); painter->setBrush(col); painter->setPen(Qt::transparent); painter->drawRect(option.rect); painter->setBrush(Qt::transparent); painter->setPen(option.palette.color(QPalette::WindowText)); painter->drawText(rects.textRect, Qt::AlignLeading, text); painter->setPen(option.palette.color(QPalette::Disabled, QPalette::WindowText)); painter->drawText(rects.descRect, Qt::AlignLeading, desc); } else { painter->setPen(option.palette.color(QPalette::WindowText)); painter->drawText(rects.textRect, Qt::AlignLeading, text); painter->setPen(option.palette.color(QPalette::Disabled, QPalette::WindowText)); painter->drawText(rects.descRect, Qt::AlignLeading, desc); } if (!icon.isNull()) { painter->drawPixmap(rects.iconRect, icon.pixmap(rects.iconRect.size())); } } QSize WirelessNetworkListDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { WirelessNetworkListDelegatePrivate::Rects rects(option); QRect u = rects.iconRect; u = u.united(rects.textRect); u = u.united(rects.descRect); u.adjust(SC_DPI(-6), SC_DPI(-6), SC_DPI(6), SC_DPI(6)); return u.size(); } ================================================ FILE: plugins/NetworkPlugin/models/wirelessnetworklistdelegate.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIRELESSNETWORKLISTDELEGATE_H #define WIRELESSNETWORKLISTDELEGATE_H #include struct WirelessNetworkListDelegatePrivate; class WirelessNetworkListDelegate : public QAbstractItemDelegate { Q_OBJECT public: explicit WirelessNetworkListDelegate(QString deviceUni, QObject* parent = nullptr); ~WirelessNetworkListDelegate(); signals: private: WirelessNetworkListDelegatePrivate* d; // QAbstractItemDelegate interface public: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; }; #endif // WIRELESSNETWORKLISTDELEGATE_H ================================================ FILE: plugins/NetworkPlugin/networkplugincommon.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "networkplugincommon.h" #include QString NetworkPluginCommon::stateChangeReasonToString(NetworkManager::Device::StateChangeReason reason) { switch (reason) { case NetworkManager::Device::NowUnmanagedReason: return tr("the device is no longer managed by NetworkManager"); case NetworkManager::Device::ConfigFailedReason: return tr("configuration of the device failed"); case NetworkManager::Device::ConfigUnavailableReason: return tr("configuration of the device is unavailable"); case NetworkManager::Device::ConfigExpiredReason: return tr("configuration of the device expired"); case NetworkManager::Device::NoSecretsReason: return tr("required secrets were not provided"); case NetworkManager::Device::AuthSupplicantDisconnectReason: return tr("the authentication supplicant disconnected"); case NetworkManager::Device::AuthSupplicantConfigFailedReason: return tr("configuration of the authentication supplicant failed"); case NetworkManager::Device::AuthSupplicantFailedReason: return tr("the authentication supplicant failed"); case NetworkManager::Device::AuthSupplicantTimeoutReason: return tr("the authentication supplicant timed out"); case NetworkManager::Device::PppStartFailedReason: return tr("the PPP network failed to start"); case NetworkManager::Device::PppDisconnectReason: return tr("the PPP network was disconnected"); case NetworkManager::Device::PppFailedReason: return tr("the PPP network failed"); case NetworkManager::Device::DhcpStartFailedReason: return tr("DHCP configuration failed to start"); case NetworkManager::Device::DhcpErrorReason: return tr("DHCP configuration had an error"); case NetworkManager::Device::DhcpFailedReason: return tr("DHCP configuration failed"); case NetworkManager::Device::SharedStartFailedReason: break; case NetworkManager::Device::SharedFailedReason: break; case NetworkManager::Device::AutoIpStartFailedReason: break; case NetworkManager::Device::AutoIpErrorReason: break; case NetworkManager::Device::AutoIpFailedReason: break; case NetworkManager::Device::ModemBusyReason: return tr("the modem is busy"); case NetworkManager::Device::ModemNoDialToneReason: return tr("there is no dial tone on the modem"); case NetworkManager::Device::ModemNoCarrierReason: return tr("no carrier is available on the modem"); case NetworkManager::Device::ModemDialTimeoutReason: return tr("dialling the number on the modem timed out"); case NetworkManager::Device::ModemDialFailedReason: return tr("dialling the number on the modem failed"); case NetworkManager::Device::ModemInitFailedReason: return tr("initialising the modem failed"); case NetworkManager::Device::GsmApnSelectFailedReason: return tr("APN selection failed"); case NetworkManager::Device::GsmNotSearchingReason: return tr("the modem is not searching"); case NetworkManager::Device::GsmRegistrationDeniedReason: return tr("the cell tower denied registration of the modem"); case NetworkManager::Device::GsmRegistrationTimeoutReason: return tr("registration of the modem on the cell tower timed out"); case NetworkManager::Device::GsmRegistrationFailedReason: return tr("registration of the modem on the cell tower failed"); case NetworkManager::Device::GsmPinCheckFailedReason: break; case NetworkManager::Device::FirmwareMissingReason: return tr("the device firmware is missing"); case NetworkManager::Device::DeviceRemovedReason: return tr("the device was removed"); case NetworkManager::Device::SleepingReason: return tr("the device is sleeping"); case NetworkManager::Device::ConnectionRemovedReason: return tr("the connection was removed"); case NetworkManager::Device::UserRequestedReason: return tr("you requested the action"); case NetworkManager::Device::CarrierReason: break; case NetworkManager::Device::ConnectionAssumedReason: break; case NetworkManager::Device::SupplicantAvailableReason: break; case NetworkManager::Device::ModemNotFoundReason: return tr("the modem was not found"); case NetworkManager::Device::BluetoothFailedReason: return tr("Bluetooth is not available"); case NetworkManager::Device::GsmSimNotInserted: return tr("the SIM card is not inserted"); case NetworkManager::Device::GsmSimPinRequired: return tr("the SIM PIN is required"); case NetworkManager::Device::GsmSimPukRequired: return tr("the SIM PUK is required"); case NetworkManager::Device::GsmSimWrong: case NetworkManager::Device::SimPinIncorrect: return tr("the SIM PUK is exhausted"); case NetworkManager::Device::InfiniBandMode: break; case NetworkManager::Device::DependencyFailed: break; case NetworkManager::Device::Br2684Failed: break; case NetworkManager::Device::ModemManagerUnavailable: return tr("ModemManager is not operational on this device"); case NetworkManager::Device::SsidNotFound: return tr("the wireless network wasn't found"); case NetworkManager::Device::SecondaryConnectionFailed: break; case NetworkManager::Device::DcbFcoeFailed: break; case NetworkManager::Device::TeamdControlFailed: break; case NetworkManager::Device::ModemFailed: break; case NetworkManager::Device::ModemAvailable: break; case NetworkManager::Device::NewActivation: break; case NetworkManager::Device::ParentChanged: break; case NetworkManager::Device::ParentManagedChanged: break; case NetworkManager::Device::Reserved: case NetworkManager::Device::UnknownReason: case NetworkManager::Device::NoReason: case NetworkManager::Device::NowManagedReason: break; } return tr("an unknown error occurred"); } QString NetworkPluginCommon::iconForSignalStrength(int strength, NetworkPluginCommon::WirelessType type) { QString iconString = "network-"; switch (type) { case NetworkPluginCommon::WiFi: iconString += "wireless-connected-"; break; case NetworkPluginCommon::WiFiError: iconString += "wireless-error-"; break; case NetworkPluginCommon::Cellular: iconString += "cellular-connected-"; break; case NetworkPluginCommon::CellularError: iconString += "cellular-error-"; break; } if (strength < 15) { iconString += "00"; } else if (strength < 35) { iconString += "25"; } else if (strength < 65) { iconString += "50"; } else if (strength < 85) { iconString += "75"; } else { iconString += "100"; } return iconString; } QString NetworkPluginCommon::operatorNameForModem(ModemManager::ModemDevice::Ptr device) { if (device->sim() && !device->sim()->operatorName().isEmpty()) { return device->sim()->operatorName(); } ModemManager::Modem3gpp::Ptr modem3gpp(new ModemManager::Modem3gpp(device->uni())); if (!modem3gpp->operatorName().isEmpty()) { return modem3gpp->operatorName(); } return tr("Cellular"); } bool NetworkPluginCommon::isDeviceConnecting(NetworkManager::Device::Ptr device) { QList connectingStates = { NetworkManager::Device::Preparing, NetworkManager::Device::ConfiguringHardware, NetworkManager::Device::NeedAuth, NetworkManager::Device::ConfiguringIp, NetworkManager::Device::CheckingIp, NetworkManager::Device::WaitingForSecondaries}; return connectingStates.contains(device->state()); } ================================================ FILE: plugins/NetworkPlugin/networkplugincommon.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NETWORKPLUGINCOMMON_H #define NETWORKPLUGINCOMMON_H #include #include #include class NetworkPluginCommon { Q_DECLARE_TR_FUNCTIONS(Common) public: enum WirelessType { WiFi, Cellular, WiFiError, CellularError }; static QString stateChangeReasonToString(NetworkManager::Device::StateChangeReason reason); static QString iconForSignalStrength(int strength, WirelessType type); static QString operatorNameForModem(ModemManager::ModemDevice::Ptr device); static bool isDeviceConnecting(NetworkManager::Device::Ptr device); }; #endif // NETWORKPLUGINCOMMON_H ================================================ FILE: plugins/NetworkPlugin/onboarding/onboardingnetwork.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingnetwork.h" #include "ui_onboardingnetwork.h" #include #include #include "wiredonboardingsetup.h" #include "wirelessonboardingsetup.h" #include OnboardingNetwork::OnboardingNetwork(QWidget* parent) : OnboardingPage(parent), ui(new Ui::OnboardingNetwork) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); ui->disconnectButton->setProperty("type", "destructive"); ui->networkConnectedIcon->setPixmap(QIcon::fromTheme("network-wired-activated").pixmap(SC_DPI_T(QSize(128, 128), QSize))); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &OnboardingNetwork::updateConnectivity); updateConnectivity(); //Find out what network devices are available for (const NetworkManager::Device::Ptr& device : NetworkManager::networkInterfaces()) { QWidget* setupPane = nullptr; switch (device->type()) { case NetworkManager::Device::Ethernet: setupPane = new WiredOnboardingSetup(device->uni()); break; case NetworkManager::Device::Wifi: setupPane = new WirelessOnboardingSetup(device->uni()); break; default: break; } if (setupPane) { ui->panesLayout->addWidget(setupPane); } } } OnboardingNetwork::~OnboardingNetwork() { delete ui; } void OnboardingNetwork::updateConnectivity() { switch (NetworkManager::connectivity()) { case NetworkManager::UnknownConnectivity: case NetworkManager::NoConnectivity: ui->skipInfoPrompt->setVisible(true); ui->nextButton->setText(tr("Continue without Internet")); ui->stackedWidget->setCurrentWidget(ui->networkSelectionPage); break; case NetworkManager::Limited: case NetworkManager::Full: ui->skipInfoPrompt->setVisible(false); ui->nextButton->setText(tr("Next")); ui->stackedWidget->setCurrentWidget(ui->networkConnectionCompletePage); break; case NetworkManager::Portal: //TODO: something cool, maybe pop open a browser or something ui->skipInfoPrompt->setVisible(false); ui->nextButton->setText(tr("Next")); ui->stackedWidget->setCurrentWidget(ui->networkConnectionCompletePage); break; } } QString OnboardingNetwork::name() { return QStringLiteral("OnboardingNetwork"); } QString OnboardingNetwork::displayName() { return tr("Network"); } void OnboardingNetwork::on_titleLabel_backButtonClicked() { StateManager::onboardingManager()->previousStep(); } void OnboardingNetwork::on_nextButton_clicked() { StateManager::onboardingManager()->nextStep(); } void OnboardingNetwork::on_disconnectButton_clicked() { //Disconnect from all active connections for (NetworkManager::ActiveConnection::Ptr connection : NetworkManager::activeConnections()) { NetworkManager::deactivateConnection(connection->path()); } } ================================================ FILE: plugins/NetworkPlugin/onboarding/onboardingnetwork.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGNETWORK_H #define ONBOARDINGNETWORK_H #include namespace Ui { class OnboardingNetwork; } class OnboardingNetwork : public OnboardingPage { Q_OBJECT public: explicit OnboardingNetwork(QWidget* parent = nullptr); ~OnboardingNetwork(); private: Ui::OnboardingNetwork* ui; void updateConnectivity(); // OnboardingPage interface public: QString name(); QString displayName(); private slots: void on_titleLabel_backButtonClicked(); void on_nextButton_clicked(); void on_disconnectButton_clicked(); }; #endif // ONBOARDINGNETWORK_H ================================================ FILE: plugins/NetworkPlugin/onboarding/onboardingnetwork.ui ================================================ OnboardingNetwork 0 0 666 560 Form 0 0 0 0 0 Network Connect to the Internet to get updates and install new software. 9 16777215 1 Qt::Horizontal 1 0 0 0 0 0 QFrame::NoFrame true 0 0 100 30 0 0 0 0 0 0 0 0 0 0 Qt::Vertical 20 0 20 Qt::Vertical 20 153 false Qt::AlignCenter 15 You're connected! Qt::AlignCenter Disconnect and connect to a different network .. Qt::Vertical 20 153 16777215 1 Qt::Horizontal 6 9 9 9 9 Qt::Horizontal 40 20 You can always set up the network connection later. Next ../../../thedesk/libthedesk/onboarding../../../thedesk/libthedesk/onboarding tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/NetworkPlugin/onboarding/wiredonboardingsetup.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wiredonboardingsetup.h" #include "ui_wiredonboardingsetup.h" #include "networkplugincommon.h" #include #include #include #include #include "statusCenter/popovers/connectionselectionpopover.h" #include struct WiredOnboardingSetupPrivate { NetworkManager::WiredDevice::Ptr device; }; WiredOnboardingSetup::WiredOnboardingSetup(QString device, QWidget* parent) : QWidget(parent), ui(new Ui::WiredOnboardingSetup) { ui->setupUi(this); d = new WiredOnboardingSetupPrivate(); d->device = NetworkManager::WiredDevice::Ptr(new NetworkManager::WiredDevice(device)); connect(d->device.data(), &NetworkManager::WiredDevice::carrierChanged, this, &WiredOnboardingSetup::updateState); connect(d->device.data(), &NetworkManager::WiredDevice::stateChanged, this, &WiredOnboardingSetup::updateState); updateState(); ui->spinner->setFixedSize(SC_DPI_T(QSize(16, 16), QSize)); } WiredOnboardingSetup::~WiredOnboardingSetup() { delete ui; delete d; } void WiredOnboardingSetup::on_connectButton_clicked() { NetworkManager::Connection::List connections = NetworkManager::listConnections(); QtConcurrent::blockingFilter(connections, [=](const NetworkManager::Connection::Ptr& connection) { NetworkManager::ConnectionSettings::Ptr settings = connection->settings(); if (settings->interfaceName() != "" && d->device->interfaceName() != settings->interfaceName()) return false; // This connection is not applicable to this device return QList({NetworkManager::ConnectionSettings::Wired}).contains(connection->settings()->connectionType()); }); if (connections.count() == 0) { // Create a new automatic connection NetworkManager::ConnectionSettings settings(NetworkManager::ConnectionSettings::Wired); settings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); settings.setInterfaceName(d->device->interfaceName()); NetworkManager::addAndActivateConnection(settings.toMap(), d->device->uni(), ""); } else if (connections.count() == 1) { // Use this connection NetworkManager::activateConnection(connections.first()->path(), d->device->uni(), ""); } else { // Ask the user for the connection to use ConnectionSelectionPopover* selection = new ConnectionSelectionPopover(connections); tPopover* popover = new tPopover(selection); popover->setPopoverWidth(SC_DPI(600)); connect(selection, &ConnectionSelectionPopover::reject, popover, &tPopover::dismiss); connect(selection, &ConnectionSelectionPopover::accept, this, [=](NetworkManager::Connection::Ptr connection) { NetworkManager::activateConnection(connection->path(), d->device->uni(), ""); popover->dismiss(); }); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, selection, &ConnectionSelectionPopover::deleteLater); popover->show(this->window()); } } void WiredOnboardingSetup::updateState() { if (d->device->carrier()) { ui->stateDescription->setText(tr("Connect to the Internet using a wired network")); ui->connectButton->setEnabled(true); } else { ui->stateDescription->setText(tr("To connect to the Internet using a wired network, connect the network cable.")); ui->connectButton->setEnabled(false); } ui->spinner->setVisible(NetworkPluginCommon::isDeviceConnecting(d->device)); } ================================================ FILE: plugins/NetworkPlugin/onboarding/wiredonboardingsetup.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIREDONBOARDINGSETUP_H #define WIREDONBOARDINGSETUP_H #include namespace Ui { class WiredOnboardingSetup; } struct WiredOnboardingSetupPrivate; class WiredOnboardingSetup : public QWidget { Q_OBJECT public: explicit WiredOnboardingSetup(QString device, QWidget* parent = nullptr); ~WiredOnboardingSetup(); private slots: void on_connectButton_clicked(); private: Ui::WiredOnboardingSetup* ui; WiredOnboardingSetupPrivate* d; void updateState(); }; #endif // WIREDONBOARDINGSETUP_H ================================================ FILE: plugins/NetworkPlugin/onboarding/wiredonboardingsetup.ui ================================================ WiredOnboardingSetup 0 0 400 92 Form 0 0 0 0 0 6 9 9 9 9 true WIRED Connect to the Internet using a Wi-Fi network Use Wired Connection .. Qt::Horizontal 40 20 16777215 1 Qt::Horizontal tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/NetworkPlugin/onboarding/wirelessonboardingsetup.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wirelessonboardingsetup.h" #include "ui_wirelessonboardingsetup.h" #include "networkplugincommon.h" #include "statusCenter/popovers/wirelessnetworkselectionpopover.h" #include #include #include struct WirelessOnboardingSetupPrivate { NetworkManager::WirelessDevice::Ptr device; }; WirelessOnboardingSetup::WirelessOnboardingSetup(QString device, QWidget* parent) : QWidget(parent), ui(new Ui::WirelessOnboardingSetup) { ui->setupUi(this); d = new WirelessOnboardingSetupPrivate(); d->device = NetworkManager::WirelessDevice::Ptr(new NetworkManager::WirelessDevice(device)); connect(d->device.data(), &NetworkManager::WirelessDevice::stateChanged, this, &WirelessOnboardingSetup::updateState); updateState(); ui->spinner->setFixedSize(SC_DPI_T(QSize(16, 16), QSize)); } WirelessOnboardingSetup::~WirelessOnboardingSetup() { delete ui; delete d; } void WirelessOnboardingSetup::on_selectNetworkButton_clicked() { // Turn on Wi-Fi in case it is disabled NetworkManager::setWirelessEnabled(true); WirelessNetworkSelectionPopover* selection = new WirelessNetworkSelectionPopover(d->device->uni()); tPopover* popover = new tPopover(selection); popover->setPopoverWidth(SC_DPI(600)); connect(selection, &WirelessNetworkSelectionPopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, selection, &WirelessNetworkSelectionPopover::deleteLater); popover->show(this->window()); } void WirelessOnboardingSetup::updateState() { ui->spinner->setVisible(NetworkPluginCommon::isDeviceConnecting(d->device)); } ================================================ FILE: plugins/NetworkPlugin/onboarding/wirelessonboardingsetup.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIRELESSONBOARDINGSETUP_H #define WIRELESSONBOARDINGSETUP_H #include namespace Ui { class WirelessOnboardingSetup; } struct WirelessOnboardingSetupPrivate; class WirelessOnboardingSetup : public QWidget { Q_OBJECT public: explicit WirelessOnboardingSetup(QString device, QWidget* parent = nullptr); ~WirelessOnboardingSetup(); private slots: void on_selectNetworkButton_clicked(); private: Ui::WirelessOnboardingSetup* ui; WirelessOnboardingSetupPrivate* d; void updateState(); }; #endif // WIRELESSONBOARDINGSETUP_H ================================================ FILE: plugins/NetworkPlugin/onboarding/wirelessonboardingsetup.ui ================================================ WirelessOnboardingSetup 0 0 400 92 Form 0 0 0 0 0 6 9 9 9 9 true WI-FI Connect to the Internet using a Wi-Fi network Select Network .. Qt::Horizontal 40 20 16777215 1 Qt::Horizontal tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/NetworkPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "chunk/networkchunk.h" #include "switchmanager.h" #include "tsettings.h" #include #include #include #include #include #include #include #include #include "onboarding/onboardingnetwork.h" #include "statusCenter/networkstatuscenterpane.h" struct PluginPrivate { NetworkStatusCenterPane* statusCenterPane; NetworkChunk* chunk; SwitchManager* switches; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/NetworkPlugin/thedesk-network.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-network.conf"); d->chunk = new NetworkChunk(); d->switches = new SwitchManager(); d->statusCenterPane = new NetworkStatusCenterPane(d->switches); StateManager::statusCenterManager()->addPane(d->statusCenterPane); QObject::connect(StateManager::onboardingManager(), &OnboardingManager::onboardingRequired, [=] { StateManager::onboardingManager()->addOnboardingStep(new OnboardingNetwork()); }); } void Plugin::deactivate() { d->switches->deleteLater(); d->chunk->deleteLater(); StateManager::statusCenterManager()->removePane(d->statusCenterPane); d->statusCenterPane->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/NetworkPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/connectioneditorpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "connectioneditorpane.h" ConnectionEditorPane::ConnectionEditorPane(NetworkManager::Setting::Ptr setting, QWidget* parent) : QWidget(parent) { setting->setInitialized(true); } bool ConnectionEditorPane::prepareSave() { //noop return true; } ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/connectioneditorpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CONNECTIONEDITORPANE_H #define CONNECTIONEDITORPANE_H #include #include class ConnectionEditorPane : public QWidget { Q_OBJECT public: explicit ConnectionEditorPane(NetworkManager::Setting::Ptr setting, QWidget* parent = nullptr); virtual QString displayName() = 0; virtual void reload(NetworkManager::Setting::Ptr setting) = 0; virtual NetworkManager::Setting::SettingType type() = 0; virtual bool prepareSave(); signals: void setConnectionName(QString connectionName); void changed(); }; #endif // CONNECTIONEDITORPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/ipv4connectioneditorpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "ipv4connectioneditorpane.h" #include "ui_ipv4connectioneditorpane.h" #include #include #include #include struct IPv4ConnectionEditorPanePrivate { NetworkManager::Ipv4Setting::Ptr setting; }; IPv4ConnectionEditorPane::IPv4ConnectionEditorPane(NetworkManager::Setting::Ptr setting, QWidget* parent) : ConnectionEditorPane(setting, parent), ui(new Ui::IPv4ConnectionEditorPane) { ui->setupUi(this); d = new IPv4ConnectionEditorPanePrivate(); this->reload(setting); } IPv4ConnectionEditorPane::~IPv4ConnectionEditorPane() { delete d; delete ui; } void IPv4ConnectionEditorPane::updateDns() { ui->dnsList->clear(); for (QHostAddress address : d->setting->dns()) { QListWidgetItem* w = new QListWidgetItem(); w->setText(address.toString()); ui->dnsList->addItem(w); } } void IPv4ConnectionEditorPane::setAddresses() { QHostAddress addr(ui->ipAddress->text()); if (addr.isNull()) { d->setting->setAddressData({}); } else { d->setting->setAddressData({{ {"address", ui->ipAddress->text()}, {"prefix", static_cast(ui->ipSubnet->value())} }}); } emit changed(); } QString IPv4ConnectionEditorPane::displayName() { return tr("IPv4"); } void IPv4ConnectionEditorPane::on_configurationMethod_currentIndexChanged(int index) { bool configureAddresses = false; bool configureDns = false; switch (index) { case 0: //DHCP d->setting->setMethod(NetworkManager::Ipv4Setting::Automatic); d->setting->setIgnoreAutoDns(false); break; case 1: //DHCP, Manual DNS d->setting->setMethod(NetworkManager::Ipv4Setting::Automatic); d->setting->setIgnoreAutoDns(true); configureDns = true; break; case 2: //Manual d->setting->setMethod(NetworkManager::Ipv4Setting::Manual); configureAddresses = true; configureDns = true; break; case 3: //Shared d->setting->setMethod(NetworkManager::Ipv4Setting::Shared); break; case 4: //Disabled d->setting->setMethod(NetworkManager::Ipv4Setting::Disabled); break; } ui->addressesWidget->setExpanded(configureAddresses); ui->dnsWidget->setExpanded(configureDns); emit changed(); } void IPv4ConnectionEditorPane::on_requireIPv4Switch_toggled(bool checked) { d->setting->setMayFail(!checked); emit changed(); } void IPv4ConnectionEditorPane::reload(NetworkManager::Setting::Ptr setting) { d->setting = setting.staticCast(); d->setting->setInitialized(true); switch (d->setting->method()) { case NetworkManager::Ipv4Setting::Automatic: if (d->setting->ignoreAutoDns()) { //DHCP, Manual DNS ui->configurationMethod->setCurrentIndex(1); } else { //DHCP ui->configurationMethod->setCurrentIndex(0); } break; case NetworkManager::Ipv4Setting::LinkLocal: break; case NetworkManager::Ipv4Setting::Manual: ui->configurationMethod->setCurrentIndex(2); break; case NetworkManager::Ipv4Setting::Shared: ui->configurationMethod->setCurrentIndex(3); break; case NetworkManager::Ipv4Setting::Disabled: ui->configurationMethod->setCurrentIndex(4); break; } ui->requireIPv4Switch->setChecked(!d->setting->mayFail()); if (d->setting->addressData().count() > 0) { QVariantMap addressData = d->setting->addressData().first(); ui->ipAddress->setText(addressData.value("address").toString()); ui->ipSubnet->setValue(addressData.value("prefix").toInt()); } ui->ipGateway->setText(d->setting->gateway()); updateDns(); } NetworkManager::Setting::SettingType IPv4ConnectionEditorPane::type() { return NetworkManager::Setting::Ipv4; } bool IPv4ConnectionEditorPane::prepareSave() { switch (d->setting->method()) { case NetworkManager::Ipv4Setting::Automatic: case NetworkManager::Ipv4Setting::Shared: d->setting->setAddresses({}); d->setting->setAddressData({}); d->setting->setGateway(""); if (d->setting->ignoreAutoDns()) { if (d->setting->dns().count() == 0) { tErrorFlash::flashError(ui->dnsWidget); return false; } } else { //DHCP d->setting->setDns({}); } break; case NetworkManager::Ipv4Setting::Manual: if (ui->ipAddress->text().isEmpty()) { tErrorFlash::flashError(ui->ipAddress); return false; } if (ui->ipGateway->text().isEmpty()) { tErrorFlash::flashError(ui->ipGateway); return false; } if (d->setting->dns().count() == 0) { tErrorFlash::flashError(ui->dnsWidget); return false; } break; case NetworkManager::Ipv4Setting::LinkLocal: case NetworkManager::Ipv4Setting::Disabled: break; } return true; } void IPv4ConnectionEditorPane::on_addDnsServerButton_clicked() { QHostAddress address(ui->dnsServer->text()); if (address.isNull()) { tErrorFlash::flashError(ui->dnsServer); ui->dnsServer->setFocus(); return; } QList addresses = d->setting->dns(); addresses.append(address); d->setting->setDns(addresses); ui->dnsServer->clear(); updateDns(); ui->dnsServer->setFocus(); emit changed(); } void IPv4ConnectionEditorPane::on_dnsList_customContextMenuRequested(const QPoint& pos) { QListWidgetItem* item = ui->dnsList->itemAt(pos); int row = ui->dnsList->row(item); QMenu* menu = new QMenu(); menu->addSection(tr("For DNS server %1").arg(item->text())); menu->addAction(QIcon::fromTheme("list-remove"), tr("Remove"), this, [ = ] { QList addresses = d->setting->dns(); addresses.removeAt(row); d->setting->setDns(addresses); updateDns(); emit changed(); }); connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); menu->popup(ui->dnsList->mapToGlobal(pos)); } void IPv4ConnectionEditorPane::on_ipAddress_editingFinished() { QHostAddress addr(ui->ipAddress->text()); if (addr.isNull()) { tErrorFlash::flashError(ui->ipAddress); ui->ipAddress->clear(); return; } ui->ipAddress->setText(addr.toString()); setAddresses(); } void IPv4ConnectionEditorPane::on_ipSubnet_valueChanged(int arg1) { setAddresses(); } void IPv4ConnectionEditorPane::on_ipGateway_editingFinished() { QHostAddress addr(ui->ipGateway->text()); if (addr.isNull()) { tErrorFlash::flashError(ui->ipGateway); ui->ipGateway->clear(); return; } ui->ipGateway->setText(addr.toString()); d->setting->setGateway(ui->ipGateway->text()); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/ipv4connectioneditorpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef IPV4CONNECTIONEDITORPANE_H #define IPV4CONNECTIONEDITORPANE_H #include "connectioneditorpane.h" namespace Ui { class IPv4ConnectionEditorPane; } struct IPv4ConnectionEditorPanePrivate; class IPv4ConnectionEditorPane : public ConnectionEditorPane { Q_OBJECT public: explicit IPv4ConnectionEditorPane(NetworkManager::Setting::Ptr setting, QWidget* parent = nullptr); ~IPv4ConnectionEditorPane(); private: Ui::IPv4ConnectionEditorPane* ui; IPv4ConnectionEditorPanePrivate* d; void updateDns(); void setAddresses(); // ConnectionEditorPane interface public: QString displayName(); void reload(NetworkManager::Setting::Ptr setting); NetworkManager::Setting::SettingType type(); bool prepareSave(); private slots: void on_configurationMethod_currentIndexChanged(int index); void on_requireIPv4Switch_toggled(bool checked); void on_addDnsServerButton_clicked(); void on_dnsList_customContextMenuRequested(const QPoint& pos); void on_ipAddress_editingFinished(); void on_ipSubnet_valueChanged(int arg1); void on_ipGateway_editingFinished(); }; #endif // IPV4CONNECTIONEDITORPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/ipv4connectioneditorpane.ui ================================================ IPv4ConnectionEditorPane 0 0 419 456 Form 0 0 0 0 0 IPv4 QFrame::NoFrame true 0 0 405 532 0 0 0 0 0 9 9 9 9 6 0 0 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method RequireIPv4Switch Require IPv4 0 0 0 0 0 16777215 1 Qt::Horizontal 9 9 9 9 6 IP Address Default Gateway Subnet Length 75 true ADDRESSES 1 32 24 Set the IP address that this device will be assigned. true true 0 0 0 0 0 16777215 1 Qt::Horizontal 9 9 9 9 6 Qt::CustomContextMenu ... .. 75 true DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. true Qt::Vertical 20 0 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tSwitch QPushButton
tswitch.h
tConditionalWidget QWidget
tconditionalwidget.h
1
configurationMethod requireIPv4Switch ipAddress ipSubnet ipGateway dnsServer addDnsServerButton dnsList scrollArea dnsServer returnPressed() addDnsServerButton click() 333 330 387 330
================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/networkconnectioneditor.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "networkconnectioneditor.h" #include "ui_networkconnectioneditor.h" #include #include #include #include #include "wificonnectioneditorpane.h" #include "ipv4connectioneditorpane.h" struct NetworkConnectionEditorPrivate { NetworkManager::ConnectionSettings::Ptr connectionSettings; NetworkManager::Connection::Ptr connection; NMVariantMapMap oldSettings; bool haveUnsaved = false; QList panes; }; NetworkConnectionEditor::NetworkConnectionEditor(NetworkManager::ConnectionSettings::Ptr connectionSettings, QWidget* parent) : QWidget(parent), ui(new Ui::NetworkConnectionEditor) { ui->setupUi(this); this->init(); d->connectionSettings = connectionSettings; ui->saveWidget->setVisible(true); ui->unsavedPane->setVisible(false); this->populate(); } NetworkConnectionEditor::NetworkConnectionEditor(NetworkManager::Connection::Ptr connection, QWidget* parent) : QWidget(parent), ui(new Ui::NetworkConnectionEditor) { ui->setupUi(this); this->init(); d->connectionSettings = connection->settings(); d->connection = connection; d->oldSettings = connection->settings()->toMap(); ui->saveWidget->setVisible(false); ui->unsavedPane->setVisible(true); ui->unsavedPane->setFixedHeight(0); this->populate(); d->haveUnsaved = false; updateUnsaved(); } NetworkConnectionEditor::~NetworkConnectionEditor() { delete d; delete ui; } int NetworkConnectionEditor::preferredPopoverWidth() { return SC_DPI(-300); } void NetworkConnectionEditor::setSaveButtonText(QString text) { ui->saveButton->setText(text); } void NetworkConnectionEditor::on_titleLabel_backButtonClicked() { if (d->connection && d->haveUnsaved) { tErrorFlash::flashError(ui->unsavedPane); return; } emit rejected(); } void NetworkConnectionEditor::on_connectionName_textChanged(const QString& arg1) { ui->titleLabel->setText(arg1); d->connectionSettings->setId(arg1); } void NetworkConnectionEditor::init() { d = new NetworkConnectionEditorPrivate(); ui->leftWidget->setFixedWidth(SC_DPI(300)); ui->titleLabel->setBackButtonShown(true); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Lift); } void NetworkConnectionEditor::populate() { ui->connectionName->setText(d->connectionSettings->id()); ui->titleLabel->setText(d->connectionSettings->id()); for (NetworkManager::Setting::Ptr setting : d->connectionSettings->settings()) { ConnectionEditorPane* pane = nullptr; switch (setting->type()) { case NetworkManager::Setting::Wireless: pane = new WifiConnectionEditorPane(setting, this); break; case NetworkManager::Setting::Ipv4: pane = new IPv4ConnectionEditorPane(setting, this); break; case NetworkManager::Setting::Adsl: case NetworkManager::Setting::Cdma: case NetworkManager::Setting::Gsm: case NetworkManager::Setting::Infiniband: case NetworkManager::Setting::Ipv6: case NetworkManager::Setting::Ppp: case NetworkManager::Setting::Pppoe: case NetworkManager::Setting::Security8021x: case NetworkManager::Setting::Serial: case NetworkManager::Setting::Vpn: case NetworkManager::Setting::Wired: case NetworkManager::Setting::WirelessSecurity: case NetworkManager::Setting::Bluetooth: case NetworkManager::Setting::OlpcMesh: case NetworkManager::Setting::Vlan: case NetworkManager::Setting::Wimax: case NetworkManager::Setting::Bond: case NetworkManager::Setting::Bridge: case NetworkManager::Setting::BridgePort: case NetworkManager::Setting::Team: case NetworkManager::Setting::Generic: case NetworkManager::Setting::Tun: case NetworkManager::Setting::Vxlan: case NetworkManager::Setting::IpTunnel: case NetworkManager::Setting::Proxy: case NetworkManager::Setting::User: case NetworkManager::Setting::OvsBridge: case NetworkManager::Setting::OvsInterface: case NetworkManager::Setting::OvsPatch: case NetworkManager::Setting::OvsPort: case NetworkManager::Setting::Match: case NetworkManager::Setting::Tc: case NetworkManager::Setting::TeamPort: case NetworkManager::Setting::Macsec: case NetworkManager::Setting::Dcb: case NetworkManager::Setting::WireGuard: continue; } if (pane) { ui->stackedWidget->addWidget(pane); d->panes.append(pane); QListWidgetItem* item = new QListWidgetItem(); item->setText(pane->displayName()); ui->listWidget->addItem(item); connect(pane, &ConnectionEditorPane::setConnectionName, this, [ = ](QString connectionName) { d->connectionSettings->setId(connectionName); ui->connectionName->setText(connectionName); ui->titleLabel->setText(connectionName); }); connect(pane, &ConnectionEditorPane::changed, this, [ = ] { d->haveUnsaved = true; updateUnsaved(); }); } } } void NetworkConnectionEditor::updateUnsaved() { tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(ui->unsavedPane->height()); if (d->haveUnsaved) { anim->setEndValue(ui->unsavedPane->sizeHint().height()); } else { anim->setEndValue(0); } anim->setDuration(250); anim->setEasingCurve(QEasingCurve::OutCubic); connect(anim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { ui->unsavedPane->setFixedHeight(value.toInt()); }); connect(anim, &tVariantAnimation::finished, anim, &tVariantAnimation::deleteLater); anim->start(); } void NetworkConnectionEditor::on_saveButton_clicked() { //Save the new connection settings QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(NetworkManager::addConnection(d->connectionSettings->toMap())); connect(watcher, &QDBusPendingCallWatcher::finished, this, [ = ] { if (watcher->isError()) { tToast* toast = new tToast(); toast->setTitle(tr("Couldn't save settings")); toast->setText(watcher->error().message()); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); } else { QDBusObjectPath path = watcher->reply().arguments().first().value(); NetworkManager::Connection::Ptr connection(new NetworkManager::Connection(path.path())); emit accepted(connection); } watcher->deleteLater(); }); } void NetworkConnectionEditor::on_saveModifiedButton_clicked() { //Notify all panes about intent to save for (ConnectionEditorPane* pane : d->panes) { if (!pane->prepareSave()) { //Can't save this one; go there to let the user know ui->listWidget->setCurrentRow(ui->stackedWidget->indexOf(pane)); return; } } //Save the changes QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(d->connection->update(d->connectionSettings->toMap())); connect(watcher, &QDBusPendingCallWatcher::finished, this, [ = ] { if (watcher->isError()) { tToast* toast = new tToast(); toast->setTitle(tr("Couldn't save settings")); toast->setText(watcher->error().message()); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); } else { d->connectionSettings = d->connection->settings(); for (ConnectionEditorPane* pane : d->panes) { pane->reload(d->connectionSettings->setting(pane->type())); } d->haveUnsaved = false; updateUnsaved(); } watcher->deleteLater(); }); } void NetworkConnectionEditor::on_revertButton_clicked() { //Undo the changes d->connectionSettings->fromMap(d->oldSettings); for (ConnectionEditorPane* pane : d->panes) { pane->reload(d->connectionSettings->setting(pane->type())); } d->haveUnsaved = false; updateUnsaved(); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/networkconnectioneditor.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NETWORKCONNECTIONEDITOR_H #define NETWORKCONNECTIONEDITOR_H #include #include #include namespace Ui { class NetworkConnectionEditor; } struct NetworkConnectionEditorPrivate; class NetworkConnectionEditor : public QWidget { Q_OBJECT public: explicit NetworkConnectionEditor(NetworkManager::ConnectionSettings::Ptr connectionSettings, QWidget* parent = nullptr); explicit NetworkConnectionEditor(NetworkManager::Connection::Ptr connection, QWidget* parent = nullptr); ~NetworkConnectionEditor(); static int preferredPopoverWidth(); void setSaveButtonText(QString text); private slots: void on_titleLabel_backButtonClicked(); void on_connectionName_textChanged(const QString& arg1); void on_saveButton_clicked(); void on_saveModifiedButton_clicked(); void on_revertButton_clicked(); signals: void rejected(); void accepted(NetworkManager::Connection::Ptr connection); private: Ui::NetworkConnectionEditor* ui; NetworkConnectionEditorPrivate* d; void init(); void populate(); void updateUnsaved(); }; #endif // NETWORKCONNECTIONEDITOR_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/networkconnectioneditor.ui ================================================ NetworkConnectionEditor 0 0 632 400 Form 0 0 0 0 0 0 0 0 0 0 TextLabel true 0 0 0 0 0 75 true SETTINGS MODIFIED Save your settings once you're done so you don't lose them true 0 Qt::Horizontal 40 20 Revert .. Save .. 16777215 1 Qt::Horizontal 0 0 0 0 0 75 true DONE? Your settings look good. Qt::Horizontal 40 20 Save .. 16777215 1 Qt::Horizontal QFrame::NoFrame General 1 16777215 Qt::Vertical 0 0 0 0 0 General 9 9 9 9 6 Connection Name Qt::Vertical 20 337 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
listWidget currentRowChanged(int) stackedWidget setCurrentIndex(int) 225 183 486 200
================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/wificonnectioneditorpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wificonnectioneditorpane.h" #include "ui_wificonnectioneditorpane.h" #include #include #include struct WifiConnectionEditorPanePrivate { NetworkManager::WirelessSetting::Ptr setting; }; WifiConnectionEditorPane::WifiConnectionEditorPane(NetworkManager::Setting::Ptr setting, QWidget* parent) : ConnectionEditorPane(setting, parent), ui(new Ui::WifiConnectionEditorPane) { ui->setupUi(this); d = new WifiConnectionEditorPanePrivate(); this->reload(setting); } WifiConnectionEditorPane::~WifiConnectionEditorPane() { delete ui; delete d; } QString WifiConnectionEditorPane::displayName() { return tr("Wi-Fi"); } void WifiConnectionEditorPane::reload(NetworkManager::Setting::Ptr setting) { d->setting = setting.staticCast(); d->setting->setInitialized(true); ui->ssidLineEdit->setText(d->setting->ssid()); ui->modeBox->setCurrentIndex(d->setting->mode()); } NetworkManager::Setting::SettingType WifiConnectionEditorPane::type() { return NetworkManager::Setting::Wireless; } void WifiConnectionEditorPane::on_ssidLineEdit_textChanged(const QString& arg1) { d->setting->setSsid(arg1.toUtf8()); QString newId = arg1; int number = 0; bool loopAgain = true; auto name = [ & ] { if (number == 0) return arg1; return newId + " " + QString::number(number); }; NetworkManager::Connection::List connections = NetworkManager::listConnections(); while (loopAgain) { loopAgain = false; for (NetworkManager::Connection::Ptr connection : connections) { if (connection->settings()->id() == name()) { number++; loopAgain = true; } } } emit setConnectionName(name()); emit changed(); } void WifiConnectionEditorPane::on_modeBox_currentIndexChanged(int index) { d->setting->setMode(static_cast(index)); emit changed(); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/wificonnectioneditorpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIFICONNECTIONEDITORPANE_H #define WIFICONNECTIONEDITORPANE_H #include "connectioneditorpane.h" namespace Ui { class WifiConnectionEditorPane; } struct WifiConnectionEditorPanePrivate; class WifiConnectionEditorPane : public ConnectionEditorPane { Q_OBJECT public: explicit WifiConnectionEditorPane(NetworkManager::Setting::Ptr setting, QWidget* parent = nullptr); ~WifiConnectionEditorPane(); private: Ui::WifiConnectionEditorPane* ui; WifiConnectionEditorPanePrivate* d; // ConnectionEditorPane interface public: QString displayName(); void reload(NetworkManager::Setting::Ptr setting); NetworkManager::Setting::SettingType type(); private slots: void on_ssidLineEdit_textChanged(const QString& arg1); void on_modeBox_currentIndexChanged(int index); }; #endif // WIFICONNECTIONEDITORPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/connectionEditor/wificonnectioneditorpane.ui ================================================ WifiConnectionEditorPane 0 0 400 300 Form 0 0 0 0 0 Wi-Fi 9 9 9 9 6 Mode SSID Infrastructure Ad-Hoc Access Point Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/abstractdevicepane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "abstractdevicepane.h" AbstractDevicePane::AbstractDevicePane(QWidget* parent) : QWidget(parent) { } AbstractDevicePane::~AbstractDevicePane() { } ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/abstractdevicepane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ABSTRACTDEVICEPANE_H #define ABSTRACTDEVICEPANE_H #include #include class AbstractDevicePane : public QWidget { Q_OBJECT public: explicit AbstractDevicePane(QWidget* parent = nullptr); virtual ~AbstractDevicePane(); virtual QListWidgetItem* leftPaneItem() = 0; signals: }; #endif // ABSTRACTDEVICEPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/cellularpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "cellularpane.h" #include "ui_cellularpane.h" #include "../popovers/simsettingspopover.h" #include "../popovers/unlockmodempopover.h" #include "networkplugincommon.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct CellularPanePrivate { QListWidgetItem* item; NetworkManager::ModemDevice::Ptr device; ModemManager::ModemDevice::Ptr modem; ModemManager::Modem3gpp::Ptr modem3gpp; IconTextChunk* chunk; tSettings settings; NetworkManager::Device::State oldState; QAction* unlockSimAction; bool pinNotificationSent = false; }; CellularPane::CellularPane(QString uni, QWidget* parent) : AbstractDevicePane(parent), ui(new Ui::CellularPane) { ui->setupUi(this); d = new CellularPanePrivate(); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->actionsWidget->setFixedWidth(contentWidth); ui->statusWidget->setFixedWidth(contentWidth); ui->disconnectButton->setProperty("type", "destructive"); ui->errorFrame->setVisible(false); d->chunk = new IconTextChunk("network-cellular"); d->item = new QListWidgetItem(); d->device = NetworkManager::findNetworkInterface(uni).staticCast(); d->modem = ModemManager::findModemDevice(d->device->udi()); d->modem3gpp = ModemManager::Modem3gpp::Ptr(new ModemManager::Modem3gpp(d->device->udi())); d->unlockSimAction = new QAction(this); d->unlockSimAction->setVisible(false); d->unlockSimAction->setIcon(QIcon::fromTheme("sim-card")); connect(d->unlockSimAction, &QAction::triggered, this, &CellularPane::unlockDevice); QAction* enableDisableCellularAction = new QAction(this); enableDisableCellularAction->setIcon(QIcon::fromTheme("network-cellular")); connect(enableDisableCellularAction, &QAction::triggered, this, [=] { NetworkManager::setWwanEnabled(!NetworkManager::isWwanEnabled()); }); ActionQuickWidget* quickWidget = new ActionQuickWidget(d->chunk); quickWidget->addAction(d->unlockSimAction); quickWidget->addAction(enableDisableCellularAction); d->chunk->setQuickWidget(quickWidget); auto updateWwanEnabled = [=](bool enabled) { if (enabled) { enableDisableCellularAction->setText(tr("Disable Cellular")); } else { enableDisableCellularAction->setText(tr("Enable Cellular")); } }; connect(NetworkManager::notifier(), &NetworkManager::Notifier::wwanEnabledChanged, this, updateWwanEnabled); updateWwanEnabled(NetworkManager::isWwanEnabled()); d->item->setText(this->operatorName()); ui->titleLabel->setText(this->operatorName()); connect(d->device.data(), &NetworkManager::ModemDevice::stateChanged, this, &CellularPane::updateState); updateState(); connect(d->device.data(), &NetworkManager::ModemDevice::stateChanged, this, [=](NetworkManager::Device::State newState, NetworkManager::Device::State oldState, NetworkManager::Device::StateChangeReason reason) { if (d->settings.value("NetworkPlugin/notifications.activation").toBool()) { switch (newState) { case NetworkManager::Device::Unavailable: d->device->setAutoconnect(false); Q_FALLTHROUGH(); case NetworkManager::Device::Disconnected: if (oldState != NetworkManager::Device::Failed) StateManager::hudManager()->showHud({ {"icon", "network-cellular-disconnected"}, {"title", this->operatorName() }, {"text", tr("Disconnected") } }); break; case NetworkManager::Device::Activated: { d->device->setAutoconnect(true); QString title = tr("Cellular"); StateManager::hudManager()->showHud({ {"icon", "network-cellular-activated"}, {"title", this->operatorName() }, {"text", tr("Connected") } }); break; } case NetworkManager::Device::Failed: d->device->setAutoconnect(false); StateManager::hudManager()->showHud({ {"icon", "network-cellular-error"}, {"title", this->operatorName() }, {"text", tr("Failed") } }); break; default: break; } } }); connect(d->modem->modemInterface().data(), &ModemManager::Modem::signalQualityChanged, this, &CellularPane::updateState); connect(d->modem->modemInterface().data(), &ModemManager::Modem::currentModesChanged, this, &CellularPane::updateState); connect(d->modem->modemInterface().data(), &ModemManager::Modem::unlockRequiredChanged, this, &CellularPane::updateState); connect(d->modem3gpp.data(), &ModemManager::Modem3gpp::registrationStateChanged, this, &CellularPane::updateState); StateManager::barManager()->addChunk(d->chunk); } CellularPane::~CellularPane() { StateManager::barManager()->removeChunk(d->chunk); d->chunk->deleteLater(); delete d; delete ui; } void CellularPane::updateState() { if (!d->modem) return; if (!d->modem->modemInterface()) return; QIcon signalIcon = QIcon::fromTheme(NetworkPluginCommon::iconForSignalStrength(d->modem->modemInterface()->signalQuality().signal, NetworkPluginCommon::Cellular)); QIcon signalErrorIcon = QIcon::fromTheme(NetworkPluginCommon::iconForSignalStrength(d->modem->modemInterface()->signalQuality().signal, NetworkPluginCommon::CellularError)); ui->deviceIcon->setPixmap(QIcon::fromTheme("computer").pixmap(SC_DPI_T(QSize(96, 96), QSize))); ui->routerIcon->setPixmap(signalIcon.pixmap(SC_DPI_T(QSize(96, 96), QSize))); ui->routerName->setText(this->operatorName()); ui->unlockModemButton->setVisible(false); QStringList chunkParts; chunkParts.append(this->operatorName()); NetworkManager::DeviceStateReason stateReason = d->device->stateReason(); if (d->oldState != NetworkManager::Device::Failed) { // Only get rid of the error message here if the previous state was not failure. ui->errorFrame->setVisible(false); } switch (stateReason.state()) { case NetworkManager::Device::UnknownState: case NetworkManager::Device::Unmanaged: case NetworkManager::Device::Unavailable: { ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-cancel").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->leftStateLine->setEnabled(false); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(false); ui->connectButton->setVisible(false); d->device->setAutoconnect(false); if (d->modem->sim()->uni() == "/") { ui->errorFrame->setTitle(tr("No SIM Card")); ui->errorFrame->setText(tr("Insert a SIM card to connect to cellular services.")); chunkParts.clear(); chunkParts.append(tr("No SIM")); d->chunk->setIcon(QIcon::fromTheme("sim-card-none")); } else { ui->errorFrame->setTitle(tr("Unavailable")); QString reasonText; reasonText = tr("This network is unavailable because %2."); reasonText = reasonText.arg(NetworkPluginCommon::stateChangeReasonToString(stateReason.reason())); ui->errorFrame->setText(reasonText); d->chunk->setIcon(signalErrorIcon); } ui->errorFrame->setState(tStatusFrame::Warning); ui->errorFrame->setVisible(true); break; } case NetworkManager::Device::Disconnected: ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-cancel").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->leftStateLine->setEnabled(false); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(false); ui->connectButton->setVisible(true); d->chunk->setIcon(signalErrorIcon); break; case NetworkManager::Device::Failed: { ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-cancel").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->leftStateLine->setEnabled(false); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(false); ui->connectButton->setVisible(true); d->chunk->setIcon(signalErrorIcon); ui->errorFrame->setTitle(tr("Connection Failure")); QString reasonText = tr("Connecting to the network failed because %2."); reasonText = reasonText.arg(NetworkPluginCommon::stateChangeReasonToString(stateReason.reason())); ui->errorFrame->setText(reasonText); ui->errorFrame->setState(tStatusFrame::Error); ui->errorFrame->setVisible(true); break; } case NetworkManager::Device::Preparing: case NetworkManager::Device::ConfiguringHardware: case NetworkManager::Device::NeedAuth: case NetworkManager::Device::ConfiguringIp: case NetworkManager::Device::CheckingIp: case NetworkManager::Device::WaitingForSecondaries: case NetworkManager::Device::Deactivating: ui->stateConnecting->setVisible(true); ui->stateIcon->setVisible(false); ui->leftStateLine->setEnabled(true); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(true); ui->connectButton->setVisible(false); d->chunk->setIcon(signalIcon); break; case NetworkManager::Device::Activated: ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->leftStateLine->setEnabled(true); ui->rightStateLine->setEnabled(true); ui->disconnectButton->setVisible(true); ui->connectButton->setVisible(false); d->chunk->setIcon(signalIcon); ModemManager::Modem::AccessTechnologies accessTechnology = d->modem->modemInterface()->accessTechnologies(); #if MM_CHECK_VERSION(1, 14, 0) if (accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_5GNR) { chunkParts.append("5G"); } else #endif if (accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_LTE) { chunkParts.append("LTE"); } else if (accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS) { chunkParts.append("H+"); } else if (accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_HSDPA || accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_HSUPA || accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_HSPA) { chunkParts.append("H"); } else if (accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_UMTS || accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 || accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_EVDOA || accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_EVDOB) { chunkParts.append("3G"); } else if (accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_EDGE) { chunkParts.append("E"); } else if (accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_GPRS) { chunkParts.append("G"); } else if (accessTechnology & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT) { chunkParts.append("1X"); } MMModem3gppRegistrationState modem3gppRegistration = d->modem3gpp->registrationState(); if (modem3gppRegistration == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING || modem3gppRegistration == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY || modem3gppRegistration == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) { chunkParts.append("R"); } break; } MMModemLock unlockRequired = d->modem->modemInterface()->unlockRequired(); ModemManager::UnlockRetriesMap retries = d->modem->modemInterface()->unlockRetries(); switch (unlockRequired) { case MM_MODEM_LOCK_SIM_PIN: { ui->unlockModemButton->setText(tr("Enter SIM PIN")); ui->unlockModemButton->setVisible(true); chunkParts.append(tr("SIM PIN Required")); d->chunk->setIcon(QIcon::fromTheme("sim-card")); ui->connectButton->setVisible(false); ui->errorFrame->setTitle(tr("SIM PIN Required")); QString reasonText = tr("A SIM PIN is required to connect to the cellular network."); ui->errorFrame->setText(reasonText); ui->errorFrame->setState(tStatusFrame::Error); ui->errorFrame->setVisible(true); d->unlockSimAction->setText(tr("Enter SIM PIN")); d->unlockSimAction->setVisible(true); if (!d->pinNotificationSent) { tNotification* notification = new tNotification(); notification->setSummary(tr("SIM PIN Required")); notification->setText(reasonText); notification->insertAction(QStringLiteral("unlock"), tr("Enter SIM PIN")); connect(notification, &tNotification::actionClicked, this, [=](QString key) { if (key == QStringLiteral("unlock")) unlockDevice(); }); notification->post(); d->pinNotificationSent = true; } break; } case MM_MODEM_LOCK_SIM_PUK: { ui->unlockModemButton->setText(tr("Enter SIM PUK")); ui->unlockModemButton->setVisible(true); chunkParts.append(tr("SIM PUK Required")); d->chunk->setIcon(QIcon::fromTheme("sim-card")); ui->connectButton->setVisible(false); ui->errorFrame->setTitle(tr("SIM PUK Required")); QString reasonText = tr("A SIM PUK is required to connect to the cellular network."); ui->errorFrame->setText(reasonText); ui->errorFrame->setState(tStatusFrame::Error); ui->errorFrame->setVisible(true); d->unlockSimAction->setText(tr("Enter SIM PUK")); d->unlockSimAction->setVisible(true); if (!d->pinNotificationSent) { tNotification* notification = new tNotification(); notification->setSummary(tr("SIM PUK Required")); notification->setText(reasonText); notification->insertAction(QStringLiteral("unlock"), tr("Enter SIM PUK")); connect(notification, &tNotification::actionClicked, this, [=](QString key) { if (key == QStringLiteral("unlock")) unlockDevice(); }); notification->post(); d->pinNotificationSent = true; } break; } default: ui->unlockModemButton->setVisible(false); d->unlockSimAction->setVisible(false); d->pinNotificationSent = false; } d->oldState = stateReason.state(); d->chunk->setText(chunkParts.join(" · ")); } QString CellularPane::operatorName() { if (!d->modem) return tr("Cellular"); return NetworkPluginCommon::operatorNameForModem(d->modem); } void CellularPane::unlockDevice() { TransparentDialog* dialog = new TransparentDialog(); dialog->setWindowFlag(Qt::FramelessWindowHint); dialog->setWindowFlag(Qt::WindowStaysOnTopHint); tScrim::scrimForWidget(dialog)->setBlurEnabled(false); dialog->showFullScreen(); QTimer::singleShot(500, [=] { UnlockModemPopover* popoverContents = new UnlockModemPopover(d->modem); tPopover* popover = new tPopover(popoverContents); popover->setPopoverSide(tPopover::Bottom); popover->setPopoverWidth(SC_DPI(600)); connect(popoverContents, &UnlockModemPopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, [=] { popover->deleteLater(); dialog->deleteLater(); popoverContents->deleteLater(); }); popover->show(dialog); }); } QListWidgetItem* CellularPane::leftPaneItem() { return d->item; } void CellularPane::on_disconnectButton_clicked() { d->device->disconnectInterface(); } void CellularPane::on_simSettingsButton_clicked() { SimSettingsPopover* simSettings = new SimSettingsPopover(d->modem); tPopover* popover = new tPopover(simSettings); popover->setPopoverWidth(SC_DPI(600)); connect(simSettings, &SimSettingsPopover::dismissed, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, simSettings, &SimSettingsPopover::deleteLater); popover->show(this->window()); } void CellularPane::on_unlockModemButton_clicked() { unlockDevice(); } void CellularPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void CellularPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/cellularpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CELLULARPANE_H #define CELLULARPANE_H #include #include "abstractdevicepane.h" namespace Ui { class CellularPane; } struct CellularPanePrivate; class CellularPane : public AbstractDevicePane { Q_OBJECT public: explicit CellularPane(QString uni, QWidget* parent = nullptr); ~CellularPane(); void updateState(); QString operatorName(); private: Ui::CellularPane* ui; CellularPanePrivate* d; void unlockDevice(); // AbstractDevicePane interface public: QListWidgetItem* leftPaneItem(); private slots: void on_disconnectButton_clicked(); void on_simSettingsButton_clicked(); void on_unlockModemButton_clicked(); void on_titleLabel_backButtonClicked(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // CELLULARPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/cellularpane.ui ================================================ CellularPane 0 0 806 594 Form 0 0 0 0 0 Cellular QFrame::NoFrame true 0 0 806 577 0 0 0 0 0 75 true STATUS TextLabel This Device Qt::AlignCenter 0 0 16777215 1 Qt::Horizontal TextLabel 0 0 16777215 1 Qt::Horizontal TextLabel TextLabel Qt::AlignCenter QFrame::StyledPanel QFrame::Raised 16777215 1 Qt::Horizontal 0 0 0 0 9 9 9 6 75 true ACTIONS Enter SIM PIN Connect Disconnect Modem Settings Qt::Vertical 20 138 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tCircularSpinner QWidget
tcircularspinner.h
1
tStatusFrame QFrame
tstatusframe.h
1
================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/devicepane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "devicepane.h" #include "ui_devicepane.h" #include #include #include #include struct DevicePanePrivate { QListWidgetItem* item; NetworkManager::Device::Ptr device; }; DevicePane::DevicePane(QString uni, QWidget* parent) : AbstractDevicePane(parent), ui(new Ui::DevicePane) { ui->setupUi(this); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->actionsWidget->setFixedWidth(contentWidth); ui->statusWidget->setFixedWidth(contentWidth); ui->disconnectButton->setProperty("type", "destructive"); d = new DevicePanePrivate(); d->item = new QListWidgetItem(); d->device = NetworkManager::findNetworkInterface(uni); d->item->setText(d->device->interfaceName()); ui->titleLabel->setText(d->device->interfaceName()); connect(d->device.data(), &NetworkManager::Device::interfaceNameChanged, this, [ = ] { d->item->setText(d->device->interfaceName()); ui->titleLabel->setText(d->device->interfaceName()); }); } DevicePane::~DevicePane() { delete d->item; delete d; delete ui; } QListWidgetItem* DevicePane::leftPaneItem() { return d->item; } void DevicePane::on_disconnectButton_clicked() { d->device->disconnectInterface(); } void DevicePane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void DevicePane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/devicepane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef DEVICEPANE_H #define DEVICEPANE_H #include "abstractdevicepane.h" namespace Ui { class DevicePane; } struct DevicePanePrivate; class DevicePane : public AbstractDevicePane { Q_OBJECT public: explicit DevicePane(QString uni, QWidget* parent = nullptr); ~DevicePane(); private: Ui::DevicePane* ui; DevicePanePrivate* d; // AbstractDevicePane interface public: QListWidgetItem* leftPaneItem(); private slots: void on_disconnectButton_clicked(); void on_titleLabel_backButtonClicked(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // DEVICEPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/devicepane.ui ================================================ DevicePane 0 0 400 300 Form 0 0 0 0 0 TextLabel QFrame::NoFrame true 0 0 400 283 0 0 0 0 0 true STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. true 16777215 1 Qt::Horizontal 0 0 0 9 9 9 true ACTIONS Disconnect .. Qt::Vertical 20 138 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/wifidevicepane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wifidevicepane.h" #include "ui_wifidevicepane.h" #include "../popovers/tetheringsettingspopover.h" #include "../popovers/wirelessnetworkselectionpopover.h" #include "networkplugincommon.h" #include "switchmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct WifiDevicePanePrivate { QListWidgetItem* item; NetworkManager::WirelessDevice::Ptr device; IconTextChunk* tetheringChunk; SwitchManager* switchManager = nullptr; tSettings settings; }; WifiDevicePane::WifiDevicePane(QString uni, QWidget* parent) : AbstractDevicePane(parent), ui(new Ui::WifiDevicePane) { ui->setupUi(this); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->actionsWidget->setFixedWidth(contentWidth); ui->statusWidget->setFixedWidth(contentWidth); ui->tetheringWidget->setFixedWidth(contentWidth); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->wifiOffIcon->setPixmap(QIcon::fromTheme("network-wireless-disconnected").pixmap(SC_DPI_T(QSize(128, 128), QSize))); ui->wifiBlockedIcon->setPixmap(QIcon::fromTheme("network-wireless-disconnected").pixmap(SC_DPI_T(QSize(128, 128), QSize))); ui->wifiFlightIcon->setPixmap(QIcon::fromTheme("flight-mode").pixmap(SC_DPI_T(QSize(128, 128), QSize))); ui->disconnectButton->setProperty("type", "destructive"); ui->errorFrame->setVisible(false); ui->tetheringKey->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); d = new WifiDevicePanePrivate(); d->item = new QListWidgetItem(); d->device = NetworkManager::findNetworkInterface(uni).staticCast(); d->tetheringChunk = new IconTextChunk("network-tethering"); d->tetheringChunk->setIcon(QIcon::fromTheme("network-wireless-tethered")); d->tetheringChunk->setText(tr("Tethering")); ActionQuickWidget* tetheringQuickWidget = new ActionQuickWidget(d->tetheringChunk); tetheringQuickWidget->addAction(QIcon::fromTheme("network-wireless-tethered"), tr("Disable Tethering"), [=] { ui->tetheringSwitch->setChecked(false); }); d->tetheringChunk->setQuickWidget(tetheringQuickWidget); connect(d->device.data(), &NetworkManager::WirelessDevice::activeConnectionChanged, this, &WifiDevicePane::updateNetworkName); connect(d->device.data(), &NetworkManager::WirelessDevice::activeAccessPointChanged, this, &WifiDevicePane::updateNetworkName); updateNetworkName(); connect(d->device.data(), &NetworkManager::WirelessDevice::stateChanged, this, &WifiDevicePane::updateState); connect(d->device.data(), &NetworkManager::WirelessDevice::activeAccessPointChanged, this, &WifiDevicePane::updateState); connect(d->device.data(), &NetworkManager::WirelessDevice::wirelessCapabilitiesChanged, this, &WifiDevicePane::updateState); updateState(); connect(&d->settings, &tSettings::settingChanged, this, [=](QString key, QVariant value) { if (key.startsWith("NetworkPlugin/tethering")) { updateState(); } }); updateState(); connect(d->device.data(), &NetworkManager::WirelessDevice::stateChanged, this, [=](NetworkManager::Device::State newState, NetworkManager::Device::State oldState, NetworkManager::Device::StateChangeReason reason) { if (d->settings.value("NetworkPlugin/notifications.activation").toBool()) { switch (newState) { case NetworkManager::Device::Disconnected: if (oldState != NetworkManager::Device::Failed) StateManager::hudManager()->showHud({ {"icon", "network-wireless-disconnected"}, {"title", tr("Wi-Fi") }, {"text", tr("Disconnected") } }); break; case NetworkManager::Device::Activated: { QString title; QString text; QString connUuid = d->settings.value("NetworkPlugin/tethering.uuid").toString(); if (d->device->activeConnection()->uuid() == connUuid) { StateManager::hudManager()->showHud({ {"icon", "network-wireless-tethered"}, {"title", tr("Tethering") }, {"text", tr("Active") } }); } else if (d->device->activeAccessPoint()) { StateManager::hudManager()->showHud({ {"icon", "network-wireless-connected-100" }, {"title", d->device->activeAccessPoint()->ssid()}, {"text", tr("Connected") } }); } else { StateManager::hudManager()->showHud({ {"icon", "network-wireless-connected-100"}, {"title", tr("Wi-Fi") }, {"text", tr("Connected") } }); } break; } case NetworkManager::Device::Failed: StateManager::hudManager()->showHud({ {"icon", "network-wireless-disconnected"}, {"title", tr("Wi-Fi") }, {"text", tr("Failed") } }); break; default: break; } } if (newState == NetworkManager::Device::Failed) { d->device->setAutoconnect(false); ui->errorFrame->setTitle(tr("Connection Failure")); QString reasonText = tr("Connecting to %1 failed because %2."); if (d->device->activeAccessPoint()) { reasonText = reasonText.arg(d->device->activeAccessPoint()->ssid()); } else { reasonText = reasonText.arg(tr("the network")); } reasonText = reasonText.arg(NetworkPluginCommon::stateChangeReasonToString(reason)); ui->errorFrame->setText(reasonText); ui->errorFrame->setState(tStatusFrame::Error); ui->errorFrame->setVisible(true); } else if (oldState != NetworkManager::Device::Failed) { ui->errorFrame->setVisible(false); } }); connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessEnabledChanged, this, &WifiDevicePane::updateNetworkCardState); connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessHardwareEnabledChanged, this, &WifiDevicePane::updateNetworkCardState); updateNetworkCardState(); } WifiDevicePane::~WifiDevicePane() { delete d->item; d->tetheringChunk->deleteLater(); delete d; delete ui; } void WifiDevicePane::setSwitchManager(SwitchManager* switchManager) { d->switchManager = switchManager; } void WifiDevicePane::updateNetworkName() { if (d->device->isActive() && d->device->activeAccessPoint()) { d->item->setText(d->device->activeAccessPoint()->ssid()); ui->titleLabel->setText(d->device->activeAccessPoint()->ssid()); } else { d->item->setText(tr("Wi-Fi")); ui->titleLabel->setText(tr("Wi-Fi")); } } void WifiDevicePane::updateState() { ui->deviceIcon->setPixmap(QIcon::fromTheme("computer").pixmap(SC_DPI_T(QSize(96, 96), QSize))); switch (d->device->mode()) { case NetworkManager::WirelessDevice::Adhoc: case NetworkManager::WirelessDevice::ApMode: ui->routerIcon->setPixmap(QIcon::fromTheme("computer").pixmap(SC_DPI_T(QSize(96, 96), QSize))); break; case NetworkManager::WirelessDevice::Unknown: case NetworkManager::WirelessDevice::Infra: ui->routerIcon->setPixmap(QIcon::fromTheme("network-wireless-connected-100").pixmap(SC_DPI_T(QSize(96, 96), QSize))); break; } bool setRouterName = false; switch (d->device->state()) { case NetworkManager::Device::UnknownState: case NetworkManager::Device::Unmanaged: case NetworkManager::Device::Unavailable: case NetworkManager::Device::Disconnected: ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-cancel").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->routerName->setText(tr("Disconnected")); ui->leftStateLine->setEnabled(false); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(false); break; case NetworkManager::Device::Failed: ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-cancel").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->routerName->setText(tr("Failed")); ui->leftStateLine->setEnabled(false); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(false); break; case NetworkManager::Device::Preparing: case NetworkManager::Device::ConfiguringHardware: case NetworkManager::Device::NeedAuth: case NetworkManager::Device::ConfiguringIp: case NetworkManager::Device::CheckingIp: case NetworkManager::Device::WaitingForSecondaries: case NetworkManager::Device::Deactivating: ui->stateConnecting->setVisible(true); ui->stateIcon->setVisible(false); setRouterName = true; ui->leftStateLine->setEnabled(true); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(true); break; case NetworkManager::Device::Activated: ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(SC_DPI_T(QSize(32, 32), QSize))); setRouterName = true; ui->leftStateLine->setEnabled(true); ui->rightStateLine->setEnabled(true); ui->disconnectButton->setVisible(true); break; } if (setRouterName) { QString routerName; switch (d->device->mode()) { case NetworkManager::WirelessDevice::ApMode: routerName = tr("0 Devices"); break; case NetworkManager::WirelessDevice::Infra: if (d->device->activeAccessPoint()) { routerName = d->device->activeAccessPoint()->ssid(); break; } Q_FALLTHROUGH(); default: routerName = tr("Unknown"); } ui->routerName->setText(routerName); } if (d->device->wirelessCapabilities() & NetworkManager::WirelessDevice::ApCap || d->device->wirelessCapabilities() & NetworkManager::WirelessDevice::AdhocCap) { ui->tetheringWidget->setVisible(true); ui->tetheringLine->setVisible(true); QString ssid = d->settings.value("NetworkPlugin/tethering.ssid").toString(); ssid = ssid.replace("$hostname", QHostInfo::localHostName()); ui->tetheringSsid->setText(ssid); QString key = d->settings.value("NetworkPlugin/tethering.key").toString(); if (key == ".") { QString validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()"; QRandomGenerator* random = QRandomGenerator::global(); key.clear(); while (key.length() < 10) { key.append(validChars.at(random->bounded(validChars.length()))); } d->settings.setValue("NetworkPlugin/tethering.key", key); } ui->tetheringKey->setText(key); bool tetheringOn = false; QSignalBlocker blocker(ui->tetheringSwitch); QString connUuid = d->settings.value("NetworkPlugin/tethering.uuid").toString(); for (NetworkManager::ActiveConnection::Ptr connection : NetworkManager::activeConnections()) { if (connection->connection()->uuid() == connUuid) { tetheringOn = true; } } QString qrString = QStringLiteral("WIFI:T:WPA;S:%1;P:%2;;").arg(ssid, key.replace(":", "\\:")); QRcode* qrc = QRcode_encodeString(qrString.toUtf8().data(), 0, QR_ECLEVEL_M, QR_MODE_8, 1); QPixmap qrcode(ui->tetheringWidget->width() / 2, ui->tetheringWidget->width() / 2); qrcode.fill(Qt::white); int margin = ui->tetheringWidget->width() / 20; QPainter qrcodePainter(&qrcode); qrcodePainter.setWindow(QRect(0, 0, qrc->width, qrc->width)); qrcodePainter.setViewport(QRect(margin, margin, qrcode.width() - margin * 2, qrcode.width() - margin * 2)); for (int y = 0; y < qrc->width; y++) { for (int x = 0; x < qrc->width; x++) { if (qrc->data[qrc->width * y + x] & 1) qrcodePainter.fillRect(x, y, 1, 1, Qt::black); } } qrcodePainter.end(); ui->tetheringQrCodeLabel->setPixmap(qrcode); QRcode_free(qrc); ui->tetheringSwitch->setChecked(tetheringOn); ui->tetheringSettings->setVisible(!tetheringOn); ui->actionsWidget->setVisible(!tetheringOn); ui->actionsLine->setVisible(!tetheringOn); ui->tetheringQrCodeLabel->setVisible(tetheringOn); if (tetheringOn && !StateManager::barManager()->isChunkRegistered(d->tetheringChunk)) { StateManager::barManager()->addChunk(d->tetheringChunk); } else if (!tetheringOn && StateManager::barManager()->isChunkRegistered(d->tetheringChunk)) { StateManager::barManager()->removeChunk(d->tetheringChunk); } } else { ui->tetheringWidget->setVisible(false); ui->tetheringLine->setVisible(false); ui->actionsWidget->setVisible(true); ui->actionsLine->setVisible(true); if (StateManager::barManager()->isChunkRegistered(d->tetheringChunk)) d->tetheringChunk->setVisible(false); } } void WifiDevicePane::updateNetworkCardState() { if (!NetworkManager::isWirelessHardwareEnabled()) { ui->stackedWidget->setCurrentWidget(ui->wifiBlockedPage); } else if (!NetworkManager::isWirelessEnabled()) { if (d->switchManager && d->switchManager->isFlightModeEnabled()) { ui->stackedWidget->setCurrentWidget(ui->wifiFlightPage); } else { ui->stackedWidget->setCurrentWidget(ui->wifiOffPage); } } else { ui->stackedWidget->setCurrentWidget(ui->mainPage); } } QListWidgetItem* WifiDevicePane::leftPaneItem() { return d->item; } void WifiDevicePane::on_disconnectButton_clicked() { d->device->disconnectInterface(); } void WifiDevicePane::on_selectNetworkButton_clicked() { WirelessNetworkSelectionPopover* selection = new WirelessNetworkSelectionPopover(d->device->uni()); tPopover* popover = new tPopover(selection); popover->setPopoverWidth(SC_DPI(600)); connect(selection, &WirelessNetworkSelectionPopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, selection, &WirelessNetworkSelectionPopover::deleteLater); popover->show(this->window()); } void WifiDevicePane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void WifiDevicePane::on_tetheringSwitch_toggled(bool checked) { if (checked) { NetworkManager::ConnectionSettings::Ptr settings(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wireless)); settings->setId("Tethering"); settings->setAutoconnect(false); settings->setInterfaceName(d->device->interfaceName()); NetworkManager::WirelessSetting::Ptr wirelessSettings = settings->setting(NetworkManager::Setting::Wireless).staticCast(); NetworkManager::WirelessSecuritySetting::Ptr wirelessSecuritySettings = settings->setting(NetworkManager::Setting::WirelessSecurity).staticCast(); NetworkManager::Ipv4Setting::Ptr ipv4 = settings->setting(NetworkManager::Setting::Ipv4).staticCast(); NetworkManager::Ipv6Setting::Ptr ipv6 = settings->setting(NetworkManager::Setting::Ipv6).staticCast(); QString ssid = d->settings.value("NetworkPlugin/tethering.ssid").toString(); ssid = ssid.replace("$hostname", QHostInfo::localHostName()); wirelessSettings->setSsid(ssid.toUtf8()); wirelessSettings->setSecurity("802-11-wireless-security"); if (d->device->wirelessCapabilities() & NetworkManager::WirelessDevice::ApCap) { wirelessSettings->setMode(NetworkManager::WirelessSetting::Ap); } else { wirelessSettings->setMode(NetworkManager::WirelessSetting::Adhoc); } wirelessSettings->setInitialized(true); wirelessSecuritySettings->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); wirelessSecuritySettings->setGroup({NetworkManager::WirelessSecuritySetting::Ccmp}); wirelessSecuritySettings->setPairwise({NetworkManager::WirelessSecuritySetting::Ccmp}); wirelessSecuritySettings->setProto({NetworkManager::WirelessSecuritySetting::Rsn}); wirelessSecuritySettings->setPsk(d->settings.value("NetworkPlugin/tethering.key").toString()); wirelessSecuritySettings->setInitialized(true); ipv4->setMethod(NetworkManager::Ipv4Setting::Shared); ipv4->setInitialized(true); ipv6->setMethod(NetworkManager::Ipv6Setting::Ignored); ipv6->setInitialized(true); QString connUuid = d->settings.value("NetworkPlugin/tethering.uuid").toString(); NetworkManager::Connection::Ptr connection; if (connUuid == ".") { connUuid = NetworkManager::ConnectionSettings::createNewUuid(); d->settings.setValue("NetworkPlugin/tethering.uuid", connUuid); } else { for (NetworkManager::Connection::Ptr checkConnection : NetworkManager::listConnections()) { if (checkConnection->uuid() == connUuid) connection = checkConnection; } } settings->setUuid(connUuid); QDBusPendingCallWatcher* watcher; if (!connection) { watcher = new QDBusPendingCallWatcher(NetworkManager::addConnectionUnsaved(settings->toMap())); } else { watcher = new QDBusPendingCallWatcher(connection->updateUnsaved(settings->toMap())); } connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { tToast* toast = new tToast(); toast->setTitle(tr("Couldn't configure tethering")); toast->setText(watcher->error().message()); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); updateState(); } else { QString connectionPath; if (connection) { connectionPath = connection->path(); } else { connectionPath = watcher->reply().arguments().first().value().path(); } NetworkManager::activateConnection(connectionPath, d->device->uni(), ""); } watcher->deleteLater(); }); } else { QString connUuid = d->settings.value("NetworkPlugin/tethering.uuid").toString(); for (NetworkManager::ActiveConnection::Ptr connection : NetworkManager::activeConnections()) { if (connection->connection()->uuid() == connUuid) { QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(connection->connection()->remove()); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { tToast* toast = new tToast(); toast->setTitle(tr("Couldn't switch off tethering")); toast->setText(watcher->error().message()); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); } updateState(); watcher->deleteLater(); }); } } } } void WifiDevicePane::on_turnWifiOnButton_clicked() { NetworkManager::setWirelessEnabled(true); } void WifiDevicePane::on_turnWifiOnButton_2_clicked() { NetworkManager::setWirelessEnabled(true); } void WifiDevicePane::on_tetheringSettings_clicked() { TetheringSettingsPopover* tetheringSettings = new TetheringSettingsPopover(); tPopover* popover = new tPopover(tetheringSettings); popover->setPopoverWidth(SC_DPI(600)); connect(tetheringSettings, &TetheringSettingsPopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, tetheringSettings, &TetheringSettingsPopover::deleteLater); popover->show(this->window()); } void WifiDevicePane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/wifidevicepane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIFIDEVICEPANE_H #define WIFIDEVICEPANE_H #include "abstractdevicepane.h" namespace Ui { class WifiDevicePane; } class SwitchManager; struct WifiDevicePanePrivate; class WifiDevicePane : public AbstractDevicePane { Q_OBJECT public: explicit WifiDevicePane(QString uni, QWidget* parent = nullptr); ~WifiDevicePane(); void setSwitchManager(SwitchManager* switchManager); private: Ui::WifiDevicePane* ui; WifiDevicePanePrivate* d; void updateNetworkName(); void updateState(); void updateNetworkCardState(); // AbstractDevicePane interface public: QListWidgetItem* leftPaneItem(); private slots: void on_disconnectButton_clicked(); void on_selectNetworkButton_clicked(); void on_titleLabel_backButtonClicked(); void on_tetheringSwitch_toggled(bool checked); void on_turnWifiOnButton_clicked(); void on_turnWifiOnButton_2_clicked(); void on_tetheringSettings_clicked(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // WIFIDEVICEPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/wifidevicepane.ui ================================================ WifiDevicePane 0 0 730 597 Form 0 0 0 0 0 TextLabel 0 0 0 0 0 0 QFrame::NoFrame true 0 0 730 580 0 0 0 0 0 75 true STATUS TextLabel This Device Qt::AlignCenter 0 0 16777215 1 Qt::Horizontal TextLabel 0 0 16777215 1 Qt::Horizontal TextLabel TextLabel Qt::AlignCenter QFrame::StyledPanel QFrame::Raised 16777215 1 Qt::Horizontal 0 0 0 0 9 9 9 6 75 true ACTIONS Select Network Disconnect 16777215 1 Qt::Horizontal 0 0 0 0 0 9 9 9 6 6 75 true TETHERING Network Key 0 0 TextLabel Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Qt::MarkdownText true 0 0 Enable Tethering TetheringSwitch SSID TextLabel Qt::AlignCenter Set Tethering Settings Qt::Vertical 20 138 Qt::Vertical 20 217 20 Wi-Fi is off Qt::AlignCenter false TextLabel Qt::AlignCenter Switch Wi-Fi on to connect to a wireless network Qt::AlignCenter Switch Wi-Fi On .. Qt::Vertical 20 217 Qt::Vertical 20 233 20 Wi-Fi is disabled Qt::AlignCenter false TextLabel Qt::AlignCenter Use the Wi-Fi switch to enable Wi-Fi and connect to a network Qt::AlignCenter Qt::Vertical 20 232 Qt::Vertical 20 217 20 You're in flight mode Qt::AlignCenter false TextLabel Qt::AlignCenter Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Qt::AlignCenter Switch Wi-Fi On .. Qt::Vertical 20 217 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tSwitch QPushButton
tswitch.h
tCircularSpinner QWidget
tcircularspinner.h
1
tStatusFrame QFrame
tstatusframe.h
1
================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/wireddevicepane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wireddevicepane.h" #include "ui_wireddevicepane.h" #include #include "../popovers/connectionselectionpopover.h" #include "networkplugincommon.h" #include #include #include #include #include #include #include #include struct WiredDevicePanePrivate { QListWidgetItem* item; NetworkManager::WiredDevice::Ptr device; tSettings settings; NetworkManager::Device::State oldState; }; WiredDevicePane::WiredDevicePane(QString uni, QWidget* parent) : AbstractDevicePane(parent), ui(new Ui::WiredDevicePane) { ui->setupUi(this); d = new WiredDevicePanePrivate(); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->actionsWidget->setFixedWidth(contentWidth); ui->statusWidget->setFixedWidth(contentWidth); ui->disconnectButton->setProperty("type", "destructive"); ui->errorFrame->setVisible(false); d->item = new QListWidgetItem(); d->item->setText(tr("Wired")); d->device = NetworkManager::findNetworkInterface(uni).staticCast(); // connect(d->device.data(), &NetworkManager::WirelessDevice::activeConnectionChanged, this, &WifiDevicePane::updateNetworkName); // connect(d->device.data(), &NetworkManager::WirelessDevice::activeAccessPointChanged, this, &WifiDevicePane::updateNetworkName); // updateNetworkName(); connect(d->device.data(), &NetworkManager::WiredDevice::stateChanged, this, &WiredDevicePane::updateState); updateState(); connect(d->device.data(), &NetworkManager::WiredDevice::stateChanged, this, [=](NetworkManager::Device::State newState, NetworkManager::Device::State oldState, NetworkManager::Device::StateChangeReason reason) { if (d->settings.value("NetworkPlugin/notifications.activation").toBool()) { switch (newState) { case NetworkManager::Device::Unavailable: d->device->setAutoconnect(false); Q_FALLTHROUGH(); case NetworkManager::Device::Disconnected: if (oldState != NetworkManager::Device::Failed) StateManager::hudManager()->showHud({ {"icon", "network-wired-unavailable"}, {"title", tr("Wired") }, {"text", tr("Disconnected") } }); break; case NetworkManager::Device::Activated: { d->device->setAutoconnect(true); QString title = tr("Wired"); StateManager::hudManager()->showHud({ {"icon", "network-wired-activated"}, {"title", title }, {"text", tr("Connected") } }); break; } case NetworkManager::Device::Failed: d->device->setAutoconnect(false); StateManager::hudManager()->showHud({ {"icon", "network-wired-error"}, {"title", tr("Wired") }, {"text", tr("Failed") } }); break; default: break; } } }); } WiredDevicePane::~WiredDevicePane() { delete d; delete ui; } void WiredDevicePane::updateState() { ui->deviceIcon->setPixmap(QIcon::fromTheme("computer").pixmap(SC_DPI_T(QSize(96, 96), QSize))); ui->routerIcon->setPixmap(QIcon::fromTheme("network-modem").pixmap(SC_DPI_T(QSize(96, 96), QSize))); ui->routerName->setText(tr("Router")); NetworkManager::DeviceStateReason stateReason = d->device->stateReason(); if (d->oldState != NetworkManager::Device::Failed) { // Only get rid of the error message here if the previous state was not failure. ui->errorFrame->setVisible(false); } switch (stateReason.state()) { case NetworkManager::Device::UnknownState: case NetworkManager::Device::Unmanaged: case NetworkManager::Device::Unavailable: { ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-cancel").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->leftStateLine->setEnabled(false); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(false); ui->connectButton->setVisible(false); d->device->setAutoconnect(false); ui->errorFrame->setTitle(tr("Unavailable")); QString reasonText; if (stateReason.reason() == NetworkManager::Device::CarrierReason) { reasonText = tr("Connect an Ethernet cable."); } else { reasonText = tr("This network is unavailable because %2."); reasonText = reasonText.arg(NetworkPluginCommon::stateChangeReasonToString(stateReason.reason())); } ui->errorFrame->setText(reasonText); ui->errorFrame->setState(tStatusFrame::Warning); ui->errorFrame->setVisible(true); break; } case NetworkManager::Device::Disconnected: ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-cancel").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->leftStateLine->setEnabled(false); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(false); ui->connectButton->setVisible(true); break; case NetworkManager::Device::Failed: { ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-cancel").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->leftStateLine->setEnabled(false); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(false); ui->connectButton->setVisible(true); ui->errorFrame->setTitle(tr("Connection Failure")); QString reasonText = tr("Connecting to the network failed because %2."); reasonText = reasonText.arg(NetworkPluginCommon::stateChangeReasonToString(stateReason.reason())); ui->errorFrame->setText(reasonText); ui->errorFrame->setState(tStatusFrame::Error); ui->errorFrame->setVisible(true); break; } case NetworkManager::Device::Preparing: case NetworkManager::Device::ConfiguringHardware: case NetworkManager::Device::NeedAuth: case NetworkManager::Device::ConfiguringIp: case NetworkManager::Device::CheckingIp: case NetworkManager::Device::WaitingForSecondaries: case NetworkManager::Device::Deactivating: ui->stateConnecting->setVisible(true); ui->stateIcon->setVisible(false); ui->leftStateLine->setEnabled(true); ui->rightStateLine->setEnabled(false); ui->disconnectButton->setVisible(true); ui->connectButton->setVisible(false); break; case NetworkManager::Device::Activated: ui->stateConnecting->setVisible(false); ui->stateIcon->setVisible(true); ui->stateIcon->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(SC_DPI_T(QSize(32, 32), QSize))); ui->leftStateLine->setEnabled(true); ui->rightStateLine->setEnabled(true); ui->disconnectButton->setVisible(true); ui->connectButton->setVisible(false); break; } d->oldState = stateReason.state(); } QListWidgetItem* WiredDevicePane::leftPaneItem() { return d->item; } void WiredDevicePane::on_disconnectButton_clicked() { d->device->disconnectInterface(); } void WiredDevicePane::on_connectButton_clicked() { NetworkManager::Connection::List connections = NetworkManager::listConnections(); QtConcurrent::blockingFilter(connections, [=](const NetworkManager::Connection::Ptr& connection) { NetworkManager::ConnectionSettings::Ptr settings = connection->settings(); if (settings->interfaceName() != "" && d->device->interfaceName() != settings->interfaceName()) return false; // This connection is not applicable to this device return QList({NetworkManager::ConnectionSettings::Wired}).contains(connection->settings()->connectionType()); }); if (connections.count() == 0) { // Create a new automatic connection NetworkManager::ConnectionSettings settings(NetworkManager::ConnectionSettings::Wired); settings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); settings.setInterfaceName(d->device->interfaceName()); NetworkManager::addAndActivateConnection(settings.toMap(), d->device->uni(), ""); } else if (connections.count() == 1) { // Use this connection NetworkManager::activateConnection(connections.first()->path(), d->device->uni(), ""); } else { // Ask the user for the connection to use ConnectionSelectionPopover* selection = new ConnectionSelectionPopover(connections); tPopover* popover = new tPopover(selection); popover->setPopoverWidth(SC_DPI(600)); connect(selection, &ConnectionSelectionPopover::reject, popover, &tPopover::dismiss); connect(selection, &ConnectionSelectionPopover::accept, this, [=](NetworkManager::Connection::Ptr connection) { NetworkManager::activateConnection(connection->path(), d->device->uni(), ""); popover->dismiss(); }); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, selection, &ConnectionSelectionPopover::deleteLater); popover->show(this->window()); } } void WiredDevicePane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void WiredDevicePane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/wireddevicepane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIREDDEVICEPANE_H #define WIREDDEVICEPANE_H #include "abstractdevicepane.h" namespace Ui { class WiredDevicePane; } struct WiredDevicePanePrivate; class WiredDevicePane : public AbstractDevicePane { Q_OBJECT public: explicit WiredDevicePane(QString uni, QWidget* parent = nullptr); ~WiredDevicePane(); private: Ui::WiredDevicePane* ui; WiredDevicePanePrivate* d; void updateState(); // AbstractDevicePane interface public: QListWidgetItem* leftPaneItem(); private slots: void on_disconnectButton_clicked(); void on_connectButton_clicked(); void on_titleLabel_backButtonClicked(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // WIREDDEVICEPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/devicePanes/wireddevicepane.ui ================================================ WiredDevicePane 0 0 400 300 Form 0 0 0 0 0 Wired QFrame::NoFrame true 0 0 400 283 0 0 0 0 0 75 true STATUS TextLabel This Device Qt::AlignCenter 0 0 16777215 1 Qt::Horizontal TextLabel 0 0 16777215 1 Qt::Horizontal TextLabel TextLabel Qt::AlignCenter QFrame::StyledPanel QFrame::Raised 16777215 1 Qt::Horizontal 0 0 0 0 9 9 9 6 75 true ACTIONS Connect Disconnect Qt::Vertical 20 138 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tCircularSpinner QWidget
tcircularspinner.h
1
tStatusFrame QFrame
tstatusframe.h
1
================================================ FILE: plugins/NetworkPlugin/statusCenter/eap/securityeap.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "securityeap.h" SecurityEap::SecurityEap(QWidget *parent) : QWidget(parent) { } ================================================ FILE: plugins/NetworkPlugin/statusCenter/eap/securityeap.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SECURITYEAP_H #define SECURITYEAP_H #include #include class SecurityEap : public QWidget { Q_OBJECT public: explicit SecurityEap(QWidget* parent = nullptr); virtual void populateSetting(NetworkManager::Security8021xSetting::Ptr setting) = 0; signals: void back(); void done(); }; #endif // SECURITYEAP_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/eap/securityeappeap.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "securityeappeap.h" #include "ui_securityeappeap.h" #include #include #include struct SecurityEapPeapPrivate { QByteArray caCert; }; SecurityEapPeap::SecurityEapPeap(QWidget* parent) : SecurityEap(parent), ui(new Ui::SecurityEapPeap) { ui->setupUi(this); d = new SecurityEapPeapPrivate(); ui->titleLabel->setBackButtonShown(true); } SecurityEapPeap::~SecurityEapPeap() { delete ui; delete d; } void SecurityEapPeap::on_titleLabel_backButtonClicked() { emit back(); } void SecurityEapPeap::on_connectButton_clicked() { if (ui->username->text().isEmpty()) { tErrorFlash::flashError(ui->username); return; } if (ui->password->text().isEmpty()) { tErrorFlash::flashError(ui->password); return; } if (!ui->caCertificate->text().isEmpty()) { QFile file(ui->caCertificate->text()); if (!file.open(QFile::ReadOnly)) { tErrorFlash::flashError(ui->caCertificate); return; } d->caCert = file.readAll(); file.close(); } emit done(); } void SecurityEapPeap::populateSetting(NetworkManager::Security8021xSetting::Ptr setting) { setting->setEapMethods({NetworkManager::Security8021xSetting::EapMethodPeap}); if (ui->peapVersionAuto->isChecked()) { setting->setPhase1PeapVersion(NetworkManager::Security8021xSetting::PeapVersionUnknown); } else if (ui->peapVersion0->isChecked()) { setting->setPhase1PeapVersion(NetworkManager::Security8021xSetting::PeapVersionZero); } else { setting->setPhase1PeapVersion(NetworkManager::Security8021xSetting::PeapVersionOne); } switch (ui->phase2Auth->currentIndex()) { case 0: //MSCHAPv2 setting->setPhase2AuthMethod(NetworkManager::Security8021xSetting::AuthMethodMschapv2); break; case 1: //MD5 setting->setPhase2AuthMethod(NetworkManager::Security8021xSetting::AuthMethodMd5); break; case 2: //GTC setting->setPhase2AuthMethod(NetworkManager::Security8021xSetting::AuthMethodGtc); break; } setting->setCaCertificate(d->caCert); setting->setAnonymousIdentity(ui->anonymousIdentity->text()); setting->setIdentity(ui->username->text()); setting->setPassword(ui->password->text()); } void SecurityEapPeap::on_browseCaCertButton_clicked() { QFileDialog* d = new QFileDialog(this); d->setAcceptMode(QFileDialog::AcceptOpen); d->setNameFilters({tr("Certificates (*.pem, *.cer)")}); connect(d, &QFileDialog::finished, this, [ = ](int result) { if (result == QFileDialog::Accepted) { ui->caCertificate->setText(d->selectedFiles().first()); } d->deleteLater(); }); d->open(); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/eap/securityeappeap.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SECURITYEAPPEAP_H #define SECURITYEAPPEAP_H #include "securityeap.h" namespace Ui { class SecurityEapPeap; } struct SecurityEapPeapPrivate; class SecurityEapPeap : public SecurityEap { Q_OBJECT public: explicit SecurityEapPeap(QWidget* parent = nullptr); ~SecurityEapPeap(); private slots: void on_titleLabel_backButtonClicked(); void on_connectButton_clicked(); void on_browseCaCertButton_clicked(); private: Ui::SecurityEapPeap* ui; SecurityEapPeapPrivate* d; // SecurityEap interface public: void populateSetting(NetworkManager::Security8021xSetting::Ptr setting); }; #endif // SECURITYEAPPEAP_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/eap/securityeappeap.ui ================================================ SecurityEapPeap 0 0 519 489 Form 0 0 0 0 0 PEAP Enter the settings for this network 9 16777215 1 Qt::Horizontal 9 9 9 9 6 Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC 0 0 0 0 0 Automatic true true true Version 0 true true Version 1 true true Qt::Horizontal 40 20 QLineEdit::Password Connect Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/NetworkPlugin/statusCenter/eap/securityeapunsupported.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "securityeapunsupported.h" #include "ui_securityeapunsupported.h" SecurityEapUnsupported::SecurityEapUnsupported(QWidget* parent) : SecurityEap(parent), ui(new Ui::SecurityEapUnsupported) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); } SecurityEapUnsupported::~SecurityEapUnsupported() { delete ui; } void SecurityEapUnsupported::on_titleLabel_backButtonClicked() { emit back(); } void SecurityEapUnsupported::populateSetting(NetworkManager::Security8021xSetting::Ptr setting) { } ================================================ FILE: plugins/NetworkPlugin/statusCenter/eap/securityeapunsupported.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SECURITYEAPUNSUPPORTED_H #define SECURITYEAPUNSUPPORTED_H #include "securityeap.h" namespace Ui { class SecurityEapUnsupported; } class SecurityEapUnsupported : public SecurityEap { Q_OBJECT public: explicit SecurityEapUnsupported(QWidget* parent = nullptr); ~SecurityEapUnsupported(); private slots: void on_titleLabel_backButtonClicked(); private: Ui::SecurityEapUnsupported* ui; // SecurityEap interface public: void populateSetting(NetworkManager::Security8021xSetting::Ptr setting); }; #endif // SECURITYEAPUNSUPPORTED_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/eap/securityeapunsupported.ui ================================================ SecurityEapUnsupported 0 0 488 412 Form 0 0 0 0 0 Unsupported Security Settings 6 9 9 9 9 Qt::Vertical 20 40 20 Unsupported Security Settings Qt::AlignCenter Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. Qt::AlignCenter true Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/NetworkPlugin/statusCenter/networkstatuscenterleftpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "networkstatuscenterleftpane.h" #include "ui_networkstatuscenterleftpane.h" #include #include NetworkStatusCenterLeftPane::NetworkStatusCenterLeftPane(QWidget* parent) : QWidget(parent), ui(new Ui::NetworkStatusCenterLeftPane) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); } NetworkStatusCenterLeftPane::~NetworkStatusCenterLeftPane() { delete ui; } void NetworkStatusCenterLeftPane::addItem(QListWidgetItem* item) { ui->devicesWidget->addItem(item); } void NetworkStatusCenterLeftPane::removeItem(QListWidgetItem* item) { ui->devicesWidget->takeItem(ui->devicesWidget->row(item)); } void NetworkStatusCenterLeftPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->returnToRootMenu(); } void NetworkStatusCenterLeftPane::on_devicesWidget_currentRowChanged(int currentRow) { emit currentChanged(currentRow); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/networkstatuscenterleftpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NETWORKSTATUSCENTERLEFTPANE_H #define NETWORKSTATUSCENTERLEFTPANE_H #include #include namespace Ui { class NetworkStatusCenterLeftPane; } class NetworkStatusCenterLeftPane : public QWidget { Q_OBJECT public: explicit NetworkStatusCenterLeftPane(QWidget* parent = nullptr); ~NetworkStatusCenterLeftPane(); void addItem(QListWidgetItem* item); void removeItem(QListWidgetItem* item); signals: void currentChanged(int device); private slots: void on_titleLabel_backButtonClicked(); void on_devicesWidget_currentRowChanged(int currentRow); private: Ui::NetworkStatusCenterLeftPane* ui; }; #endif // NETWORKSTATUSCENTERLEFTPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/networkstatuscenterleftpane.ui ================================================ NetworkStatusCenterLeftPane 0 0 400 300 Form 0 0 0 0 0 Network QFrame::NoFrame tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/NetworkPlugin/statusCenter/networkstatuscenterpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "networkstatuscenterpane.h" #include "ui_networkstatuscenterpane.h" #include "networkstatuscenterleftpane.h" #include #include #include #include #include "devicePanes/devicepane.h" #include "devicePanes/wifidevicepane.h" #include "devicePanes/wireddevicepane.h" #include "devicePanes/cellularpane.h" #include #include #include struct NetworkStatusCenterPanePrivate { NetworkStatusCenterLeftPane* leftPane; QDBusServiceWatcher* nmWatcher; SwitchManager* switchManager; QStringList unis; QStringList visibleUnis; QMap devicePanes; }; NetworkStatusCenterPane::NetworkStatusCenterPane(SwitchManager* switchManager) : StatusCenterPane(), ui(new Ui::NetworkStatusCenterPane) { ui->setupUi(this); d = new NetworkStatusCenterPanePrivate(); d->switchManager = switchManager; ui->menuButtonErrorPage->setVisible(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->menuButtonErrorPage, &QToolButton::setVisible); d->leftPane = new NetworkStatusCenterLeftPane(); connect(d->leftPane, &NetworkStatusCenterLeftPane::currentChanged, this, [ = ](int index) { ui->devicesStack->setCurrentIndex(index); }); ui->devicesStack->setCurrentAnimation(tStackedWidget::Lift); d->nmWatcher = new QDBusServiceWatcher("org.freedesktop.NetworkManager", QDBusConnection::systemBus()); connect(d->nmWatcher, &QDBusServiceWatcher::serviceRegistered, this, &NetworkStatusCenterPane::networkManagerRunning); connect(d->nmWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &NetworkStatusCenterPane::networkManagerGone); if (QDBusConnection::systemBus().interface()->registeredServiceNames().value().contains("org.freedesktop.NetworkManager")) { networkManagerRunning(); } else { networkManagerGone(); } connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &NetworkStatusCenterPane::deviceAdded); connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &NetworkStatusCenterPane::deviceRemoved); } NetworkStatusCenterPane::~NetworkStatusCenterPane() { d->leftPane->deleteLater(); delete d; delete ui; } void NetworkStatusCenterPane::networkManagerRunning() { ui->stackedWidget->setCurrentWidget(ui->activePage); for (NetworkManager::Device::Ptr device : NetworkManager::networkInterfaces()) { this->deviceAdded(device->uni()); } } void NetworkStatusCenterPane::networkManagerGone() { QStringList unis = d->unis; for (QString str : unis) { this->deviceRemoved(str); } ui->stackedWidget->setCurrentWidget(ui->errorPage); } void NetworkStatusCenterPane::deviceAdded(QString uni) { d->unis.append(uni); AbstractDevicePane* devicePane; NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(uni); switch (device->type()) { case NetworkManager::Device::Wifi: devicePane = new WifiDevicePane(uni); static_cast(devicePane)->setSwitchManager(d->switchManager); break; case NetworkManager::Device::Ethernet: devicePane = new WiredDevicePane(uni); break; case NetworkManager::Device::Modem: devicePane = new CellularPane(uni); break; default: devicePane = new DevicePane(uni); } auto managedChanged = [ = ] { if (device->managed() && !d->visibleUnis.contains(uni)) { d->visibleUnis.append(uni); d->leftPane->addItem(devicePane->leftPaneItem()); ui->devicesStack->addWidget(devicePane); } else if (!device->managed() && d->visibleUnis.contains(uni)) { d->visibleUnis.removeOne(uni); d->leftPane->removeItem(devicePane->leftPaneItem()); ui->devicesStack->removeWidget(devicePane); } }; connect(device.data(), &NetworkManager::Device::managedChanged, this, managedChanged); managedChanged(); d->devicePanes.insert(uni, devicePane); } void NetworkStatusCenterPane::deviceRemoved(QString uni) { AbstractDevicePane* devicePane = d->devicePanes.value(uni); d->unis.removeOne(uni); if (d->visibleUnis.contains(uni)) { d->leftPane->removeItem(devicePane->leftPaneItem()); ui->devicesStack->removeWidget(devicePane); d->visibleUnis.removeOne(uni); } devicePane->deleteLater(); d->devicePanes.remove(uni); } QString NetworkStatusCenterPane::name() { return "NetworkManagerPane"; } QString NetworkStatusCenterPane::displayName() { return tr("Network"); } QIcon NetworkStatusCenterPane::icon() { return QIcon::fromTheme("preferences-system-network"); } QWidget* NetworkStatusCenterPane::leftPane() { return d->leftPane; } void NetworkStatusCenterPane::on_menuButtonErrorPage_clicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void NetworkStatusCenterPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/NetworkPlugin/statusCenter/networkstatuscenterpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NETWORKSTATUSCENTERPANE_H #define NETWORKSTATUSCENTERPANE_H #include namespace Ui { class NetworkStatusCenterPane; } class SwitchManager; struct NetworkStatusCenterPanePrivate; class NetworkStatusCenterPane : public StatusCenterPane { Q_OBJECT public: explicit NetworkStatusCenterPane(SwitchManager* switchManager); ~NetworkStatusCenterPane(); private: Ui::NetworkStatusCenterPane* ui; NetworkStatusCenterPanePrivate* d; void networkManagerRunning(); void networkManagerGone(); void deviceAdded(QString uni); void deviceRemoved(QString uni); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); private slots: void on_menuButtonErrorPage_clicked(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // NETWORKSTATUSCENTERPANE_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/networkstatuscenterpane.ui ================================================ NetworkStatusCenterPane 0 0 615 401 Form 0 0 0 0 0 0 0 0 0 .. true Qt::Horizontal 40 20 Qt::Vertical 20 40 15 NetworkManager is not operational Qt::AlignCenter Contact your system administrator Qt::AlignCenter Qt::Vertical 20 40 0 0 0 0 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/connectionselectionpopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "connectionselectionpopover.h" #include "ui_connectionselectionpopover.h" struct ConnectionSelectionPopoverPrivate { NetworkManager::Connection::List connectionList; }; ConnectionSelectionPopover::ConnectionSelectionPopover(NetworkManager::Connection::List connectionList, QWidget* parent) : QWidget(parent), ui(new Ui::ConnectionSelectionPopover) { ui->setupUi(this); d = new ConnectionSelectionPopoverPrivate(); ui->titleLabel->setBackButtonShown(true); d->connectionList = connectionList; for (NetworkManager::Connection::Ptr connection : connectionList) { QListWidgetItem* item = new QListWidgetItem(); item->setText(connection->name()); ui->connectionList->addItem(item); } } ConnectionSelectionPopover::~ConnectionSelectionPopover() { delete d; delete ui; } void ConnectionSelectionPopover::on_titleLabel_backButtonClicked() { emit reject(); } void ConnectionSelectionPopover::on_connectionList_itemActivated(QListWidgetItem* item) { emit accept(d->connectionList.at(ui->connectionList->row(item))); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/connectionselectionpopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CONNECTIONSELECTIONPOPOVER_H #define CONNECTIONSELECTIONPOPOVER_H #include #include namespace Ui { class ConnectionSelectionPopover; } class QListWidgetItem; struct ConnectionSelectionPopoverPrivate; class ConnectionSelectionPopover : public QWidget { Q_OBJECT public: explicit ConnectionSelectionPopover(NetworkManager::Connection::List connectionList, QWidget* parent = nullptr); ~ConnectionSelectionPopover(); private slots: void on_titleLabel_backButtonClicked(); void on_connectionList_itemActivated(QListWidgetItem* item); signals: void reject(); void accept(NetworkManager::Connection::Ptr connection); private: Ui::ConnectionSelectionPopover* ui; ConnectionSelectionPopoverPrivate* d; }; #endif // CONNECTIONSELECTIONPOPOVER_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/connectionselectionpopover.ui ================================================ ConnectionSelectionPopover 0 0 400 447 Form 0 0 0 0 0 Select Connection Profile Select a connection profile to use 9 16777215 1 Qt::Horizontal QFrame::NoFrame tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/simsettingspopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "simsettingspopover.h" #include "ui_simsettingspopover.h" #include "networkplugincommon.h" #include #include #include struct SimSettingsPopoverPrivate { ModemManager::ModemDevice::Ptr modem; enum Operation { EnablePin, DisablePin, ChangePin }; Operation operation; }; SimSettingsPopover::SimSettingsPopover(ModemManager::ModemDevice::Ptr modem, QWidget* parent) : QWidget(parent), ui(new Ui::SimSettingsPopover) { ui->setupUi(this); d = new SimSettingsPopoverPrivate(); d->modem = modem; ui->titleLabel->setBackButtonShown(true); ui->currentPinTitleLabel->setBackButtonShown(true); ui->changeSimPinTitleLabel->setBackButtonShown(true); ui->callWaitingTitleLabel->setBackButtonShown(true); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); ui->spinner->setFixedSize(SC_DPI_T(QSize(32, 32), QSize)); ui->modemImeiLabel->setText(modem->modemInterface()->equipmentIdentifier()); ui->callWaitingSpinner->setVisible(false); ui->callWaitingSpinner->setFixedSize(SC_DPI_T(QSize(16, 16), QSize)); if (modem->sim()->uni() == "/") { ui->modemImsiLabel->setText(tr("No SIM card")); ui->modemCarrierLabel->setText(tr("No SIM card")); ui->simSettingsWidget->setVisible(false); } else { ui->modemImsiLabel->setText(modem->sim()->imsi()); ui->modemCarrierLabel->setText(modem->sim()->operatorName()); ui->simSettingsWidget->setVisible(true); } prepareMainPage(); } SimSettingsPopover::~SimSettingsPopover() { delete d; delete ui; } void SimSettingsPopover::on_currentSimPinAcceptButton_clicked() { ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->stackedWidget->setCurrentWidget(ui->spinnerPage); QDBusPendingReply<> pendingReply; switch (d->operation) { case SimSettingsPopoverPrivate::EnablePin: pendingReply = d->modem->sim()->enablePin(ui->currentPinBox->text(), true); break; case SimSettingsPopoverPrivate::DisablePin: pendingReply = d->modem->sim()->enablePin(ui->currentPinBox->text(), false); break; case SimSettingsPopoverPrivate::ChangePin: pendingReply = d->modem->sim()->changePin(ui->currentPinBox->text(), ui->changeSimPinBox->text()); break; } QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(pendingReply); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { prepareCurrentPinPage(); QTimer::singleShot(0, [=] { ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); }); } else { ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); ui->stackedWidget->setCurrentWidget(ui->startPage); prepareMainPage(); } }); } void SimSettingsPopover::on_titleLabel_backButtonClicked() { emit dismissed(); } void SimSettingsPopover::on_enableSimPinButton_clicked() { d->operation = SimSettingsPopoverPrivate::EnablePin; ui->currentPinTitleLabel->setText(tr("Enable SIM PIN")); prepareCurrentPinPage(); } void SimSettingsPopover::on_disableSimPinButton_clicked() { d->operation = SimSettingsPopoverPrivate::DisablePin; ui->currentPinTitleLabel->setText(tr("Disable SIM PIN")); prepareCurrentPinPage(); } void SimSettingsPopover::on_currentPinTitleLabel_backButtonClicked() { if (d->operation == SimSettingsPopoverPrivate::ChangePin) { ui->stackedWidget->setCurrentWidget(ui->changeSimPinPage); } else { ui->stackedWidget->setCurrentWidget(ui->startPage); } } void SimSettingsPopover::prepareCurrentPinPage() { ModemManager::UnlockRetriesMap retries; QDBusMessage unlockRetriesMessage = QDBusMessage::createMethodCall("org.freedesktop.ModemManager1", d->modem->uni(), "org.freedesktop.DBus.Properties", "Get"); unlockRetriesMessage.setArguments({"org.freedesktop.ModemManager1.Modem", "UnlockRetries"}); QDBusMessage unlockRetriesReply = QDBusConnection::systemBus().call(unlockRetriesMessage); QDBusArgument unlockRetriesArg = unlockRetriesReply.arguments().first().value().variant().value(); unlockRetriesArg >> retries; ui->currentPinPageOperatorName->setText(NetworkPluginCommon::operatorNameForModem(d->modem)); ui->pinRetryCount->setText(tr("You have %n remaining tries", nullptr, retries.value(MM_MODEM_LOCK_SIM_PIN))); ui->stackedWidget->setCurrentWidget(ui->currentPinPage); } void SimSettingsPopover::prepareMainPage() { ModemManager::Modem3gpp::Ptr modem3gpp(new ModemManager::Modem3gpp(d->modem->uni())); bool simLockEnabled = modem3gpp->enabledFacilityLocks() & MM_MODEM_3GPP_FACILITY_SIM; ui->enableSimPinButton->setVisible(!simLockEnabled); ui->disableSimPinButton->setVisible(simLockEnabled); } void SimSettingsPopover::on_changeSimPinTitleLabel_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->startPage); } void SimSettingsPopover::on_changeSimPinAcceptButton_clicked() { prepareCurrentPinPage(); } void SimSettingsPopover::on_changeSimPinButton_clicked() { d->operation = SimSettingsPopoverPrivate::ChangePin; ui->currentPinTitleLabel->setText(tr("Change SIM PIN")); ui->changeSimPinOperatorName->setText(NetworkPluginCommon::operatorNameForModem(d->modem)); ui->stackedWidget->setCurrentWidget(ui->changeSimPinPage); } void SimSettingsPopover::on_enableCallWaitingSwitch_toggled(bool checked) { this->setEnabled(false); ui->callWaitingSpinner->setVisible(true); QString uni = d->modem->uni(); QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.ModemManager1", uni, "org.freedesktop.ModemManager1.Modem.Voice", "CallWaitingSetup"); message.setArguments({checked}); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(QDBusConnection::systemBus().asyncCall(message)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { this->setEnabled(true); ui->callWaitingSpinner->setVisible(false); watcher->deleteLater(); }); } void SimSettingsPopover::on_callWaitingTitleLabel_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->startPage); } void SimSettingsPopover::on_callWaitingButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->spinnerPage); QString uni = d->modem->uni(); QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.ModemManager1", uni, "org.freedesktop.ModemManager1.Modem.Voice", "CallWaitingQuery"); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(QDBusConnection::systemBus().asyncCall(message)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { QSignalBlocker blocker(ui->enableCallWaitingSwitch); if (watcher->isError()) { ui->stackedWidget->setCurrentWidget(ui->startPage); tToast* toast = new tToast(this); toast->setTitle(tr("Error")); toast->setText(tr("Couldn't get current Call Waiting status from carrier")); toast->show(this); } else { ui->stackedWidget->setCurrentWidget(ui->callWaitingPage); ui->enableCallWaitingSwitch->setChecked(watcher->reply().arguments().first().toBool()); } watcher->deleteLater(); }); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/simsettingspopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SIMSETTINGSPOPOVER_H #define SIMSETTINGSPOPOVER_H #include #include namespace Ui { class SimSettingsPopover; } struct SimSettingsPopoverPrivate; class SimSettingsPopover : public QWidget { Q_OBJECT public: explicit SimSettingsPopover(ModemManager::ModemDevice::Ptr modem, QWidget* parent = nullptr); ~SimSettingsPopover(); private slots: void on_currentSimPinAcceptButton_clicked(); void on_titleLabel_backButtonClicked(); void on_enableSimPinButton_clicked(); void on_disableSimPinButton_clicked(); void on_currentPinTitleLabel_backButtonClicked(); void on_changeSimPinTitleLabel_backButtonClicked(); void on_changeSimPinAcceptButton_clicked(); void on_changeSimPinButton_clicked(); void on_enableCallWaitingSwitch_toggled(bool checked); void on_callWaitingTitleLabel_backButtonClicked(); void on_callWaitingButton_clicked(); signals: void dismissed(); private: Ui::SimSettingsPopover* ui; SimSettingsPopoverPrivate* d; void prepareCurrentPinPage(); void prepareMainPage(); }; #endif // SIMSETTINGSPOPOVER_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/simsettingspopover.ui ================================================ SimSettingsPopover 0 0 720 806 Form 0 0 0 0 0 0 0 0 0 0 0 Modem Settings 0 0 0 0 0 75 true SIM PIN 9 Enable SIM PIN Disable SIM PIN Change SIM PIN 75 true CALLS 9 Call Waiting 9 9 9 9 6 TextLabel Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 0 0 TextLabel Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse IMSI IMEI 75 true MODEM INFORMATION Carrier TextLabel Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse Qt::Vertical 20 40 0 0 0 0 0 Change SIM PIN Qt::Vertical 20 297 Qt::Horizontal 107 20 500 0 false QFrame::NoFrame QFrame::Plain 0 15 Username 20 Enter the new SIM PIN Qt::Vertical QSizePolicy::Fixed 20 40 0 true 0 0 0 0 30 false QLineEdit::Password Qt::AlignCenter false 0 0 .. false true Qt::Horizontal 107 20 Qt::Vertical 20 297 0 0 0 0 0 Qt::Horizontal 107 20 500 0 false QFrame::NoFrame QFrame::Plain 0 15 Username 20 Enter the current SIM PIN false You have 3 remaining tries Qt::Vertical QSizePolicy::Fixed 20 40 0 true 0 0 0 0 30 false QLineEdit::Password Qt::AlignCenter false 0 0 .. false true Qt::Vertical 20 286 Qt::Horizontal 107 20 Qt::Vertical 20 285 Activate SIM PIN Qt::Vertical 20 374 Qt::Horizontal 331 20 Qt::Horizontal 330 20 Qt::Vertical 20 373 0 0 0 0 0 Call Waiting 9 9 9 9 6 EnableCallWaiting 0 0 Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. Qt::Vertical 20 720 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tSwitch QPushButton
tswitch.h
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/tetheringsettingspopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "tetheringsettingspopover.h" #include "ui_tetheringsettingspopover.h" #include #include #include struct TetheringSettingsPopoverPrivate { tSettings settings; }; TetheringSettingsPopover::TetheringSettingsPopover(QWidget* parent) : QWidget(parent), ui(new Ui::TetheringSettingsPopover) { ui->setupUi(this); d = new TetheringSettingsPopoverPrivate(); ui->titleLabel->setBackButtonShown(true); QString ssid = d->settings.value("NetworkPlugin/tethering.ssid").toString(); ssid = ssid.replace("$hostname", QHostInfo::localHostName()); ui->ssidBox->setText(ssid); ui->keyBox->setText(d->settings.value("NetworkPlugin/tethering.key").toString()); } TetheringSettingsPopover::~TetheringSettingsPopover() { delete ui; delete d; } void TetheringSettingsPopover::on_ssidBox_textChanged(const QString& arg1) { QString ssid = arg1; if (arg1.isEmpty()) { ui->ssidBox->setText(QHostInfo::localHostName()); ssid = QHostInfo::localHostName(); } d->settings.setValue("NetworkPlugin/tethering.ssid", ssid); } void TetheringSettingsPopover::on_keyBox_textChanged(const QString& arg1) { if (arg1.length() < 8) { tErrorFlash::flashError(ui->keyBox); ui->keyError->setVisible(true); ui->keyError->setText(tr("Network key needs to be at least 8 characters long")); return; } ui->keyError->setVisible(false); d->settings.setValue("NetworkPlugin/tethering.key", arg1); } void TetheringSettingsPopover::on_titleLabel_backButtonClicked() { emit done(); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/tetheringsettingspopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef TETHERINGSETTINGSPOPOVER_H #define TETHERINGSETTINGSPOPOVER_H #include namespace Ui { class TetheringSettingsPopover; } struct TetheringSettingsPopoverPrivate; class TetheringSettingsPopover : public QWidget { Q_OBJECT public: explicit TetheringSettingsPopover(QWidget* parent = nullptr); ~TetheringSettingsPopover(); signals: void done(); private slots: void on_ssidBox_textChanged(const QString& arg1); void on_keyBox_textChanged(const QString& arg1); void on_titleLabel_backButtonClicked(); private: Ui::TetheringSettingsPopover* ui; TetheringSettingsPopoverPrivate* d; }; #endif // TETHERINGSETTINGSPOPOVER_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/tetheringsettingspopover.ui ================================================ TetheringSettingsPopover 0 0 503 500 Form 0 0 0 0 0 Tethering Settings QFrame::NoFrame true 0 0 503 483 SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. true Qt::Vertical 20 0 Network Key tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/unlockmodempopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "unlockmodempopover.h" #include "ui_unlockmodempopover.h" #include "networkplugincommon.h" #include #include #include struct UnlockModemPopoverPrivate { ModemManager::ModemDevice::Ptr modem; }; UnlockModemPopover::UnlockModemPopover(ModemManager::ModemDevice::Ptr modem, QWidget* parent) : QWidget(parent), ui(new Ui::UnlockModemPopover) { ui->setupUi(this); d = new UnlockModemPopoverPrivate(); d->modem = modem; updatePage(); ui->simPinTitleLabel->setBackButtonShown(true); ui->simPukTitleLabel->setBackButtonShown(true); ui->spinner->setFixedSize(SC_DPI_T(QSize(32, 32), QSize)); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->simPukContainer->setFixedWidth(SC_DPI(600)); ui->simPukWarning->setState(tStatusFrame::Warning); ui->simPukWarning->setTitle(tr("Don't guess the PUK!")); ui->simPukWarning->setText(tr("Once you exhaust your attempts, the SIM card will be blocked forever.\n\nYou'll need to contact your carrier for a new SIM card.")); } UnlockModemPopover::~UnlockModemPopover() { delete d; delete ui; } void UnlockModemPopover::updatePage() { MMModemLock unlockRequired = d->modem->modemInterface()->unlockRequired(); ModemManager::UnlockRetriesMap retries; QDBusMessage unlockRetriesMessage = QDBusMessage::createMethodCall("org.freedesktop.ModemManager1", d->modem->uni(), "org.freedesktop.DBus.Properties", "Get"); unlockRetriesMessage.setArguments({"org.freedesktop.ModemManager1.Modem", "UnlockRetries"}); QDBusMessage unlockRetriesReply = QDBusConnection::systemBus().call(unlockRetriesMessage); QDBusArgument unlockRetriesArg = unlockRetriesReply.arguments().first().value().variant().value(); unlockRetriesArg >> retries; if (retries.value(MM_MODEM_LOCK_SIM_PIN) == 1) { ui->pinRetryCount->setText(tr("If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier.")); } else { ui->pinRetryCount->setText(tr("You have %n remaining tries", nullptr, retries.value(MM_MODEM_LOCK_SIM_PIN))); } if (retries.value(MM_MODEM_LOCK_SIM_PUK) == 1) { ui->pukRetryCount->setText(tr("This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier.")); } else { ui->pukRetryCount->setText(tr("You have %n remaining tries", nullptr, retries.value(MM_MODEM_LOCK_SIM_PUK))); } ui->simPinOperatorName->setText(NetworkPluginCommon::operatorNameForModem(d->modem)); ui->pukDescription->setText(tr("Contact your carrier to obtain the SIM PUK, and enter it below to unlock %1.").arg(QLocale().quoteString(NetworkPluginCommon::operatorNameForModem(d->modem)))); ui->simPinBox->clear(); ui->simPukBox->clear(); switch (unlockRequired) { case MM_MODEM_LOCK_SIM_PIN: { ui->stackedWidget->setCurrentWidget(ui->simPinPage); ui->simPinBox->setFocus(); break; } case MM_MODEM_LOCK_SIM_PUK: { ui->stackedWidget->setCurrentWidget(ui->simPukPage); ui->simPukBox->setFocus(); break; } default: emit done(); } } void UnlockModemPopover::on_simPinAcceptButton_clicked() { bool ok; ui->simPinBox->text().toInt(&ok); if (!ok) { tErrorFlash::flashError(ui->simPinBox); return; } if (ui->simPinBox->text().count() < 4) { tErrorFlash::flashError(ui->simPinBox); return; } ui->stackedWidget->setCurrentWidget(ui->loadingPage); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(d->modem->sim()->sendPin(ui->simPinBox->text())); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { QTimer::singleShot(200, this, &UnlockModemPopover::updatePage); watcher->deleteLater(); }); } void UnlockModemPopover::on_simPinTitleLabel_backButtonClicked() { emit done(); } void UnlockModemPopover::on_simPukAcceptButton_clicked() { bool ok; ui->simPukBox->text().toInt(&ok); if (!ok) { tErrorFlash::flashError(ui->simPukBox); return; } if (ui->simPukBox->text().count() < 8) { tErrorFlash::flashError(ui->simPukBox); return; } ui->simPukNewSimPin->text().toInt(&ok); if (!ok) { tErrorFlash::flashError(ui->simPukNewSimPin); return; } if (ui->simPukNewSimPin->text().count() < 4) { tErrorFlash::flashError(ui->simPukNewSimPin); return; } if (ui->simPukConfirmSimPin->text() != ui->simPukNewSimPin->text()) { tErrorFlash::flashError(ui->simPukConfirmSimPin); return; } ui->stackedWidget->setCurrentWidget(ui->loadingPage); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(d->modem->sim()->sendPuk(ui->simPukBox->text(), ui->simPukNewSimPin->text())); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { QTimer::singleShot(200, this, &UnlockModemPopover::updatePage); watcher->deleteLater(); }); } void UnlockModemPopover::on_simPukTitleLabel_backButtonClicked() { emit done(); } ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/unlockmodempopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef UNLOCKMODEMPOPOVER_H #define UNLOCKMODEMPOPOVER_H #include #include namespace Ui { class UnlockModemPopover; } struct UnlockModemPopoverPrivate; class UnlockModemPopover : public QWidget { Q_OBJECT public: explicit UnlockModemPopover(ModemManager::ModemDevice::Ptr modem, QWidget* parent = nullptr); ~UnlockModemPopover(); signals: void done(); private slots: void on_simPinAcceptButton_clicked(); void on_simPinTitleLabel_backButtonClicked(); void on_simPukAcceptButton_clicked(); void on_simPukTitleLabel_backButtonClicked(); private: Ui::UnlockModemPopover* ui; UnlockModemPopoverPrivate* d; void updatePage(); }; #endif // UNLOCKMODEMPOPOVER_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/unlockmodempopover.ui ================================================ UnlockModemPopover 0 0 923 547 Form 0 0 0 0 0 1 Qt::Vertical 20 244 Qt::Horizontal 432 20 Qt::Horizontal 432 20 Qt::Vertical 20 244 0 0 0 0 0 SIM PIN Qt::Vertical 20 156 Qt::Horizontal 209 20 500 0 false QFrame::NoFrame QFrame::Plain 0 15 Username 20 Enter the SIM PIN false You have 3 remaining tries Qt::Vertical QSizePolicy::Fixed 20 40 0 true 0 0 0 0 30 false QLineEdit::Password Qt::AlignCenter false 0 0 .. false true Qt::Horizontal 208 20 Qt::Vertical 20 156 0 0 0 0 0 SIM PUK QLineEdit::Password SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. true 75 true SIM PUK REQUIRED 0 0 QFrame::StyledPanel QFrame::Raised Provide the <b>SIM PUK</b> to unlock this SIM card. true false You have 3 tries remaining. true Unlock SIM Card .. 0 0 0 0 0 QLineEdit::Password New SIM PIN QLineEdit::Password Confirm SIM PIN Qt::Vertical 20 0 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tCircularSpinner QWidget
tcircularspinner.h
1
tStatusFrame QFrame
tstatusframe.h
1
simPukConfirmSimPin returnPressed() simPukAcceptButton click() 368 196 396 238 simPinBox returnPressed() simPinAcceptButton click() 568 350 692 350
================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/wirelessnetworkselectionpopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "wirelessnetworkselectionpopover.h" #include "ui_wirelessnetworkselectionpopover.h" #include #include #include #include #include #include #include #include #include "../eap/securityeappeap.h" #include "../eap/securityeapunsupported.h" #include #include #include #include "models/wirelessconnectionlistmodel.h" #include "models/wirelessaccesspointsmodel.h" #include "models/wirelessnetworklistdelegate.h" #include "../connectionEditor/networkconnectioneditor.h" struct WirelessNetworkSelectionPopoverPrivate { NetworkManager::WirelessDevice::Ptr device; WirelessConnectionListModel* knownNetworksModel; WirelessAccessPointsModel* newNetworksModel; NetworkManager::AccessPoint::Ptr apConnect; NetworkManager::WirelessSecurityType connectWithSecurity; SecurityEap* eapPane = nullptr; NetworkConnectionEditor* editor = nullptr; }; WirelessNetworkSelectionPopover::WirelessNetworkSelectionPopover(QString deviceUni, QWidget* parent) : QWidget(parent), ui(new Ui::WirelessNetworkSelectionPopover) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); ui->keyTitleLabel->setBackButtonShown(true); ui->eapMethodTitleLabel->setBackButtonShown(true); d = new WirelessNetworkSelectionPopoverPrivate(); d->device = NetworkManager::findNetworkInterface(deviceUni).staticCast(); d->knownNetworksModel = new WirelessConnectionListModel(); ui->knownNetworksListView->setModel(d->knownNetworksModel); connect(d->knownNetworksModel, &WirelessConnectionListModel::dataChanged, this, [ = ] { ui->knownNetworksListView->setFixedHeight(d->knownNetworksModel->rowCount() * ui->knownNetworksListView->sizeHintForRow(0)); }); ui->knownNetworksListView->setItemDelegate(new WirelessNetworkListDelegate(deviceUni)); ui->knownNetworksListView->setFixedHeight(d->knownNetworksModel->rowCount() * ui->knownNetworksListView->sizeHintForRow(0)); d->newNetworksModel = new WirelessAccessPointsModel(deviceUni, false); ui->newNetworksListView->setModel(d->newNetworksModel); connect(d->newNetworksModel, &WirelessAccessPointsModel::dataChanged, this, [ = ] { ui->newNetworksListView->setFixedHeight(d->newNetworksModel->rowCount() * ui->newNetworksListView->sizeHintForRow(0)); }); ui->newNetworksListView->setItemDelegate(new WirelessNetworkListDelegate(deviceUni)); ui->newNetworksListView->setFixedHeight(d->newNetworksModel->rowCount() * ui->newNetworksListView->sizeHintForRow(0)); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); } WirelessNetworkSelectionPopover::~WirelessNetworkSelectionPopover() { d->knownNetworksModel->deleteLater(); d->newNetworksModel->deleteLater(); delete d; delete ui; } void WirelessNetworkSelectionPopover::on_titleLabel_backButtonClicked() { emit done(); } void WirelessNetworkSelectionPopover::on_knownNetworksListView_activated(const QModelIndex& index) { activateConnection(index); } void WirelessNetworkSelectionPopover::activateConnection(const QModelIndex& index) { QVariant networkInformation = index.data(Qt::UserRole); if (networkInformation.canConvert()) { //Attempt to activate this known connection NetworkManager::activateConnection(networkInformation.value()->path(), d->device->uni(), ""); emit done(); } else if (networkInformation.canConvert()) { //Connect to a new AP d->apConnect = networkInformation.value(); d->connectWithSecurity = NetworkManager::findBestWirelessSecurity(d->device->wirelessCapabilities(), true, false, d->apConnect->capabilities(), d->apConnect->wpaFlags(), d->apConnect->rsnFlags()); switch (d->connectWithSecurity) { case NetworkManager::NoneSecurity: { //Attempt to activate a new connection createConnection(); break; } case NetworkManager::StaticWep: case NetworkManager::DynamicWep: case NetworkManager::WpaPsk: case NetworkManager::Wpa2Psk: case NetworkManager::SAE: ui->securityNetworkName->setText(d->apConnect->ssid()); ui->networkKey->clear(); ui->stackedWidget->setCurrentWidget(ui->keyPage); break; case NetworkManager::WpaEap: case NetworkManager::Wpa2Eap: ui->eapMethodTitleLabel->setText(d->apConnect->ssid()); ui->networkKey->clear(); ui->stackedWidget->setCurrentWidget(ui->eapMethodPage); break; case NetworkManager::Leap: case NetworkManager::UnknownSecurity: default: { tToast* toast = new tToast(this); toast->setTitle(tr("Unknown Security")); toast->setText(tr("Not sure how to connect to this network. Use manual setup to connect to it.")); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); break; } } } } void WirelessNetworkSelectionPopover::createConnection() { NetworkManager::ConnectionSettings settings(NetworkManager::ConnectionSettings::Wireless); NetworkManager::WirelessSetting::Ptr wirelessSettings = settings.setting(NetworkManager::Setting::Wireless).staticCast(); NetworkManager::WirelessSecuritySetting::Ptr securitySettings = settings.setting(NetworkManager::Setting::WirelessSecurity).staticCast(); NetworkManager::Security8021xSetting::Ptr eapSettings = settings.setting(NetworkManager::Setting::Security8021x).staticCast(); settings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); wirelessSettings->setSsid(d->apConnect->ssid().toUtf8()); switch (d->connectWithSecurity) { case NetworkManager::NoneSecurity: //Don't need to set anything special here break; case NetworkManager::StaticWep: case NetworkManager::DynamicWep: securitySettings->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Wep); securitySettings->setAuthAlg(NetworkManager::WirelessSecuritySetting::Shared); securitySettings->setWepKey0(ui->networkKey->text()); securitySettings->setInitialized(true); break; case NetworkManager::WpaPsk: case NetworkManager::Wpa2Psk: securitySettings->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); securitySettings->setPsk(ui->networkKey->text()); securitySettings->setInitialized(true); break; case NetworkManager::SAE: securitySettings->setKeyMgmt(NetworkManager::WirelessSecuritySetting::SAE); securitySettings->setPsk(ui->networkKey->text()); securitySettings->setInitialized(true); break; case NetworkManager::WpaEap: case NetworkManager::Wpa2Eap: securitySettings->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap); securitySettings->setInitialized(true); d->eapPane->populateSetting(eapSettings); eapSettings->setInitialized(true); break; case NetworkManager::Leap: case NetworkManager::UnknownSecurity: default: return; } wirelessSettings->setInitialized(true); // securitySettings->setInitialized(true); // eapSettings->setInitialized(true); qDebug() << settings; qDebug() << settings.toMap(); QDBusPendingReply r = NetworkManager::addAndActivateConnection(settings.toMap(), d->device->uni(), ""); r.waitForFinished(); if (r.isError()) { qDebug() << r.error().name() << r.error().message(); } emit done(); } void WirelessNetworkSelectionPopover::on_knownNetworksListView_customContextMenuRequested(const QPoint& pos) { QModelIndex index = ui->knownNetworksListView->indexAt(pos); NetworkManager::Connection::Ptr cn = index.data(Qt::UserRole).value(); QMenu* menu = new QMenu(this); menu->addSection(tr("For network %1").arg(cn->name())); menu->addAction(QIcon::fromTheme("edit-rename"), tr("Edit"), [ = ] { if (d->editor) { ui->manualPage->layout()->removeWidget(d->editor); d->editor->deleteLater(); } d->editor = new NetworkConnectionEditor(cn, this); ui->manualPage->layout()->addWidget(d->editor); connect(d->editor, &NetworkConnectionEditor::accepted, this, [ = ] { ui->stackedWidget->setCurrentWidget(ui->selectionPage); }); connect(d->editor, &NetworkConnectionEditor::rejected, this, [ = ] { ui->stackedWidget->setCurrentWidget(ui->selectionPage); }); ui->stackedWidget->setCurrentWidget(ui->manualPage); }); menu->addAction(QIcon::fromTheme("list-remove"), tr("Forget Network"), [ = ] { cn->remove(); }); connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); menu->popup(ui->knownNetworksListView->mapToGlobal(pos)); } void WirelessNetworkSelectionPopover::on_keyTitleLabel_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->selectionPage); } void WirelessNetworkSelectionPopover::on_newNetworksListView_activated(const QModelIndex& index) { activateConnection(index); } void WirelessNetworkSelectionPopover::on_securityConnectButton_clicked() { switch (d->connectWithSecurity) { case NetworkManager::StaticWep: case NetworkManager::DynamicWep: case NetworkManager::SAE: if (ui->networkKey->text().isEmpty()) { tErrorFlash::flashError(ui->networkKeyContainer); return; } break; case NetworkManager::WpaPsk: case NetworkManager::Wpa2Psk: if (ui->networkKey->text().length() < 8) { tErrorFlash::flashError(ui->networkKeyContainer); return; } break; default: return; } this->createConnection(); } void WirelessNetworkSelectionPopover::on_eapMethodTitleLabel_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->selectionPage); } void WirelessNetworkSelectionPopover::on_eapMethodList_activated(const QModelIndex& index) { if (d->eapPane) { ui->stackedWidget->removeWidget(d->eapPane); d->eapPane->deleteLater(); d->eapPane = nullptr; } switch (index.row()) { case 0: //TLS case 1: //LEAP case 2: //PWD case 3: //FAST case 4: //TTLS d->eapPane = new SecurityEapUnsupported(this); break; case 5: //PEAP d->eapPane = new SecurityEapPeap(this); } if (d->eapPane) { ui->stackedWidget->addWidget(d->eapPane); ui->stackedWidget->setCurrentWidget(d->eapPane); connect(d->eapPane, &SecurityEap::back, this, [ = ] { ui->stackedWidget->setCurrentWidget(ui->eapMethodPage); }); connect(d->eapPane, &SecurityEap::done, this, &WirelessNetworkSelectionPopover::createConnection); } } void WirelessNetworkSelectionPopover::on_manualButton_clicked() { if (d->editor) { ui->manualPage->layout()->removeWidget(d->editor); d->editor->deleteLater(); } NetworkManager::ConnectionSettings::Ptr settings(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wireless)); settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); settings->setId(tr("Wireless")); d->editor = new NetworkConnectionEditor(settings); d->editor->setSaveButtonText(tr("Connect")); ui->manualPage->layout()->addWidget(d->editor); connect(d->editor, &NetworkConnectionEditor::accepted, this, [ = ](NetworkManager::Connection::Ptr connection) { //Activate this connection NetworkManager::activateConnection(connection->path(), d->device->uni(), ""); emit done(); }); connect(d->editor, &NetworkConnectionEditor::rejected, this, [ = ] { ui->stackedWidget->setCurrentWidget(ui->selectionPage); }); ui->stackedWidget->setCurrentWidget(ui->manualPage); } void WirelessNetworkSelectionPopover::on_stackedWidget_switchingFrame(int frame) { tPopover* popover = tPopover::popoverForPopoverWidget(this); if (ui->stackedWidget->widget(frame) == ui->manualPage) { popover->setPopoverWidth(d->editor->preferredPopoverWidth()); popover->setDismissable(false); } else { popover->setPopoverWidth(SC_DPI(600)); popover->setDismissable(true); } } ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/wirelessnetworkselectionpopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WIRELESSNETWORKSELECTIONPOPOVER_H #define WIRELESSNETWORKSELECTIONPOPOVER_H #include namespace Ui { class WirelessNetworkSelectionPopover; } struct WirelessNetworkSelectionPopoverPrivate; class WirelessNetworkSelectionPopover : public QWidget { Q_OBJECT public: explicit WirelessNetworkSelectionPopover(QString deviceUni, QWidget* parent = nullptr); ~WirelessNetworkSelectionPopover(); signals: void done(); private slots: void on_titleLabel_backButtonClicked(); void on_knownNetworksListView_activated(const QModelIndex& index); void on_knownNetworksListView_customContextMenuRequested(const QPoint& pos); void on_keyTitleLabel_backButtonClicked(); void on_newNetworksListView_activated(const QModelIndex& index); void on_securityConnectButton_clicked(); void on_eapMethodTitleLabel_backButtonClicked(); void on_eapMethodList_activated(const QModelIndex& index); void on_manualButton_clicked(); void on_stackedWidget_switchingFrame(int frame); private: Ui::WirelessNetworkSelectionPopover* ui; WirelessNetworkSelectionPopoverPrivate* d; void activateConnection(const QModelIndex& index); void createConnection(); }; #endif // WIRELESSNETWORKSELECTIONPOPOVER_H ================================================ FILE: plugins/NetworkPlugin/statusCenter/popovers/wirelessnetworkselectionpopover.ui ================================================ WirelessNetworkSelectionPopover 0 0 765 505 Form 0 0 0 0 0 0 0 0 0 0 0 Connect to a Wireless Network QFrame::NoFrame true 0 0 765 488 0 0 0 0 0 0 true KNOWN NETWORKS 9 0 0 Qt::CustomContextMenu QFrame::NoFrame 16777215 1 Qt::Horizontal 0 true NEW NETWORKS 9 0 0 QFrame::NoFrame New Manual Connection .. Qt::Vertical 20 40 0 0 0 0 0 Qt::Vertical 20 224 Qt::Horizontal 161 20 500 0 false QFrame::NoFrame QFrame::Plain 0 15 Username 20 Enter the security key Qt::Vertical QSizePolicy::Fixed 20 40 0 true 0 0 0 0 30 false QLineEdit::Password Qt::AlignCenter false 0 0 .. false true Qt::Horizontal 161 20 Qt::Vertical 20 223 Network Security 0 0 0 0 0 TextLabel Select the EAP method. If you don't know what to select, contact your system administrator for the details. true 9 16777215 1 Qt::Horizontal QFrame::NoFrame TLS LEAP PWD FAST TTLS PEAP 0 0 0 0 0 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
networkKey returnPressed() securityConnectButton click() 455 30 489 30
================================================ FILE: plugins/NetworkPlugin/switchmanager.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "switchmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include struct SwitchManagerPrivate { QDBusServiceWatcher* nmWatcher; QDBusInterface* interface; QuickSwitch* flightModeSwitch; QuickSwitch* wifiSwitch; QuickSwitch* cellularSwitch; IconTextChunk* flightModeChunk; tSettings settings; bool block = false; }; SwitchManager::SwitchManager(QObject* parent) : QObject(parent) { d = new SwitchManagerPrivate(); d->interface = new QDBusInterface("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.DBus.Properties", QDBusConnection::systemBus(), this); d->flightModeSwitch = new QuickSwitch("NetworkFlight"); d->wifiSwitch = new QuickSwitch("NetworkWireless"); d->cellularSwitch = new QuickSwitch("NetworkCellular"); d->flightModeChunk = new IconTextChunk("flight-mode"); d->flightModeChunk->setText(tr("Flight Mode")); d->flightModeChunk->setIcon(QIcon::fromTheme("flight-mode")); ActionQuickWidget* flightChunkQuickWidget = new ActionQuickWidget(d->flightModeChunk); flightChunkQuickWidget->addAction(QIcon::fromTheme("flight-mode"), tr("Switch off Flight Mode"), [ = ] { this->setFlightMode(false); }); d->flightModeChunk->setQuickWidget(flightChunkQuickWidget); d->flightModeSwitch->setTitle(tr("Flight Mode")); connect(d->flightModeSwitch, &QuickSwitch::toggled, this, &SwitchManager::setFlightMode); if (d->settings.value("NetworkPlugin/flight.on").toBool()) { this->setFlightMode(true); } d->wifiSwitch->setTitle(tr("Wi-Fi")); d->wifiSwitch->setChecked(NetworkManager::isWirelessEnabled()); connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessEnabledChanged, this, [ = ](bool enabled) { QSignalBlocker blocker(d->wifiSwitch); d->wifiSwitch->setChecked(enabled); }); connect(d->wifiSwitch, &QuickSwitch::toggled, this, [ = ](bool enabled) { d->interface->asyncCall("Set", "org.freedesktop.NetworkManager", "WirelessEnabled", QVariant::fromValue(QDBusVariant(enabled))); }); d->cellularSwitch->setTitle(tr("Cellular")); d->cellularSwitch->setChecked(NetworkManager::isWwanEnabled()); connect(NetworkManager::notifier(), &NetworkManager::Notifier::wwanEnabledChanged, this, [ = ](bool enabled) { QSignalBlocker blocker(d->cellularSwitch); d->cellularSwitch->setChecked(enabled); }); connect(d->cellularSwitch, &QuickSwitch::toggled, this, [ = ](bool enabled) { d->interface->asyncCall("Set", "org.freedesktop.NetworkManager", "WwanEnabled", QVariant::fromValue(QDBusVariant(enabled))); }); d->nmWatcher = new QDBusServiceWatcher("org.freedesktop.NetworkManager", QDBusConnection::systemBus()); connect(d->nmWatcher, &QDBusServiceWatcher::serviceRegistered, this, &SwitchManager::networkManagerRunning); connect(d->nmWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &SwitchManager::networkManagerGone); if (QDBusConnection::systemBus().interface()->registeredServiceNames().value().contains("org.freedesktop.NetworkManager")) networkManagerRunning(); connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &SwitchManager::updateDevices); connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &SwitchManager::updateDevices); } SwitchManager::~SwitchManager() { d->nmWatcher->deleteLater(); d->flightModeSwitch->deleteLater(); d->wifiSwitch->deleteLater(); d->cellularSwitch->deleteLater(); delete d; } bool SwitchManager::isFlightModeEnabled() { return d->flightModeSwitch->isChecked(); } void SwitchManager::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { d->flightModeSwitch->setTitle(tr("Flight Mode")); d->wifiSwitch->setTitle(tr("Wi-Fi")); d->cellularSwitch->setTitle(tr("Cellular")); } } void SwitchManager::networkManagerRunning() { StateManager::statusCenterManager()->addSwitch(d->flightModeSwitch); updateDevices(); } void SwitchManager::networkManagerGone() { StatusCenterManager* mgr = StateManager::statusCenterManager(); mgr->removeSwitch(d->flightModeSwitch); mgr->removeSwitch(d->wifiSwitch); mgr->removeSwitch(d->cellularSwitch); } void SwitchManager::updateDevices() { StatusCenterManager* mgr = StateManager::statusCenterManager(); bool wifi = false; bool cellular = false; for (NetworkManager::Device::Ptr device : NetworkManager::networkInterfaces()) { if (device->type() == NetworkManager::Device::Wifi) wifi = true; if (device->type() == NetworkManager::Device::Modem) cellular = true; } if (wifi) { mgr->addSwitch(d->wifiSwitch); } else { mgr->removeSwitch(d->wifiSwitch); } if (cellular) { mgr->addSwitch(d->cellularSwitch); } else { mgr->removeSwitch(d->cellularSwitch); } } void SwitchManager::setFlightMode(bool flightOn) { QSignalBlocker blocker(d->flightModeSwitch); d->flightModeSwitch->setChecked(flightOn); if (flightOn) { d->settings.setValue("NetworkPlugin/flight.wifi", NetworkManager::isWirelessEnabled()); d->settings.setValue("NetworkPlugin/flight.cellular", NetworkManager::isWwanEnabled()); d->settings.setValue("NetworkPlugin/flight.on", true); d->interface->asyncCall("Set", "org.freedesktop.NetworkManager", "WirelessEnabled", QVariant::fromValue(QDBusVariant(false))); d->interface->asyncCall("Set", "org.freedesktop.NetworkManager", "WwanEnabled", QVariant::fromValue(QDBusVariant(false))); if (!StateManager::instance()->barManager()->isChunkRegistered(d->flightModeChunk)) StateManager::instance()->barManager()->addChunk(d->flightModeChunk); } else { d->interface->asyncCall("Set", "org.freedesktop.NetworkManager", "WirelessEnabled", QVariant::fromValue(QDBusVariant(d->settings.value("NetworkPlugin/flight.wifi").toBool()))); d->interface->asyncCall("Set", "org.freedesktop.NetworkManager", "WwanEnabled", QVariant::fromValue(QDBusVariant(d->settings.value("NetworkPlugin/flight.cellular").toBool()))); d->settings.setValue("NetworkPlugin/flight.on", false); if (StateManager::instance()->barManager()->isChunkRegistered(d->flightModeChunk)) StateManager::instance()->barManager()->removeChunk(d->flightModeChunk); } } ================================================ FILE: plugins/NetworkPlugin/switchmanager.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SWITCHMANAGER_H #define SWITCHMANAGER_H #include struct SwitchManagerPrivate; class SwitchManager : public QObject { Q_OBJECT public: explicit SwitchManager(QObject* parent = nullptr); ~SwitchManager(); bool isFlightModeEnabled(); void setFlightMode(bool flightOn); signals: private: SwitchManagerPrivate* d; void changeEvent(QEvent* event); void networkManagerRunning(); void networkManagerGone(); void updateDevices(); }; #endif // SWITCHMANAGER_H ================================================ FILE: plugins/NetworkPlugin/thedesk-network.conf ================================================ [NetworkPlugin] notifications.activation=true flight.on=false flight.wifi=true flight.cellular=true tethering.ssid=$hostname tethering.key=. tethering.uuid=. ================================================ FILE: plugins/NetworkPlugin/translations/ar_SA.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/au_AU.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/cy.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/da.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/de.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/en_GB.ts ================================================ CellularPane STATUS STATUS This Device This Device ACTIONS ACTIONS Connect Connect Disconnect Disconnect Cellular Cellular Disconnected Disconnected Connected Connected Failed Failed Unavailable Unavailable This network is unavailable because %2. This network is unavailable because %2. Connection Failure Connection Failure Connecting to the network failed because %2. Connecting to the network failed because %2. Enter SIM PIN Enter SIM PIN SIM PIN Required SIM PIN Required Enter SIM PUK Enter SIM PUK SIM PUK Required SIM PUK Required A SIM PIN is required to connect to the cellular network. A SIM PIN is required to connect to the cellular network. A SIM PUK is required to connect to the cellular network. A SIM PUK is required to connect to the cellular network. Modem Settings Router Settings Disable Cellular Disable Cellular Enable Cellular Enable Cellular No SIM Card No SIM Card Insert a SIM card to connect to cellular services. Insert a SIM card to connect to cellular services. No SIM No SIM Common an unknown error occurred an unknown error occurred the device is no longer managed by NetworkManager the device is no longer managed by NetworkManager configuration of the device failed configuration of the device failed configuration of the device is unavailable configuration of the device is unavailable configuration of the device expired configuration of the device expired required secrets were not provided required secrets were not provided the authentication supplicant disconnected the authentication supplicant disconnected configuration of the authentication supplicant failed configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the authentication supplicant timed out the PPP network failed to start the PPP network failed to start the PPP network was disconnected the PPP network was disconnected the PPP network failed the PPP network failed DHCP configuration failed to start DHCP configuration failed to start DHCP configuration had an error DHCP configuration had an error DHCP configuration failed DHCP configuration failed the modem is busy the router is busy there is no dial tone on the modem there is no dial tone on the modem no carrier is available on the modem no carrier is available on the router dialling the number on the modem timed out dialling the number on the router timed out dialling the number on the modem failed dialling the number on the router failed initialising the modem failed initialising the router failed APN selection failed APN selection failed the modem is not searching the router is not searching the cell tower denied registration of the modem the cell tower denied registration of the router registration of the modem on the cell tower timed out registration of the router on the cell tower timed out registration of the modem on the cell tower failed registration of the router on the cell tower failed the device firmware is missing the device firmware is missing the device was removed the device was removed the device is sleeping the device is sleeping the connection was removed the connection was removed you requested the action you requested the action the modem was not found the router was not found Bluetooth is not available Bluetooth is not available the SIM card is not inserted the SIM card is not inserted the SIM PIN is required the SIM PIN is required the SIM PUK is required the SIM PUK is required the SIM PUK is exhausted the SIM PUK is exhausted ModemManager is not operational on this device ModemManager is not operational on this device the wireless network wasn't found the wireless network wasn't found Cellular Cellular ConnectionSelectionPopover Select Connection Profile Select Connection Profile Select a connection profile to use Select a connection profile to use DevicePane ACTIONS ACTIONS Disconnect Disconnect STATUS STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. theDesk doesn't support this network interface, so you won't be able to configure it fully here. GenericChunkUpdater Connected Connected IPv4ConnectionEditorPane IPv4 IPv4 DHCP DHCP DHCP with manual DNS DHCP with manual DNS Manual Manual Shared Shared Disabled Disabled Configuration Method Configuration Method Require IPv4 Require IPv4 IP Address IP Address Default Gateway Default Gateway Subnet Length Subnet Length ADDRESSES ADDRESSES 1.1.1.1 1.1.1.1 DNS DNS Set the IP address that this device will be assigned. Set the IP address that this device will be assigned. Configure the DNS servers that will be used to resolve domain names. Configure the DNS servers that will be used to resolve domain names. For DNS server %1 For DNS server %1 Remove Remove NetworkChunk Disconnected Disconnected Login Required Login Required Can't get to the Internet Can't get to the Internet Network Settings NetworkConnectionEditor General General Connection Name Connection Name DONE? DONE? Save Save Couldn't save settings Couldn't save preferences SETTINGS MODIFIED PREFERENCES MODIFIED Revert Revert NetworkPluginCommon the device is no longer managed by NetworkManager the device is no longer managed by NetworkManager configuration of the device failed configuration of the device failed configuration of the device is unavailable configuration of the device is unavailable configuration of the device expired configuration of the device expired required secrets were not provided required secrets were not provided the authentication supplicant disconnected the authentication supplicant disconnected configuration of the authentication supplicant failed configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the authentication supplicant timed out the PPP network failed to start the PPP network failed to start the PPP network was disconnected the PPP network was disconnected the PPP network failed the PPP network failed DHCP configuration failed to start DHCP configuration failed to start DHCP configuration had an error DHCP configuration had an error DHCP configuration failed DHCP configuration failed the modem is busy the router is busy there is no dial tone on the modem there is no dial tone on the modem no carrier is available on the modem no carrier is available on the router dialling the number on the modem timed out dialling the number on the router timed out dialling the number on the modem failed dialling the number on the router failed initialising the modem failed initialising the router failed APN selection failed APN selection failed the modem is not searching the router is not searching the cell tower denied registration of the modem the cell tower denied registration of the router registration of the modem on the cell tower timed out registration of the router on the cell tower timed out registration of the modem on the cell tower failed registration of the router on the cell tower failed the device firmware is missing the device firmware is missing the device was removed the device was removed the device is sleeping the device is sleeping the connection was removed the connection was removed you requested the action you requested the action the modem was not found the router was not found Bluetooth is not available Bluetooth is not available the SIM card is not inserted the SIM card is not inserted the SIM PIN is required the SIM PIN is required the SIM PUK is required the SIM PUK is required the SIM PUK is exhausted the SIM PUK is exhausted ModemManager is not operational on this device ModemManager is not operational on this device the wireless network wasn't found the wireless network wasn't found an unknown error occurred an unknown error occurred Cellular Cellular NetworkStatusCenterLeftPane Network Network NetworkStatusCenterPane Network Network NetworkManager is not operational NetworkManager is not operational Contact your system administrator Contact your system administrator OnboardingNetwork Network Network Connect to the Internet to get updates and install new software. Next You're connected! Disconnect and connect to a different network Continue without Internet You can always set up the network connection later. SecurityEapPeap PEAP PEAP Enter the settings for this network Enter the preferences for this network CA Certificate CA Certificate Anonymous Identity Anonymous Identity Phase-2 Authentication Phase-2 Authentication MSCHAPv2 MSCHAPv2 MD5 MD5 GTC GTC Username Username Password Password Connect Connect PEAP version PEAP version Automatic Automatic Version 0 Version 0 Version 1 Version 1 Browse... Browse... Certificates (*.pem, *.cer) Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Unsupported Security Preferences Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. Sorry, theDesk doesn't support those security preferences at the moment. You can try using the terminal to configure this network. SimSettingsPopover Enable SIM PIN Enable SIM PIN Enter the current SIM PIN Enter the current SIM PIN Disable SIM PIN Disable SIM PIN Change SIM PIN Change SIM PIN You have %n remaining tries You have %n remaining try You have %n remaining tries Enter the new SIM PIN Enter the new SIM PIN Modem Settings Router Preferences SIM PIN SIM PIN IMSI IMSI IMEI IMEI MODEM INFORMATION MODEM INFORMATION Carrier Carrier No SIM card No SIM card CALLS CALLS Call Waiting Call Waiting Enable Call Waiting Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. Call Waiting allows you to receive calls while another call is currently active. Error Error Couldn't get current Call Waiting status from carrier Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Aeroplane Mode Wi-Fi Wi-Fi Cellular Cellular Switch off Flight Mode Switch off Flight Mode TetheringSettingsPopover Tethering Settings Tethering Preferences SSID SSID Network Key Network Key These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. These preferences will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network key needs to be at least 8 characters long Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN Enter the SIM PIN You have %n remaining tries You have %n remaining try You have %n remaining tries SIM PUK REQUIRED SIM PUK REQUIRED Confirm SIM PIN Confirm SIM PIN SIM PUK SIM PUK New SIM PIN New SIM PIN You'll also need to provide a new SIM PIN to set once the SIM is unlocked. You'll also need to provide a new SIM PIN to set once the SIM is unlocked. Unlock SIM Card Unlock SIM Card Don't guess the PUK! Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. WifiConnectionEditorPane Wi-Fi Wi-Fi SSID SSID Mode Mode Infrastructure Infrastructure Ad-Hoc Ad-Hoc Access Point Access Point WifiDevicePane STATUS STATUS ACTIONS ACTIONS Disconnect Disconnect Wi-Fi Wi-Fi This Device This Device Disconnected Disconnected Failed Failed Unknown Unknown 0 Devices 0 Devices Connected Connected Select Network Select Network Connection Failure Connection Failure Connecting to %1 failed because %2. Connecting to %1 failed because %2. the network the network SSID SSID Network Key Network Key Enable Tethering Enable Tethering TETHERING TETHERING Set Tethering Settings Set Tethering Preferences Couldn't configure tethering Couldn't configure tethering Tethering Tethering Active Active Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Couldn't switch off tethering Couldn't switch off tethering Wi-Fi is off Wi-Fi is off Switch Wi-Fi On Switch Wi-Fi On Wi-Fi is disabled Wi-Fi is disabled Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi on to connect to a wireless network Use the Wi-Fi switch to enable Wi-Fi and connect to a network Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode You're in aeroplane mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Switch Wi-Fi on to connect to a wireless network. Aeroplane mode won't be disabled. Disable Tethering WiredChunkUpdater Wired Wired WiredDevicePane STATUS STATUS This Device This Device ACTIONS ACTIONS Connect Connect Disconnect Disconnect Wired Wired Disconnected Disconnected Connected Connected Failed Failed Connection Failure Connection Failure Connecting to the network failed because %2. Connecting to the network failed because %2. Router Router Unavailable Unavailable Connect an Ethernet cable. Connect an Ethernet cable. This network is unavailable because %2. This network is unavailable because %2. WiredOnboardingSetup WIRED Use Wired Connection To connect to the Internet using a wired network, connect the network cable. Connect to the Internet using a wired network WirelessNetworkListDelegate In Range In Range Out of range Out of range Not Secured Not Secured Secured with Static WEP Secured with Static WEP Secured with Dynamic WEP Secured with Dynamic WEP Secured with LEAP Secured with LEAP Secured with WPA-PSK Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA2 Enterprise Connected Connected Secured with WPA3 Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network Connect to a Wireless Network KNOWN NETWORKS KNOWN NETWORKS NEW NETWORKS NEW NETWORKS New Manual Connection New Manual Connection For network %1 For network %1 Forget Network Forget Network Network Security Network Security Unknown Security Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. Not sure how to connect to this network. Use manual setup to connect to it. Enter the security key Enter the security key Select the EAP method. If you don't know what to select, contact your system administrator for the details. Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS TLS LEAP LEAP PWD PWD FAST FAST TTLS TTLS PEAP PEAP Wireless Wireless Edit Edit Connect Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/en_US.qm ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/es.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/es_VE.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/id.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/nl.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/pt_BR.ts ================================================ CellularPane STATUS STATUS This Device Este dispositivo ACTIONS AÇÕES Connect Conectar Disconnect Desconectar Modem Settings Configurações do modem Disable Cellular Desativar dados móveis Enable Cellular Ativar dados móveis Disconnected Desconectado Cellular Dados móveis Connected Conectado Failed Falha No SIM Card Nenhum cartão SIM Insert a SIM card to connect to cellular services. Insira um cartão SIM para conectar aos dados móveis. No SIM Nenhum cartão SIM Unavailable Indisponível This network is unavailable because %2. Essa rede está indisponível porque %2. Connection Failure Falha na conexão Connecting to the network failed because %2. A conexão com a rede falhou porque %2. Enter SIM PIN Insira o PIN do SIM SIM PIN Required PIN do SIM obrigatório A SIM PIN is required to connect to the cellular network. O PIN do SIM é obrigatório para conectar com os dados móveis. Enter SIM PUK Insira PUK do SIM SIM PUK Required PUK do SIM obrigatório A SIM PUK is required to connect to the cellular network. O PUK do SIM é obrigatório para conectar aos dados móveis. Common the device is no longer managed by NetworkManager o dispositivo não é mais gerido pelo NetworkManager configuration of the device failed a configuração do dispositivo falhou configuration of the device is unavailable a configuração do dispositivo está indisponível configuration of the device expired a configuração do dispositivo expirou required secrets were not provided dados secretos obrigatórios não foram fornecidos the authentication supplicant disconnected o requerente da autenticação desconectou configuration of the authentication supplicant failed a configuração do requerente da autenticação falhou the authentication supplicant failed o requerente da autenticação falhou the authentication supplicant timed out o requerente da autenticação expirou the PPP network failed to start a rede PPP não pode começar the PPP network was disconnected a rede PPP foi desconectada the PPP network failed a rede PPP falhou DHCP configuration failed to start configuração DHCP não pôde iniciar DHCP configuration had an error a configuração DHCP teve um erro DHCP configuration failed a configuração DHCP falhou the modem is busy o modem está ocupado there is no dial tone on the modem não há tom de discagem no modem no carrier is available on the modem não há operadora disponível no modem dialling the number on the modem timed out a discagem do número no modem não se efetuou a tempo dialling the number on the modem failed a discagem do número no modem falhou initialising the modem failed a inicialização do modem falhou APN selection failed a seleção de APN falhou the modem is not searching o modem não está procurando the cell tower denied registration of the modem a torre celular negou o registro do modem registration of the modem on the cell tower timed out o registro do modem na torre celular não se efetuou a tempo registration of the modem on the cell tower failed o registro do modem na torre celular falhou the device firmware is missing o firmware do dispositivo não está presente the device was removed o dispositivo foi removido the device is sleeping o dispositivo está dormindo the connection was removed a conexão foi removida you requested the action você requiriu a ação the modem was not found o modem não foi achado Bluetooth is not available O Bluetooth não está disponível the SIM card is not inserted o cartão SIM não foi inserido the SIM PIN is required o PIN do SIM é necessário the SIM PUK is required o PUK do SIM é necessário the SIM PUK is exhausted o PUK do SIM está exausto ModemManager is not operational on this device ModemManager não opera neste dispositivo the wireless network wasn't found a rede sem fio não foi encontrada an unknown error occurred ocorreu um erro desconhecido Cellular Dados móveis ConnectionSelectionPopover Select Connection Profile Selecione o perfil da conexão Select a connection profile to use Selecione um perfil de conexão DevicePane STATUS STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. theDesk não suporta esta interface de rede e, por isso, não poderá configurá-lo completamente aqui. ACTIONS AÇÕES Disconnect Desconectar GenericChunkUpdater Connected Conectado IPv4ConnectionEditorPane IPv4 IPv4 DHCP DHCP DHCP with manual DNS DHCP com DNS manual Manual Manual Shared Compartilhado Disabled Desativado Configuration Method Método de configuração Require IPv4 Exigir IPv4 IP Address Endereço IP Default Gateway Gateway padrão Subnet Length Comprimento da sub-rede ADDRESSES ENDEREÇOS Set the IP address that this device will be assigned. Defina os endereços IP que serão assinalados a este dispositivo. DNS DNS 1.1.1.1 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. Configure os servidores DNS que serão utilizados para resolver domínios. For DNS server %1 Para o servidor DNS %1 Remove Remover NetworkChunk Network Settings Configurações de rede Disconnected Desconectado Login Required Login exigido Can't get to the Internet Não foi possível o acesso à Internet NetworkConnectionEditor SETTINGS MODIFIED CONFIGURAÇÕES MODIFICADAS Revert Reverter Save Salvar DONE? PRONTO? General Geral Connection Name Nome da conexão Couldn't save settings Não foi possível salvar as configurações NetworkPluginCommon the device is no longer managed by NetworkManager o dispositivo não é mais gerido pelo NetworkManager configuration of the device failed a configuração do dispositivo falhou configuration of the device is unavailable a configuração do dispositivo está indisponível configuration of the device expired a configuração do dispositivo expirou required secrets were not provided dados secretos obrigatórios não foram fornecidos the authentication supplicant disconnected o requerente da autenticação desconectou configuration of the authentication supplicant failed a configuração do requerente da autenticação falhou the authentication supplicant failed o requerente da autenticação falhou the authentication supplicant timed out o requerente da autenticação expirou the PPP network failed to start a rede PPP não pode começar the PPP network was disconnected a rede PPP foi desconectada the PPP network failed a rede PPP falhou DHCP configuration failed to start configuração DHCP não pôde iniciar DHCP configuration had an error a configuração DHCP teve um erro DHCP configuration failed a configuração DHCP falhou the modem is busy o modem está ocupado there is no dial tone on the modem não há tom de discagem no modem no carrier is available on the modem não há operadora disponível no modem dialling the number on the modem timed out a discagem do número no modem não se efetuou a tempo dialling the number on the modem failed a discagem do número no modem falhou initialising the modem failed a inicialização do modem falhou APN selection failed a seleção de APN falhou the modem is not searching o modem não está procurando the cell tower denied registration of the modem a torre celular negou o registro do modem registration of the modem on the cell tower timed out o registro do modem na torre celular não se efetuou a tempo registration of the modem on the cell tower failed o registro do modem na torre celular falhou the device firmware is missing o firmware do dispositivo não está presente the device was removed o dispositivo foi removido the device is sleeping o dispositivo está dormindo the connection was removed a conexão foi removida you requested the action você requiriu a ação the modem was not found o modem não foi achado Bluetooth is not available O Bluetooth não está disponível the SIM card is not inserted o cartão SIM não foi inserido the SIM PIN is required o PIN do SIM é necessário the SIM PUK is required o PUK do SIM é necessário the SIM PUK is exhausted o PUK do SIM está exausto ModemManager is not operational on this device ModemManager não opera neste dispositivo the wireless network wasn't found a rede sem fio não foi encontrada an unknown error occurred ocorreu um erro desconhecido Cellular Dados móveis NetworkStatusCenterLeftPane Network Rede NetworkStatusCenterPane NetworkManager is not operational NetworkManager não está operando Contact your system administrator Entre em contato seu administrador de sistema Network Rede OnboardingNetwork Network Rede Connect to the Internet to get updates and install new software. Conecte-se à Internet para obter atualizações e instalar novo software. You're connected! Você está conectado! Disconnect and connect to a different network Desconectar e conectar a uma outra rede You can always set up the network connection later. Você pode configurar a conexão de rede depois. Continue without Internet Continuar sem acesso à Internet Next Próximo SecurityEapPeap PEAP PEAP Enter the settings for this network Insira as configurações para esta rede Phase-2 Authentication Autenticação de fase 2 (Phase-2 Authentication) Anonymous Identity Identidade anônima PEAP version Versão PEAP Username Nome de usuário Password Senha CA Certificate Certificado CA Browse... Procurar... MSCHAPv2 MSCHAPv2 MD5 MD5 GTC GTC Automatic Automático Version 0 Versão 0 Version 1 Versão 1 Connect Conectar Certificates (*.pem, *.cer) Certificados (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Configurações de segurança sem suporte Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. Desculpe, mas, por enquanto, theDesk não tem suporte para essas configurações de segurança. Você pode usar o terminal para configurar essa rede. SimSettingsPopover Modem Settings Configurações do modem SIM PIN PIN do SIM Enable SIM PIN Ativar PIN do SIM Disable SIM PIN Desativar PIN do SIM Change SIM PIN Mudar PIN do SIM CALLS CHAMADAS Call Waiting Chamada em espera IMSI IMSI IMEI IMEI MODEM INFORMATION INFORMAÇÃO DO MODEM Carrier Operadora Enter the new SIM PIN Insira o novo PIN do SIM Enter the current SIM PIN Insira o PIN do SIM atual Enable Call Waiting Ativar chamada em espera Call Waiting allows you to receive calls while another call is currently active. "Chamada em espera" permite receber chamadas enquanto outra está ativa. No SIM card Sem cartão SIM You have %n remaining tries Você tem %1 tentativa restante Você tem %1 tentativas restantes Error Erro Couldn't get current Call Waiting status from carrier Não pode receber estado de chamada em espera da operadora SwitchManager Flight Mode Modo avião Switch off Flight Mode Desligar o modo avião Wi-Fi Wi-Fi Cellular Dados móveis TetheringSettingsPopover Tethering Settings Configurações de tethering SSID SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Essas configurações serão utilizadas para configurar uma rede Wi-Fi, a qual outros dispositivos podem se conectar quando o tethering está ativado. Network Key Chave de rede Network key needs to be at least 8 characters long A chave de rede precisa ter pelo menos 8 caracteres UnlockModemPopover Enter the SIM PIN Insira o PIN do SIM SIM PUK PUK do SIM You'll also need to provide a new SIM PIN to set once the SIM is unlocked. Você também precisará de um novo PIN do SIM para definir depois que o SIM for desbloqueado. SIM PUK REQUIRED PUK DO SIM EXIGIDO Unlock SIM Card Desbloquear cartão SIM New SIM PIN Novo PIN do SIM Confirm SIM PIN Confirmar PIN do SIM Don't guess the PUK! Não tente adivinhar o PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. Após usar todas suas tentativas, esse cartão SIM será bloqueado para sempre. Você precisará entrar em contato com sua operadora para um novo cartão SIM. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. Se inserir o PIN incorreto novamente, o seu cartão SIM será bloqueado pelo PUK, e você precisará entrar em contato com a sua operadora. You have %n remaining tries Você tem %1 tentativa restante Você tem %1 tentativas restantes This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Essa é a ultima oportunidade que você tem para inserir o PUK correto. Caso errar, você precisará contatar sua operadora para obter um novo cartão SIM. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. Entre em contato com sua operadora para obter o <b>PUK do cartão SIM</b> e insira-o abaixo para desbloquear %1. WifiConnectionEditorPane Wi-Fi Wi-Fi Mode Modo SSID SSID Infrastructure Infraestrutura Ad-Hoc Ad-Hoc Access Point Ponto de acesso WifiDevicePane STATUS STATUS This Device Este dispositivo ACTIONS AÇÕES Select Network Selecione a rede Disconnect Desconectar TETHERING TETHERING Network Key Chave de rede Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Use o tethering para compartilhar sua conexão à Internet com outros dispositivos via Wi-Fi. **Enquanto o tethering está ativo, você não poderá se conectar à Internet via Wi-Fi, então certifique-se que você tem um outro modo de se conectar à Internet.** Enable Tethering Ativar tethering SSID SSID Set Tethering Settings Definir configurações de tethering Wi-Fi is off Wi-Fi está desligado Switch Wi-Fi on to connect to a wireless network Ligue o Wi-Fi para conectar a uma rede sem fio Switch Wi-Fi On Ligar Wi-Fi Wi-Fi is disabled Wi-Fi está desativado Use the Wi-Fi switch to enable Wi-Fi and connect to a network Use o interruptor de Wi-Fi e conecte a uma rede You're in flight mode Você está em modo avião Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Ligue o Wi-Fi para conectar a uma rede sem fio. O modo avião não será desativado. Tethering Tethering Disable Tethering Desativar tethering Wi-Fi Wi-Fi Disconnected Desconectado Active Ativo Connected Conectado Failed Falha Connection Failure Falha na conexão Connecting to %1 failed because %2. A conexão com %1 falhou porque %2. the network a rede 0 Devices 0 dispositivos Unknown Desconhecido Couldn't configure tethering Não foi possível configurar tethering Couldn't switch off tethering Não foi possível desligar tethering WiredChunkUpdater Wired A fio WiredDevicePane Wired A fio STATUS STATUS This Device Este dispositivo ACTIONS AÇÕES Connect Conectar Disconnect Desconectar Disconnected Desconectado Connected Conectado Failed Falha Router Roteador Unavailable Indisponível Connect an Ethernet cable. This network is unavailable because %2. Essa rede está indisponível porque %2. Connection Failure Falha na conexão Connecting to the network failed because %2. A conexão com a rede falhou porque %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected Conectado In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect Conectar WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network Selecione a rede ================================================ FILE: plugins/NetworkPlugin/translations/ro.ts ================================================ CellularPane STATUS STARE This Device Acest dispozitiv ACTIONS ACȚIUNI Connect Conectează Disconnect Deconectează Modem Settings Setări modem Disable Cellular Dezactivează datele mobile Enable Cellular Activează datele mobile Disconnected Deconectat Cellular Date mobile Connected Conectat Failed Eșuat No SIM Card Fără cartelă SIM Insert a SIM card to connect to cellular services. Introduceți o cartelă SIM pentru a vă conecta la date mobile. No SIM Fără SIM Unavailable Indisponibil This network is unavailable because %2. Această rețea este indisponibilă deoarece %2. Connection Failure Eroare la conectare Connecting to the network failed because %2. Nu s-a putut conecta la rețea, deoarece %2. Enter SIM PIN Indroduceți PIN-ul pentru cartela SIM SIM PIN Required Este necesar PIN-ul pentru cartela SIM A SIM PIN is required to connect to the cellular network. Este necesar PIN-ul cartelei pentru conectarea la rețeaua celulară. Enter SIM PUK Introduceți codul PUK al cartelei SIM SIM PUK Required Este necesar PUK-ul pentru cartela SIM A SIM PUK is required to connect to the cellular network. Codul PUK al cartelei SIM este necesar pentru conectarea la rețeaua celulară. Common the device is no longer managed by NetworkManager dispozitivul nu mai este gestionat de NetworkManager configuration of the device failed configurarea acestui dispozitiv a eșuat configuration of the device is unavailable setările dispozitivului nu sunt disponibile configuration of the device expired setările dispozitivului au expirat required secrets were not provided secretele necesare nu au fost furnizate the authentication supplicant disconnected solicitantul de autentificare s-a deconectat configuration of the authentication supplicant failed configurarea solicitantului de autentificare a eșuat the authentication supplicant failed solicitantul de autentificare a eșuat the authentication supplicant timed out solicitantul de autentificare nu a răspuns la timp the PPP network failed to start rețeaua PPP nu a putut porni the PPP network was disconnected rețeaua PPP a fost deconectată the PPP network failed rețeaua PPP a eșuat DHCP configuration failed to start configurația DHCP nu a putut porni DHCP configuration had an error a survenit o eroare la configurația DHCP DHCP configuration failed configurarea DHCP a eșuat the modem is busy modem-ul este ocupat there is no dial tone on the modem nu există un ton de apel pe modem no carrier is available on the modem nu există un operator pe modem dialling the number on the modem timed out apelarea numărului de pe modem nu a primit un răspuns la timp dialling the number on the modem failed apelarea numărului de pe modem a eșuat initialising the modem failed nu s-a putut inițializa modem-ul APN selection failed selecția unui APN a eșuat the modem is not searching modemul nu este în modul de căutare the cell tower denied registration of the modem turnul de telefonie mobilă a refuzat înregistrarea modemului registration of the modem on the cell tower timed out înregistrarea modemului la turnul de telefonie mobilă nu s-a terminat la timp registration of the modem on the cell tower failed înregistrarea modemului pe turnul de telefonie mobilă a eșuat the device firmware is missing firmware-ul dispozitivului lipsește the device was removed dispozitivul a fost scos the device is sleeping dispozitivul este în adormire the connection was removed conexiunea a fost înlăturată you requested the action ați solicitat anularea the modem was not found modemul nu a fost găsit Bluetooth is not available Bluetooth nu este disponibil the SIM card is not inserted cartela SIM nu este inserată the SIM PIN is required PIN-ul de la SIM este necesar the SIM PUK is required PUK-ul de la SIM este necesar the SIM PUK is exhausted PUK-ul cartelei a fost folosit de prea multe ori ModemManager is not operational on this device ModemManager nu este funcțional pe acest dispozitiv the wireless network wasn't found rețeaua wireless nu a fost găsită an unknown error occurred a survenit o eroare necunoscută Cellular Date mobile ConnectionSelectionPopover Select Connection Profile Selectați profilul de conexiune Select a connection profile to use Selectați profilul de conexiune pe care doriți să-l folosiți DevicePane STATUS STARE theDesk doesn't support this network interface, so you won't be able to configure it fully here. Această interfață de rețea nu poate fi configurată în totalitate aici, deoarece nu este suportată de theDesk. ACTIONS ACȚIUNI Disconnect Deconectare GenericChunkUpdater Connected Conectat IPv4ConnectionEditorPane IPv4 IPv4 DHCP DHCP DHCP with manual DNS DHCP cu DNS manual Manual Manual Shared Partajat Disabled Dezactivat Configuration Method Metodă de configurare Require IPv4 Necesită IPv4 IP Address Adresa IP Default Gateway Gateway-ul implicit Subnet Length Lungimea de subnet ADDRESSES ADRESE Set the IP address that this device will be assigned. Setați adresa IP care va fi atribuită acestui dispozitiv. DNS DNS 1.1.1.1 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. Configurați serverele DNS care vor fi folosite să proceseze numele de domeniu. For DNS server %1 Pentru serverul DNS %1 Remove Elimină NetworkChunk Network Settings Disconnected Deconectat Login Required Autentificare necesară Can't get to the Internet Nu se poate conecta la internet NetworkConnectionEditor SETTINGS MODIFIED SETĂRI MODIFICATE Revert Restabilește Save Salvează DONE? GATA? General General Connection Name Numele conexiunii Couldn't save settings Nu au putut fi salvate setările NetworkPluginCommon the device is no longer managed by NetworkManager dispozitivul nu mai este gestionat de NetworkManager configuration of the device failed configurarea acestui dispozitiv a eșuat configuration of the device is unavailable setările dispozitivului nu sunt disponibile configuration of the device expired setările dispozitivului au expirat required secrets were not provided secretele necesare nu au fost furnizate the authentication supplicant disconnected solicitantul de autentificare s-a deconectat configuration of the authentication supplicant failed configurarea solicitantului de autentificare a eșuat the authentication supplicant failed solicitantul de autentificare a eșuat the authentication supplicant timed out solicitantul de autentificare nu a răspuns la timp the PPP network failed to start rețeaua PPP nu a putut porni the PPP network was disconnected rețeaua PPP a fost deconectată the PPP network failed rețeaua PPP a eșuat DHCP configuration failed to start configurația DHCP nu a putut porni DHCP configuration had an error a survenit o eroare la configurația DHCP DHCP configuration failed configurarea DHCP a eșuat the modem is busy modem-ul este ocupat there is no dial tone on the modem nu există un ton de apel pe modem no carrier is available on the modem nu există un operator pe modem dialling the number on the modem timed out apelarea numărului de pe modem nu a primit un răspuns la timp dialling the number on the modem failed apelarea numărului de pe modem a eșuat initialising the modem failed nu s-a putut inițializa modem-ul APN selection failed selecția unui APN a eșuat the modem is not searching modemul nu este în modul de căutare the cell tower denied registration of the modem turnul de telefonie mobilă a refuzat înregistrarea modemului registration of the modem on the cell tower timed out înregistrarea modemului la turnul de telefonie mobilă nu s-a terminat la timp registration of the modem on the cell tower failed înregistrarea modemului pe turnul de telefonie mobilă a eșuat the device firmware is missing firmware-ul dispozitivului lipsește the device was removed dispozitivul a fost scos the device is sleeping dispozitivul este în adormire the connection was removed conexiunea a fost înlăturată you requested the action ați solicitat anularea the modem was not found modemul nu a fost găsit Bluetooth is not available Bluetooth nu este disponibil the SIM card is not inserted cartela SIM nu este inserată the SIM PIN is required PIN-ul de la SIM este necesar the SIM PUK is required PUK-ul de la SIM este necesar the SIM PUK is exhausted PUK-ul cartelei a fost folosit de prea multe ori ModemManager is not operational on this device ModemManager nu este funcțional pe acest dispozitiv the wireless network wasn't found rețeaua wireless nu a fost găsită an unknown error occurred a survenit o eroare necunoscută Cellular Date mobile NetworkStatusCenterLeftPane Network Rețea NetworkStatusCenterPane NetworkManager is not operational Serviciul NetworkManager nu este operațional Contact your system administrator Contactați-vă administratorul de sistem Network Rețea OnboardingNetwork Network Rețea Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP PEAP Enter the settings for this network Completați setările pentru această rețea Phase-2 Authentication Autentificare Phase-2 Anonymous Identity Identitate anonimă PEAP version Versiunea PEAP Username Nume de utilizator Password Parolă CA Certificate Certificat CA Browse... Răsfoiește... MSCHAPv2 MSCHAPv2 MD5 MD5 GTC GTC Automatic Automat Version 0 Versiunea 0 Version 1 Versiunea 1 Connect Conectare Certificates (*.pem, *.cer) Certificate (*.pem,*.cer) SecurityEapUnsupported Unsupported Security Settings Setări de securitate nesuportate Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. Ne pare rău, theDesk nu suportă acele setări de securitate la acest moment. Puteți folosi terminalul pentru a configura această rețea. SimSettingsPopover Modem Settings Setări modem SIM PIN PIN cartelă Enable SIM PIN Activează PIN pentru cartelă Disable SIM PIN Dezactivează PIN pentru cartelă Change SIM PIN Schimbă PIN-ul cartelei CALLS APELURI Call Waiting Apel în așteptare IMSI IMSI IMEI IMEI MODEM INFORMATION INFORMAȚII DESPRE MODEM Carrier Operator Enter the new SIM PIN Introduceți noul PIN pentru SIM Enter the current SIM PIN Introduceți PIN-ul cartelei curent Enable Call Waiting Activează apeluri în așteptare Call Waiting allows you to receive calls while another call is currently active. Apeluri în așteptare vă permite să primiți apeluri în timp ce un alt apel este activ. No SIM card Fără cartelă SIM You have %n remaining tries Mai aveți o încercare Mai aveți %n încercări Mai aveți %n încercări Error Eroare Couldn't get current Call Waiting status from carrier Nu s-a putut obține starea funcției apeluri în așteptare de la operator SwitchManager Flight Mode Mod avion Switch off Flight Mode Oprește modul avion Wi-Fi Wi-Fi Cellular Date mobile TetheringSettingsPopover Tethering Settings Setări pentru Tethering SSID SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Aceste setări vor fi folosite pentru a configura o rețea Wi-Fi la care alte dispozitive se pot conecta cât timp tethering-ul este activat. Network Key Cheie de rețea Network key needs to be at least 8 characters long Cheia de rețea trebuie să aibă minim 8 caractere UnlockModemPopover Enter the SIM PIN Introduceți PIN-ul de la SIM SIM PUK PUK de la cartela SIM You'll also need to provide a new SIM PIN to set once the SIM is unlocked. Va trebui să furnizați un nou pin pentru SIM atunci când SIM-ul va fi deblocat. SIM PUK REQUIRED PUK-ul este necesar Unlock SIM Card Deblochează cartela SIM New SIM PIN PIN nou Confirm SIM PIN Confirmă PIN-ul Don't guess the PUK! Nu ghici codul PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. După ce se vor termina încercările, cartela SIM va fi blocată pe viață Va trebui să luați legătura cu operatorul de telefonie mobilă pentru o nouă cartelă SIM. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. Dacă mi introduceți PIN-ul greșit încă o dată, cartela dumneavoastră SIM va fi blocată PUK și va trebui să vă contactați operatorul de telefonie mobilă. You have %n remaining tries Mai aveți o încercare Mai aveți %n încercări Mai aveți %n încercări This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Aceasta este ultima șansă de a introduce codul PUK corect înainte de a obține un nou SIM de la operatorul dvs. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. Contactați-vă operatorul pentru a obține <b>CODUL PUK</b>, apoi introduceți-l mai jos pentru a debloca %1. WifiConnectionEditorPane Wi-Fi Wi-Fi Mode Mod SSID SSID Infrastructure Infrastructură Ad-Hoc Ad-Hoc Access Point Punct de acces WifiDevicePane STATUS STARE This Device Acest dispozitiv ACTIONS ACȚIUNI Select Network Selectați rețeaua Disconnect Deconectare TETHERING TETHERING Network Key Cheie de rețea Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Folosiți tethering pentru a vă partaja conexiunea cu alte dispozitive prin Wi-Fi **Cât timp tethering-ul este activ, nu vă veți putea conecta la internet prin Wi-Fi, deci fiți sigur că aveți o variantă alternativă pentru a vă conecta la internet.** Enable Tethering Activați tethering SSID SSID Set Tethering Settings Configurați tethering Wi-Fi is off Wi-Fi-ul este oprit Switch Wi-Fi on to connect to a wireless network Porniți Wi-Fi-ul pentru a vă conecta la o rețea fără fir Switch Wi-Fi On Activați Wi-Fi Wi-Fi is disabled Wi-Fi-ul este dezactivat Use the Wi-Fi switch to enable Wi-Fi and connect to a network Folosiți acest buton pentru a activa Wi-Fi și pentru a vă conecta la o rețea You're in flight mode Sunteți pe mod avion Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Activați Wi-Fi pentru a vă conecta la o rețea wireless. Modul avion nu va fi dezactivat. Tethering Tethering Disable Tethering Dezactivați tethering Wi-Fi Wi-Fi Disconnected Deconectat Active Activ Connected Conectat Failed Eșuat Connection Failure Eroare la conexiune Connecting to %1 failed because %2. Conectarea la rețeaua %1 a eșuat, deoarece %2. the network rețeaua 0 Devices 0 dispozitive Unknown Necunoscut Couldn't configure tethering Nu s-a putut configura tethering-ul Couldn't switch off tethering Nu s-a putut opri tethering-ul WiredChunkUpdater Wired Pe fir WiredDevicePane Wired Pe fir STATUS STARE This Device Acest dispozitiv ACTIONS ACȚIUNI Connect Conectare Disconnect Deconectare Disconnected Deconectat Connected Conectat Failed Eșuat Router Ruter Unavailable Indisponibil Connect an Ethernet cable. Conectați un cablu Ethernet. This network is unavailable because %2. Rețeaua este indisponibilă, deoarece %2. Connection Failure Eroare de conexiune Connecting to the network failed because %2. Conectarea la rețea a eșuat, deoarece %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected Conectat In Range În aria de acoperire Out of range În afara ariei de acoperire Not Secured Nesecurizat Secured with Static WEP Securizat cu WEP static Secured with Dynamic WEP Securizat cu WEP dinamic Secured with LEAP Securizat cu LEAP Secured with WPA-PSK Securizat cu WPA-PSK Secured with WPA Enterprise Securizat cu WPA-Enterprise Secured with WPA2-PSK Securizat cu WPA2-PSK Secured with WPA2 Enterprise Securizat cu WPA2-Enterprise Secured with WPA3 Securizat cu WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network Conectați-vă la o rețea wireless KNOWN NETWORKS REȚELE CUNOSCUTE NEW NETWORKS REȚELE NOI New Manual Connection Crează o conexiune manual Enter the security key Introduceți cheia de securitate Network Security Securitatea rețelei Select the EAP method. If you don't know what to select, contact your system administrator for the details. Selectați metoda EAP. Dacă nu știți ce să selectați, contactați-vă administratorul de sistem pentru mai multe detalii. TLS TLS LEAP LEAP PWD PWD FAST FAST TTLS TTLS PEAP PEAP Unknown Security Securitate necunoscută Not sure how to connect to this network. Use manual setup to connect to it. Nu suntem siguri cum să ne conectăm la această rețea. Folosiți configurarea manuală pentru a vă conecta. For network %1 Pentru rețeaua %1 Edit Editare Forget Network Uită rețeaua Wireless Fără fir Connect Conectare WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network Selectați rețeaua ================================================ FILE: plugins/NetworkPlugin/translations/sv.ts ================================================ CellularPane STATUS This Device ACTIONS Connect Disconnect Modem Settings Disable Cellular Enable Cellular Disconnected Cellular Connected Failed No SIM Card Insert a SIM card to connect to cellular services. No SIM Unavailable This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. Enter SIM PIN SIM PIN Required A SIM PIN is required to connect to the cellular network. Enter SIM PUK SIM PUK Required A SIM PUK is required to connect to the cellular network. Common the device is no longer managed by NetworkManager configuration of the device failed configuration of the device is unavailable configuration of the device expired required secrets were not provided the authentication supplicant disconnected configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start the PPP network was disconnected the PPP network failed DHCP configuration failed to start DHCP configuration had an error DHCP configuration failed the modem is busy there is no dial tone on the modem no carrier is available on the modem dialling the number on the modem timed out dialling the number on the modem failed initialising the modem failed APN selection failed the modem is not searching the cell tower denied registration of the modem registration of the modem on the cell tower timed out registration of the modem on the cell tower failed the device firmware is missing the device was removed the device is sleeping the connection was removed you requested the action the modem was not found Bluetooth is not available the SIM card is not inserted the SIM PIN is required the SIM PUK is required the SIM PUK is exhausted ModemManager is not operational on this device the wireless network wasn't found an unknown error occurred Cellular ConnectionSelectionPopover Select Connection Profile Select a connection profile to use DevicePane STATUS theDesk doesn't support this network interface, so you won't be able to configure it fully here. ACTIONS Disconnect GenericChunkUpdater Connected IPv4ConnectionEditorPane IPv4 DHCP DHCP with manual DNS Manual Shared Disabled Configuration Method Require IPv4 IP Address Default Gateway Subnet Length ADDRESSES Set the IP address that this device will be assigned. DNS 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. For DNS server %1 Remove NetworkChunk Network Settings Disconnected Login Required Can't get to the Internet NetworkConnectionEditor SETTINGS MODIFIED Revert Save DONE? General Connection Name Couldn't save settings NetworkStatusCenterLeftPane Network NetworkStatusCenterPane NetworkManager is not operational Contact your system administrator Network OnboardingNetwork Network Connect to the Internet to get updates and install new software. You're connected! Disconnect and connect to a different network You can always set up the network connection later. Continue without Internet Next SecurityEapPeap PEAP Enter the settings for this network Phase-2 Authentication Anonymous Identity PEAP version Username Password CA Certificate Browse... MSCHAPv2 MD5 GTC Automatic Version 0 Version 1 Connect Certificates (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. SimSettingsPopover Modem Settings SIM PIN Enable SIM PIN Disable SIM PIN Change SIM PIN CALLS Call Waiting IMSI IMEI MODEM INFORMATION Carrier Enter the new SIM PIN Enter the current SIM PIN Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. No SIM card You have %n remaining tries Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode Switch off Flight Mode Wi-Fi Cellular TetheringSettingsPopover Tethering Settings SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network Key Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. SIM PUK REQUIRED Unlock SIM Card New SIM PIN Confirm SIM PIN Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. You have %n remaining tries This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. WifiConnectionEditorPane Wi-Fi Mode SSID Infrastructure Ad-Hoc Access Point WifiDevicePane STATUS This Device ACTIONS Select Network Disconnect TETHERING Network Key Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Enable Tethering SSID Set Tethering Settings Wi-Fi is off Switch Wi-Fi on to connect to a wireless network Switch Wi-Fi On Wi-Fi is disabled Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Tethering Disable Tethering Wi-Fi Disconnected Active Connected Failed Connection Failure Connecting to %1 failed because %2. the network 0 Devices Unknown Couldn't configure tethering Couldn't switch off tethering WiredChunkUpdater Wired WiredDevicePane Wired STATUS This Device ACTIONS Connect Disconnect Disconnected Connected Failed Router Unavailable Connect an Ethernet cable. This network is unavailable because %2. Connection Failure Connecting to the network failed because %2. WiredOnboardingSetup WIRED Use Wired Connection Connect to the Internet using a wired network To connect to the Internet using a wired network, connect the network cable. WirelessNetworkListDelegate Connected In Range Out of range Not Secured Secured with Static WEP Secured with Dynamic WEP Secured with LEAP Secured with WPA-PSK Secured with WPA Enterprise Secured with WPA2-PSK Secured with WPA2 Enterprise Secured with WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network KNOWN NETWORKS NEW NETWORKS New Manual Connection Enter the security key Network Security Select the EAP method. If you don't know what to select, contact your system administrator for the details. TLS LEAP PWD FAST TTLS PEAP Unknown Security Not sure how to connect to this network. Use manual setup to connect to it. For network %1 Edit Forget Network Wireless Connect WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network ================================================ FILE: plugins/NetworkPlugin/translations/tr_TR.ts ================================================ CellularPane STATUS DURUM This Device Bu Cihaz ACTIONS HAREKETLER Connect Bağlan Disconnect Bağlantıyı kes Cellular Hücresel Disconnected Bağlantı kesildi Connected Bağlandı Failed Yanlış oldu Unavailable Kullanım dışı This network is unavailable because %2. Bu ağ kullanılamıyor çünkü %2. Connection Failure Bağlantı hatası Connecting to the network failed because %2. Ağa bağlanma başarısız oldu çünkü %2. Enter SIM PIN SIM PIN kodunu girin SIM PIN Required SIM PIN Gerekli Enter SIM PUK SIM PUK'unu girin SIM PUK Required SIM PUK Gerekli A SIM PIN is required to connect to the cellular network. Hücresel ağa bağlanmak için bir SIM PIN kodu gerekir. A SIM PUK is required to connect to the cellular network. Hücresel ağa bağlanmak için bir SIM PUK gereklidir. Modem Settings Modem Ayarları Disable Cellular Hücresel Bağlantıyı Devre Dışı Bırak Enable Cellular Hücresel'i etkinleştir No SIM Card SIM Kart Yok Insert a SIM card to connect to cellular services. Hücresel hizmetlere bağlanmak için bir SIM kart takın. No SIM SIM yok Common an unknown error occurred bilinmeyen bir hata oluştu the device is no longer managed by NetworkManager cihaz artık NetworkManager tarafından yönetilmiyor configuration of the device failed cihazın konfigürasyonu başarısız oldu configuration of the device is unavailable cihazın konfigürasyonu mevcut değil configuration of the device expired cihazın konfigürasyonunun süresi doldu required secrets were not provided gerekli sırlar sağlanmadı the authentication supplicant disconnected kimlik doğrulama istemcisinin bağlantısı kesildi configuration of the authentication supplicant failed kimlik doğrulama istemcisinin yapılandırması başarısız oldu the authentication supplicant failed kimlik doğrulama isteği başarısız oldu the authentication supplicant timed out kimlik doğrulama isteği zaman aşımına uğradı the PPP network failed to start PPP ağı başlatılamadı the PPP network was disconnected PPP ağının bağlantısı kesildi the PPP network failed PPP ağı başarısız oldu DHCP configuration failed to start DHCP yapılandırması başlatılamadı DHCP configuration had an error DHCP yapılandırmasında bir hata vardı DHCP configuration failed DHCP yapılandırması başarısız oldu the modem is busy modem meşgul there is no dial tone on the modem modemde çevir sesi yok no carrier is available on the modem modemde taşıyıcı yok dialling the number on the modem timed out modemdeki numaranın çevrilmesi zaman aşımına uğradı dialling the number on the modem failed modemdeki numarayı çevirme başarısız oldu initialising the modem failed modemi başlatmak başarısız oldu APN selection failed APN seçimi başarısız oldu the modem is not searching modem aramıyor the cell tower denied registration of the modem baz istasyonu modemin kaydını reddetti registration of the modem on the cell tower timed out modemin baz istasyonuna kaydı zaman aşımına uğradı registration of the modem on the cell tower failed modemin baz istasyonuna kaydı başarısız oldu the device firmware is missing cihaz donanım yazılımı eksik the device was removed cihaz kaldırıldı the device is sleeping cihaz uyuyor the connection was removed bağlantı kaldırıldı you requested the action eylemi sen istedin the modem was not found modem bulunamadı Bluetooth is not available Bluetooth kullanılamıyor the SIM card is not inserted SIM kart takılı değil the SIM PIN is required SIM PIN kodu gerekli the SIM PUK is required SIM PUK gereklidir the SIM PUK is exhausted SIM PUK tükendi ModemManager is not operational on this device ModemManager bu cihazda çalışmıyor the wireless network wasn't found kablosuz ağ bulunamadı Cellular Hücresel ConnectionSelectionPopover Select Connection Profile Bağlantı Profilini Seçin Select a connection profile to use Kullanmak için bir bağlantı profili seçin DevicePane ACTIONS HAREKETLER Disconnect Bağlantıyı kes STATUS DURUM theDesk doesn't support this network interface, so you won't be able to configure it fully here. theDesk bu ağ arayüzünü desteklemez, bu nedenle burada tam olarak yapılandıramazsınız. GenericChunkUpdater Connected Bağlandı IPv4ConnectionEditorPane IPv4 IPv4 DHCP DHCP DHCP with manual DNS Manuel DNS ile DHCP Manual Manuel Shared Paylaşılan Disabled Sakat Configuration Method Yapılandırma Yöntemi Require IPv4 IPv4 gerektir IP Address IP adresi Default Gateway Varsayılan giriş Subnet Length Alt Ağ Uzunluğu ADDRESSES ADRESLER 1.1.1.1 1.1.1.1 DNS DNS Set the IP address that this device will be assigned. Bu cihazın atanacağı IP adresini ayarlayın. Configure the DNS servers that will be used to resolve domain names. Etki alanı adlarını çözümlemek için kullanılacak DNS sunucularını yapılandırın. For DNS server %1 DNS sunucusu %1 için Remove Sil NetworkChunk Disconnected Bağlantı kesildi Login Required Oturum açmak gereklidir Can't get to the Internet İnternete ulaşamıyor Network Settings NetworkConnectionEditor General Genel Connection Name Bağlantı adı DONE? BİTİRDİN Mİ? Save Kaydet Couldn't save settings Ayarlar kaydedilemedi SETTINGS MODIFIED DEĞİŞTİRİLEN AYARLAR Revert Geri döndür NetworkPluginCommon the device is no longer managed by NetworkManager cihaz artık NetworkManager tarafından yönetilmiyor configuration of the device failed cihazın konfigürasyonu başarısız oldu configuration of the device is unavailable cihazın konfigürasyonu mevcut değil configuration of the device expired cihazın konfigürasyonunun süresi doldu required secrets were not provided gerekli sırlar sağlanmadı the authentication supplicant disconnected kimlik doğrulama istemcisinin bağlantısı kesildi configuration of the authentication supplicant failed kimlik doğrulama istemcisinin yapılandırması başarısız oldu the authentication supplicant failed kimlik doğrulama isteği başarısız oldu the authentication supplicant timed out kimlik doğrulama isteği zaman aşımına uğradı the PPP network failed to start PPP ağı başlatılamadı the PPP network was disconnected PPP ağının bağlantısı kesildi the PPP network failed PPP ağı başarısız oldu DHCP configuration failed to start DHCP yapılandırması başlatılamadı DHCP configuration had an error DHCP yapılandırmasında bir hata vardı DHCP configuration failed DHCP yapılandırması başarısız oldu the modem is busy modem meşgul there is no dial tone on the modem modemde çevir sesi yok no carrier is available on the modem modemde taşıyıcı yok dialling the number on the modem timed out modemdeki numaranın çevrilmesi zaman aşımına uğradı dialling the number on the modem failed modemdeki numarayı çevirme başarısız oldu initialising the modem failed modemi başlatmak başarısız oldu APN selection failed APN seçimi başarısız oldu the modem is not searching modem aramıyor the cell tower denied registration of the modem baz istasyonu modemin kaydını reddetti registration of the modem on the cell tower timed out modemin baz istasyonuna kaydı zaman aşımına uğradı registration of the modem on the cell tower failed modemin baz istasyonuna kaydı başarısız oldu the device firmware is missing cihaz donanım yazılımı eksik the device was removed cihaz kaldırıldı the device is sleeping cihaz uyuyor the connection was removed bağlantı kaldırıldı you requested the action eylemi sen istedin the modem was not found modem bulunamadı Bluetooth is not available Bluetooth kullanılamıyor the SIM card is not inserted SIM kart takılı değil the SIM PIN is required SIM PIN kodu gerekli the SIM PUK is required SIM PUK gereklidir the SIM PUK is exhausted SIM PUK tükendi ModemManager is not operational on this device ModemManager bu cihazda çalışmıyor the wireless network wasn't found kablosuz ağ bulunamadı an unknown error occurred bilinmeyen bir hata oluştu Cellular Hücresel NetworkStatusCenterLeftPane Network NetworkStatusCenterPane Network NetworkManager is not operational NetworkManager çalışmıyor Contact your system administrator Sistem yöneticinizle iletişime geçin OnboardingNetwork Network Connect to the Internet to get updates and install new software. Next You're connected! Disconnect and connect to a different network Continue without Internet You can always set up the network connection later. SecurityEapPeap PEAP PEAP Enter the settings for this network Bu ağ için ayarları girin CA Certificate CA Sertifikası Anonymous Identity Anonim Kimlik Phase-2 Authentication 2. Aşama Kimlik Doğrulaması MSCHAPv2 MSCHAPv2 MD5 MD5 GTC GTC Username Kullanıcı adı Password Şifre Connect Bağlan PEAP version PEAP versiyonu Automatic Otomatik Version 0 Sürüm 0 Version 1 Versiyon 1 Browse... Araştır... Certificates (*.pem, *.cer) Sertifikalar (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Desteklenmeyen Güvenlik Ayarları Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. Üzgünüz, theDesk şu anda bu güvenlik ayarlarını desteklemiyor. Bu ağı yapılandırmak için theTerminal kullanmayı deneyebilirsiniz. SimSettingsPopover Enable SIM PIN SIM PIN'ini etkinleştir Enter the current SIM PIN Mevcut SIM PIN kodunu girin Disable SIM PIN SIM PIN'ini devre dışı bırak Change SIM PIN SIM PIN kodunu değiştir You have %n remaining tries %n deneme hakkınız kaldı Enter the new SIM PIN Yeni SIM PIN kodunu girin Modem Settings Modem Ayarları SIM PIN SIM PIN IMSI IMSI IMEI IMEI MODEM INFORMATION MODEM BİLGİLERİ Carrier Taşımacı No SIM card SIM Kart Yok CALLS ARAMALAR Call Waiting Görüşme beklemede Enable Call Waiting Çağrı Bekletmeyi Etkinleştir Call Waiting allows you to receive calls while another call is currently active. Çağrı Bekletme, o anda başka bir çağrı etkinken çağrı almanıza olanak tanır. Error Hata Couldn't get current Call Waiting status from carrier Operatörden mevcut Çağrı Bekletme durumu alınamadı SwitchManager Flight Mode Uçuş modu Wi-Fi Wi-Fi Cellular Hücresel Switch off Flight Mode Uçuş modunu kapatın TetheringSettingsPopover Tethering Settings Bağlama Ayarları SSID SSID Network Key Ağ Şifre These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Bu ayarlar, bağlama etkinleştirildiğinde diğer cihazların bağlanabileceği bir Wi-Fi ağı kurmak için kullanılacaktır. Network key needs to be at least 8 characters long Ağ şifresi en az 8 karakter uzunluğunda olmalıdır UnlockModemPopover Enter the SIM PIN SIM PIN kodunu girin You have %n remaining tries %n deneme hakkınız kaldı SIM PUK REQUIRED SIM PUK GEREKLİ Confirm SIM PIN SIM PIN'ini onaylayın SIM PUK SIM PUK New SIM PIN Yeni SIM PIN kodu You'll also need to provide a new SIM PIN to set once the SIM is unlocked. Ayrıca, SIM kilidi açıldığında ayarlamak için yeni bir SIM PIN kodu sağlamanız gerekir. Unlock SIM Card SIM Kartın Kilidini Açın Don't guess the PUK! PUK'u tahmin etmeyin! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. Denemelerinizi tükettiğinizde, SIM kart sonsuza kadar bloke olacaktır. Yeni bir SIM kart için operatörünüze başvurmanız gerekecek. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. <b>SIM PUK</b> almak için operatörünüze başvurun ve %1'in kilidini açmak için aşağıya girin. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. Yanlış PIN kodunu tekrar girerseniz, SIM kartınız PUK ile kilitlenir ve operatörünüze başvurmanız gerekir. This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Bu, operatörünüzden yeni bir SIM kart almanız gerekmeden önce PUK'U almak için son şansınız. WifiConnectionEditorPane Wi-Fi Wi-Fi SSID SSID Mode Mod Infrastructure Altyapı Ad-Hoc Özel Access Point Yönlendirici WifiDevicePane STATUS DURUM ACTIONS HAREKETLER Disconnect Bağlantıyı kes Wi-Fi Wi-Fi This Device Bu Cihaz Disconnected Bağlantı kesildi Failed Yanlış oldu Unknown Bilinmeyen 0 Devices 0 Cihazler Connected Bağlandı Select Network Ağ Seçin Connection Failure Bağlantı Hatası Connecting to %1 failed because %2. %1 bağlantısı başarısız oldu çünkü %2. the network SSID SSID Network Key Ağ Çözüm Enable Tethering Tethering'i Etkinleştir TETHERING TETHERING Set Tethering Settings İnternet Bağlantısı Ayarlarını Yapın Couldn't configure tethering Tethering yapılandırılamadı Tethering İnternet paylaşımı Active Aktif Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** İnternet bağlantınızı Wi-Fi üzerinden diğer cihazlarla paylaşmak için Tethering'i kullanın. ** Tethering etkinken, Wi-Fi ile İnternet'e bağlanamayacaksınız, bu nedenle İnternet'e bağlanmak için alternatif bir yolunuz olduğundan emin olmanız gerekir. ** Couldn't switch off tethering İnternet paylaşımı kapatılamadı Wi-Fi is off Wi-Fi kapalı Switch Wi-Fi On Wi-Fi'yi Aç Wi-Fi is disabled Wi-Fi devre dışı bırakılır Switch Wi-Fi on to connect to a wireless network Kablosuz ağa bağlanmak için Wi-Fi'yi açın Use the Wi-Fi switch to enable Wi-Fi and connect to a network Wi-Fi'yi etkinleştirmek ve bir ağa bağlanmak için Wi-Fi anahtarını kullanın You're in flight mode Uçuş modundasın Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Bir kablosuz ağa bağlanmak için Wi-Fi'yi açın. Uçuş modu devre dışı bırakılmayacak. Disable Tethering Tethering'i Devre Dışı Bırak WiredChunkUpdater Wired Kablolu WiredDevicePane STATUS DURUM This Device Bu Cihaz ACTIONS HAREKETLER Connect Bağlan Disconnect Bağlantıyı kes Wired Kablolu Disconnected Bağlantı kesildi Connected Bağlandı Failed Yanlış oldu Connection Failure Bağlantı Hatası Connecting to the network failed because %2. Ağa bağlanma başarısız oldu çünkü %2. Router Yönlendirici Unavailable Kullanım dışı Connect an Ethernet cable. Bir Ethernet kablosu bağlayın. This network is unavailable because %2. Bu ağ kullanılamıyor çünkü %2. WiredOnboardingSetup WIRED Use Wired Connection To connect to the Internet using a wired network, connect the network cable. Connect to the Internet using a wired network WirelessNetworkListDelegate In Range Aralıkta Out of range Menzil dışında Not Secured Güvenli Değil Secured with Static WEP Statik WEP ile güvenlik altına alındı Secured with Dynamic WEP Dinamik WEP ile güvenlik altına alındı Secured with LEAP LEAP ile güvenlik altına alındı Secured with WPA-PSK WPA-PSK ile güvenlik altına alındı Secured with WPA Enterprise WPA Enterprise ile güvenlik altına alındı Secured with WPA2-PSK WPA2-PSK ile güvenlik altına alındı Secured with WPA2 Enterprise WPA2 Enterprise ile güvenlik altına alındı Connected Bağlandı Secured with WPA3 WPA3 ile güvenlik altına alındı WirelessNetworkSelectionPopover Connect to a Wireless Network Bir Kablosuz Ağa Bağlanın KNOWN NETWORKS BİLİNEN AĞLAR NEW NETWORKS YENİ AĞLAR New Manual Connection Yeni Manuel Bağlantı For network %1 Ağ 1% için Forget Network Ağı Unut Network Security Ağ güvenliği Unknown Security Bilinmeyen Güvenlik Not sure how to connect to this network. Use manual setup to connect to it. Bu ağa nasıl bağlanacağınızdan emin değilim. Bağlanmak için manuel kurulumu kullanın. Enter the security key Güvenlik anahtarını girin Select the EAP method. If you don't know what to select, contact your system administrator for the details. EAP yöntemini seçin. Neyi seçeceğinizi bilmiyorsanız, ayrıntılar için sistem yöneticinize başvurun. TLS TLS LEAP LEAP PWD PWD FAST HIZLI TTLS TTLS PEAP PEAP Wireless Kablosuz Edit Düzenle Connect Bağlan WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network Ağ Seçin ================================================ FILE: plugins/NetworkPlugin/translations/vi.ts ================================================ CellularPane STATUS TRẠNG THÁI This Device Thiết bị này ACTIONS HOẠT ĐỘNG Connect Kết nối Disconnect Ngắt kết nối Modem Settings Cài đặt modem Disable Cellular Tắt mạng di động Enable Cellular Bật mạng di động Disconnected Không kết nối Cellular Mạng di động Connected Đã kết nối Failed Đã thất bại No SIM Card Không có thẻ SIM Insert a SIM card to connect to cellular services. Cài một thẻ SIM để kết nối với dịch vụ di động. No SIM Không có SIM Unavailable Không có sẵn This network is unavailable because %2. Mạng này không có sẵn tại vì %2. Connection Failure Kết nối thất bại Connecting to the network failed because %2. Kết nối với mạng thất bại tại vì %2. Enter SIM PIN Điền vào SIM PIN SIM PIN Required Cần SIM PIN A SIM PIN is required to connect to the cellular network. Cần mã PIN cho thẻ SIM để kết nối với mạng di động. Enter SIM PUK Điền vào SIM PUK SIM PUK Required Cần SIM PUK A SIM PUK is required to connect to the cellular network. Cần mã PUK cho thẻ SIM để kết nối với mạng di động. Common the device is no longer managed by NetworkManager thiết bị này không có quản lý với NetworkManager nũa configuration of the device failed cấu hình thiết bị không thành công configuration of the device is unavailable cấu hình thiết bị không có sẵn configuration of the device expired cấu hình thiết bị hết hạn required secrets were not provided những bí mật không được cung cấp the authentication supplicant disconnected trình xác thực bị ngắt kết nối configuration of the authentication supplicant failed cấu hình trình xác thực không thành công the authentication supplicant failed trình xác thực không thành công the authentication supplicant timed out trình xác thực hết giờ the PPP network failed to start mạng PPP không khởi chạy được the PPP network was disconnected mạng PPP bị ngắt kết nối the PPP network failed mạng PPP không thành công DHCP configuration failed to start cấu hình DHCP không thể bắt đầu DHCP configuration had an error cấu hình DHCP xảy ra lỗi DHCP configuration failed cấu hình DHCP không thành công the modem is busy modem đang bận there is no dial tone on the modem không có âm quay số trên modem no carrier is available on the modem không có âm cung cấp trên modem dialling the number on the modem timed out quay số trên modem mất quá nhiều thời gian dialling the number on the modem failed quay số trên modem không thành công initialising the modem failed khởi tạo modem không thành công APN selection failed hoạt động chọn APN không thành công the modem is not searching modem không tìm kiếm the cell tower denied registration of the modem tháp di động từ chối chi tiết đăng ký của modem registration of the modem on the cell tower timed out hoạt động đăng ký modem trên tháp di động mất quá nhiều thời gian registration of the modem on the cell tower failed hoạt động đăng ký modem trên tháp di động không thành công the device firmware is missing thiếu phần sụn thiết bị the device was removed thiết bị bị tháo ra the device is sleeping thiết bị đang ngủ the connection was removed kết nối bị xóa you requested the action bạn yêu cầu hoạt động này the modem was not found không thể tìm kiếm modem Bluetooth is not available Bluetooth không có sẵn the SIM card is not inserted không có thẻ SIM the SIM PIN is required thiếu mã PIN của SIM the SIM PUK is required thiếu mã PUK của SIM the SIM PUK is exhausted mã PUK của SIM đã hết ModemManager is not operational on this device ModemManager không hoạt động trên thiết bị này the wireless network wasn't found mạng Wi-Fi không tìm được an unknown error occurred một lỗi không xác định đã xảy ra Cellular Mạng di động ConnectionSelectionPopover Select Connection Profile Chọn hồ sơ kết nối Select a connection profile to use Chọn một hồ sơ kết nối để sử dụng DevicePane STATUS TRẠNG THÁI theDesk doesn't support this network interface, so you won't be able to configure it fully here. theDesk không hỗ trợ giao diện mạng này, vì vậy bạn sẽ không thể cấu hình nó đầy đủ ở đây. ACTIONS HOẠT ĐỘNG Disconnect Ngắt kết nối GenericChunkUpdater Connected Đã kết nối IPv4ConnectionEditorPane IPv4 IPv4 DHCP DHCP DHCP with manual DNS DHCP với DNS thủ công Manual Thủ công Shared Bị chia sẻ Disabled Vô hiệu Configuration Method Phương thức cấu hình Require IPv4 Yêu cầu IPv4 IP Address Địa chỉ IP Default Gateway Máy cổng mặc định Subnet Length Chiều dài mạng con ADDRESSES ĐỊA CHỈ Set the IP address that this device will be assigned. Đặt địa chỉ IP thiết bị này sẽ bị cung cáp với. DNS DNS 1.1.1.1 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. Cấu hình máy chủ DNS sử dụng để phân giải tên miền. For DNS server %1 Cho máy chủ DNS %1 Remove Xóa NetworkChunk Network Settings Disconnected Đã ngắt kết nối Login Required Cần đăng nhập Can't get to the Internet Không thể truy cập Internet NetworkConnectionEditor SETTINGS MODIFIED CÀI ĐẶT BỊ THAY ĐỔI Revert Khôi phục lại Save Lưu DONE? XONG CHƯA? General Chung Connection Name Tên kết nối Couldn't save settings Không thể lưu cài đặt NetworkPluginCommon the device is no longer managed by NetworkManager thiết bị này không có quản lý với NetworkManager nũa configuration of the device failed cấu hình thiết bị không thành công configuration of the device is unavailable cấu hình thiết bị không có sẵn configuration of the device expired cấu hình thiết bị hết hạn required secrets were not provided những bí mật không được cung cấp the authentication supplicant disconnected trình xác thực bị ngắt kết nối configuration of the authentication supplicant failed cấu hình trình xác thực không thành công the authentication supplicant failed trình xác thực không thành công the authentication supplicant timed out trình xác thực hết giờ the PPP network failed to start mạng PPP không khởi chạy được the PPP network was disconnected mạng PPP bị ngắt kết nối the PPP network failed mạng PPP không thành công DHCP configuration failed to start cấu hình DHCP không thể bắt đầu DHCP configuration had an error cấu hình DHCP xảy ra lỗi DHCP configuration failed cấu hình DHCP không thành công the modem is busy modem đang bận there is no dial tone on the modem không có âm quay số trên modem no carrier is available on the modem không có âm cung cấp trên modem dialling the number on the modem timed out quay số trên modem mất quá nhiều thời gian dialling the number on the modem failed quay số trên modem không thành công initialising the modem failed khởi tạo modem không thành công APN selection failed hoạt động chọn APN không thành công the modem is not searching modem không tìm kiếm the cell tower denied registration of the modem tháp di động từ chối chi tiết đăng ký của modem registration of the modem on the cell tower timed out hoạt động đăng ký modem trên tháp di động mất quá nhiều thời gian registration of the modem on the cell tower failed hoạt động đăng ký modem trên tháp di động không thành công the device firmware is missing thiếu phần sụn thiết bị the device was removed thiết bị bị tháo ra the device is sleeping thiết bị đang ngủ the connection was removed kết nối bị xóa you requested the action bạn yêu cầu hoạt động này the modem was not found không thể tìm kiếm modem Bluetooth is not available Bluetooth không có sẵn the SIM card is not inserted không có thẻ SIM the SIM PIN is required thiếu mã PIN của SIM the SIM PUK is required thiếu mã PUK của SIM the SIM PUK is exhausted mã PUK của SIM đã hết ModemManager is not operational on this device ModemManager không hoạt động trên thiết bị này the wireless network wasn't found mạng Wi-Fi không tìm được an unknown error occurred một lỗi không xác định đã xảy ra Cellular Mạng di động NetworkStatusCenterLeftPane Network Mạng NetworkStatusCenterPane NetworkManager is not operational NetworkManager không có hoạt động Contact your system administrator Vui lòng liên hệ với quản trị hệ thống của bạn Network Mạng OnboardingNetwork Network Mạng Connect to the Internet to get updates and install new software. Kết nối với Internet để nhận các cập nhật và cài đặt phần mềm mới. You're connected! Bạn đã kết nối! Disconnect and connect to a different network Ngắt kết nối và kết nối với mạng khác You can always set up the network connection later. Bạn có thể thiết lập cài đặt kết nối sau. Continue without Internet Tiếp tục mà không có Internet Next Tiếp SecurityEapPeap PEAP PEAP Enter the settings for this network Điền vào cài đặt cho mạng này Phase-2 Authentication Xác thực buớc 2 Anonymous Identity Thực thể vô danh PEAP version Phiên bản PEAP Username Tên tài khoản Password Mật khẩu CA Certificate Chứng nhận CA Browse... Duyệt... MSCHAPv2 MSCHAPv2 MD5 MD5 GTC GTC Automatic Tự động Version 0 Phiên bản 0 Version 1 Phiên bản 1 Connect Kết nối Certificates (*.pem, *.cer) Chứng nhận (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Không hỗ trợ cài đặt bảo mật Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. Rất tiếc, theDesk không có hỗ trợ cài đặt bảo mật đó ngay bây giờ. Bạn nên sử dụng thiết bị đầu cuối để cấu hình mạng này. SimSettingsPopover Modem Settings Cài đặt modem SIM PIN SIM PIN Enable SIM PIN Bật SIM PIN Disable SIM PIN Tắt SIM PIN Change SIM PIN Thay đổi SIM PIN CALLS CUỘC GỌI Call Waiting Chờ cuộc gọi IMSI IMSI IMEI IMEI MODEM INFORMATION THÔNG TIN VỀ MODEM Carrier Nhà cung cấp mạng Enter the new SIM PIN Điền vào SIM PIN mới Enter the current SIM PIN Điền vào SIM PIN hiện tại Enable Call Waiting Bật chờ cuộc gọi Call Waiting allows you to receive calls while another call is currently active. Chờ cuộc gọi cho bạn nhận cuộc gọi trong khi một cuộc gọi khác hiện đang diễn ra. No SIM card Không có thẻ SIM You have %n remaining tries Bạn còn %n lần thử Error Lỗi Couldn't get current Call Waiting status from carrier Không thể nhận trạng thái chờ cuộc gọi từ nhà cung cấp mạng SwitchManager Flight Mode Chế độ máy bay Switch off Flight Mode Tắt chế độ máy bay Wi-Fi Wi-Fi Cellular Mạng di động TetheringSettingsPopover Tethering Settings Cài đặt điểm phát sóng SSID SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Cài đặt này sẽ bị dùng để thiết lập một mạng Wi-Fi cho thiết bị khác kết nối với khi điểm phát sóng bị bật. Network Key Mật khẩu mạng Network key needs to be at least 8 characters long Mật khẩu mạng cần phải ít nhất 8 ký tự UnlockModemPopover Enter the SIM PIN Điền vào mã PIN của SIM SIM PUK SIM PUK You'll also need to provide a new SIM PIN to set once the SIM is unlocked. Bạn cũng cần cung cấp một mã PIN mới để đặt sau khi thẻ SIM bị mở khóa. SIM PUK REQUIRED YÊU CẦU SIM PUK Unlock SIM Card Mở khóa thẻ SIM New SIM PIN Mã PIN mới Confirm SIM PIN Xác nhận mã PIN mới Don't guess the PUK! Đừng có đoán mã PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. Sau khi bạn hết lần thử, thẻ SIM này sẽ bị khóa mãi mãi. Bạn sẽ cần liên hệ với nhà cung cấp mạng để yêu cầu thẻ SIM mới. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. Nếu bạn điền mã PIN sai một lần nữa, thẻ SIM sẽ bị khóa với mã PUK, và bạn cần liên hệ với nhà cung cấp mạng. You have %n remaining tries Bạn còn %n lần thử This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Đây là cơ hội cuối cùng cho bạn điền mã PUK đúng trước khi bạn cần nhận thẻ SIM mới từ nhà cung cấp dịch vụ của bạn. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. Liên hệ với nhà cung cấp mạng của bạn để nhận <b>mã PUK của thẻ SIM</b>, sau đó điền nó vào để mở khóa %1. WifiConnectionEditorPane Wi-Fi Wi-Fi Mode Chế độ SSID SSID Infrastructure Hạ tầng Ad-Hoc Ad-Hob Access Point Điểm truy cập WifiDevicePane STATUS TRẠNG THÁI This Device Thiết bị này ACTIONS HOẠT ĐỘNG Select Network Chọn mạng Disconnect Ngắt kết nối TETHERING ĐIỂM PHÁT SÓNG Network Key Mật khẩu mạng Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Sử dụng điểm phát sóng để chia sẻ kết nối Internet của bạn qua Wi-Fi. **Khi điểm phát sóng bị bật, bạn không thể kết nối với Internet bằng Wi-Fi, vì vậy bạn cần đảm bảo rằng bạn có cách thay thế để kết nối với Internet.** Enable Tethering Bật điểm phát sóng SSID SSID Set Tethering Settings Cài đặt điểm phát sóng Wi-Fi is off Wi-Fi đang tắt Switch Wi-Fi on to connect to a wireless network Bật Wi-Fi để kết nối với mạng không dây Switch Wi-Fi On Bật Wi-Fi Wi-Fi is disabled Wi-Fi bị vô hiệu Use the Wi-Fi switch to enable Wi-Fi and connect to a network Sử dụng nút Wi-Fi để bật Wi-Fi và kết nối với một mạng You're in flight mode Bạn đang ở chế độ máy bay Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Bật Wi-Fi để kết nối với mạng không dây. Chế độ máy bay sẽ không bị tắt. Tethering Điểm phát sóng Disable Tethering Tắt điểm phát sóng Wi-Fi Wi-Fi Disconnected Đã ngắt kết nối Active Đang hoạt động Connected Đã kết nối Failed Thất bại Connection Failure Kết nối không thành công Connecting to %1 failed because %2. Kết nối với %1 không thành công tại vì %2. the network mạng 0 Devices 0 thiết bị Unknown Không xác định Couldn't configure tethering Không thể cấu hình điểm phát sóng Couldn't switch off tethering Không thể tắt điểm phát sóng WiredChunkUpdater Wired Mạng dây WiredDevicePane Wired Mạng dây STATUS TRẠNG THÁI This Device Thiết bị này ACTIONS HOẠT ĐỘNG Connect Kết nối Disconnect Ngắt kết nối Disconnected Không kết nối Connected Đã kết nối Failed Thất bại Router Bộ định tuyến Unavailable Không có sẵn Connect an Ethernet cable. Cắm dây Ethernet vào. This network is unavailable because %2. Mạng này không có sẵn tại vì %2. Connection Failure Kết nối không thành công Connecting to the network failed because %2. Kết nối với mạng không thành công tại vì %2. WiredOnboardingSetup WIRED MẠNG DÂY Use Wired Connection Sử dụng mạng dây Connect to the Internet using a wired network Kết nối với Internet sử dụng mạng dây To connect to the Internet using a wired network, connect the network cable. Để kết nối với Internet sử dụng mạng dây, hãy cắm dây mạng vào. WirelessNetworkListDelegate Connected Đã kết nối In Range Trong phạm vi Out of range Ngoài phạm vi Not Secured Không bảo mật Secured with Static WEP Bảo mật với WEP tĩnh Secured with Dynamic WEP Bảo mật với WEP động Secured with LEAP Bảo mật với LEAP Secured with WPA-PSK Bảo mật với WPA-PSK Secured with WPA Enterprise Bảo mật với WPA Doanh nghiệp Secured with WPA2-PSK Bảo mật với WPA2-PSK Secured with WPA2 Enterprise Bảo mật với WPA2 Doanh nghiệp Secured with WPA3 Bảo mật với WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network Kết nối với mạng không dây KNOWN NETWORKS MẠNG ĐÁ NHỚ NEW NETWORKS MẠNG MỚI New Manual Connection Kết nối thủ công mới Enter the security key Điền vào mật khẩu mạng Network Security Bảo mật mạng Select the EAP method. If you don't know what to select, contact your system administrator for the details. Chọn phương pháp EAP. Nếu bạn không biết phải chọn mục nào, hãy liên hệ với quản trị hệ thống của bạn. TLS TLS LEAP LEAP PWD PWD FAST FAST TTLS TTLS PEAP PEAP Unknown Security Bảo mật không xác định Not sure how to connect to this network. Use manual setup to connect to it. Chúng tôi không có biết cách kết nối với mạng này. Vui lòng sử dụng cấu hình thủ công để kết nối. For network %1 Cho mạng %1 Edit Sửa Forget Network Quên mạng Wireless Mạng không dây Connect Kết nối WirelessOnboardingSetup WI-FI WI-FI Connect to the Internet using a Wi-Fi network Kết nối với Internet sử dụng mạng Wi-Fi Select Network Chọn mạng ================================================ FILE: plugins/NetworkPlugin/translations/vi_VN.ts ================================================ CellularPane STATUS TRẠNG THÁI This Device Thiết bị này ACTIONS HOẠT ĐỘNG Connect Kết nối Disconnect Ngắt kết nối Modem Settings Cài đặt modem Disable Cellular Tất mạng di động Enable Cellular Bật mạng di động Disconnected Đã ngắt kết nối Cellular Mạng di động Connected Đã kết nối Failed Thất bại No SIM Card Không có thẻ SIM Insert a SIM card to connect to cellular services. Chèn thẻ SIM để kết nối với dịch vụ di động. No SIM Không có thẻ SIM Unavailable Không có sẵn This network is unavailable because %2. Mạng này không có sẵn tại vì %2. Connection Failure Lỗi kết nối Connecting to the network failed because %2. Không có thể kết nối với mạng này tại vì %2. Enter SIM PIN Điền vào mã PIN cho thẻ SIM SIM PIN Required Cần mã PIN A SIM PIN is required to connect to the cellular network. Cần mã PIN cho thẻ SIM để kết nối với mạng di động Enter SIM PUK Điền vào mã PUK cho thẻ SIM SIM PUK Required Cần mã PUK A SIM PUK is required to connect to the cellular network. Cần mã PUK cho thẻ SIM để kết nối với mạng di động. Common the device is no longer managed by NetworkManager thiết bị này không có quẩn lý bởi NetworkManager nữa configuration of the device failed cấu hình thiết bị không có thành công configuration of the device is unavailable cấu hình thiết bị không có sẵn configuration of the device expired cấu hình cho thiết bị hết hạn required secrets were not provided bí mật cần thiết không được cung cấp the authentication supplicant disconnected thẻ thay thế xác thực bị ngắt kết nối configuration of the authentication supplicant failed the authentication supplicant failed the authentication supplicant timed out the PPP network failed to start mạng PPP không thể khởi động the PPP network was disconnected mạng PPP bị ngắt kết nối the PPP network failed mạng PPP không có thành công DHCP configuration failed to start cấu hình DHCP không thể khởi động DHCP configuration had an error cấu hình DHCP đã xảy ra lỗi DHCP configuration failed cấu hình DHCP không có thành công the modem is busy modem đang bận there is no dial tone on the modem không có âm quay số trên modem no carrier is available on the modem không có nhà mạng nào sẵn trên modem dialling the number on the modem timed out quay số trên modem bị hết giờ dialling the number on the modem failed quay số trên modem không có thành công initialising the modem failed khởi tạo modem không có thành công APN selection failed hoạt động lựa chọn APN không thành công the modem is not searching modem không có tìm kiếm the cell tower denied registration of the modem tháp di động từ chối đăng ký modem registration of the modem on the cell tower timed out hoạt động đang ký modem trên tháp di động bị hết giờ registration of the modem on the cell tower failed hoạt động đang ký modem trên tháp di động không có thành công the device firmware is missing đang mất phần mềm thiết bị the device was removed thiết bị bị tháo the device is sleeping thiết bị đang ngủ the connection was removed cấu hình kết nối bị xóa you requested the action bạn yêu cầu hoạt động the modem was not found không có tìm thấy modem Bluetooth is not available Bluetooth không có sẵn the SIM card is not inserted thẻ SIM không được lắp vào the SIM PIN is required mã PIN của thẻ SIM chưa được điền vào the SIM PUK is required mã PUK của thẻ SIM chưa được điền vào the SIM PUK is exhausted hết lần thử để điền vào mã PUK của thẻ SIM ModemManager is not operational on this device ModemManager không hoạt động trên thiết bị này the wireless network wasn't found không tìm thấy được điểm truy cập an unknown error occurred một lỗi không xác định đã bị xảy ra Cellular Mạng di động ConnectionSelectionPopover Select Connection Profile Chọn hồ sơ kết nối Select a connection profile to use Chọn một hồ sơ kết nối để sử dụng DevicePane STATUS TRẠNG THÁI theDesk doesn't support this network interface, so you won't be able to configure it fully here. theDesk không có hỗ trợ thiết bị này, vì vậy bạn không có thể cấu hình hoàn toàn tại đây được. ACTIONS HOẠT ĐỘNG Disconnect Ngắt kết nối GenericChunkUpdater Connected Đã kết nối IPv4ConnectionEditorPane IPv4 IPv4 DHCP DHCP DHCP with manual DNS DHCP với DNS thủ công Manual Thủ công Shared Bị chia sẻ Disabled Vô hiệu Configuration Method Phương pháp cấu hình Require IPv4 Yêu cầu IPv4 IP Address Địa chỉ IP Default Gateway Định tuyến mặc định Subnet Length Độ dài mạng con ADDRESSES ĐỊA CHỈ Set the IP address that this device will be assigned. Đặt địa chỉ IP để giao phó DNS DNS 1.1.1.1 1.1.1.1 Configure the DNS servers that will be used to resolve domain names. Cấu hình máy chủ DNS sự dụng để giải quyết truy vấn For DNS server %1 Cho máy chủ DNS %1 Remove Xóa NetworkChunk Network Settings Cài đặt mạng Disconnected Bị ngắt kết nối Login Required Cần đăng nhập Can't get to the Internet Không thể truy cập internet NetworkConnectionEditor SETTINGS MODIFIED CÀI ĐẶT BỊ THAY ĐỔI Revert Hoàn lại Save Lưu DONE? XONG CHƯA? General Chung Connection Name Tên kết nối Couldn't save settings Không thể lưu các cài đặt NetworkStatusCenterLeftPane Network Mạng NetworkStatusCenterPane NetworkManager is not operational NetworkManager không có hoạt động Contact your system administrator Vùi lòng liên hệ với quản trị hệ thống Network Mạng OnboardingNetwork Network Mạng Connect to the Internet to get updates and install new software. Kết nối với Internet để truy cập các cập nhật và cài đặt phần mềm mới. You're connected! Bạn đã kết nối! Disconnect and connect to a different network Ngắt kết nối và kết nối với mạng khác You can always set up the network connection later. Bạn cũng có thể thiết lập kết nối mạng sau. Continue without Internet Tiếp tục không có Internet Next Tiếp tục SecurityEapPeap PEAP PEAP Enter the settings for this network Điền vào cài đặt cho mạng này Phase-2 Authentication Xác thực bước hai Anonymous Identity Thực thể nặc danh PEAP version Phiên bản PEAP Username Tên người dùng Password Mặt khẩu CA Certificate Chúng nhận CA Browse... Duyệt... MSCHAPv2 MSCHAPv2 MD5 MD5 GTC GTC Automatic Tự động Version 0 Phiên bản 0 Version 1 Phiên bản 1 Connect Kết nối Certificates (*.pem, *.cer) Chúng nhận (*.pem, *.cer) SecurityEapUnsupported Unsupported Security Settings Cài đặt bảo mật không được hỗ trợ Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. Rất tiếc, theDesk không có hỗ trợ cài đặt bảo mật bây giờ. Bạn có thể thử sử dụng đầu cuối để kết nối với mạng này. SimSettingsPopover Modem Settings Cài đặt modem SIM PIN Mã PIN của thẻ SIM Enable SIM PIN Bật mã PIN Disable SIM PIN Tất mã PIN Change SIM PIN Đổi mã PIN CALLS CUỘC GỌI Call Waiting Chờ cuộc gọi IMSI IMSI IMEI IMEI MODEM INFORMATION THÔNG TIN MODEM Carrier Nhà cung cấp dịch vụ Enter the new SIM PIN Điền vào mã PIN mới Enter the current SIM PIN Điền vào mã PIN hiện tại Enable Call Waiting Bật chờ cuộc gọi Call Waiting allows you to receive calls while another call is currently active. Chờ cuộc gọi cho phép bạn nhận cuộc gọi đến khi một cuộc gọi khác hiện đang hoạt động. No SIM card Không có thể SIM You have %n remaining tries Bạn còn %n lần thử lại Error Lỗi Couldn't get current Call Waiting status from carrier Không thể nhận trạng thái chờ cuộc gọi từ nhà cung cấp dịch vụ SwitchManager Flight Mode Chế độ trên máy bay Switch off Flight Mode Tất chế độ trên máy bay Wi-Fi Wi-Fi Cellular Mạng di động TetheringSettingsPopover Tethering Settings Cài đặt chia sẻ kết nối SSID SSID These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Cài đặt này sẽ bị dùng để thiết lập mạng Wi-Fi có thể kết nối bởi thiết bị khác khi chia sẻ mạng đang bật. Network Key Mặt khẩu mạng Network key needs to be at least 8 characters long Độ dài mặt khẩu mạng phải ít nhất 8 ký tự UnlockModemPopover Enter the SIM PIN Điền vào mã PIN của thẻ SIM SIM PUK Mã PUK của thẻ SIM You'll also need to provide a new SIM PIN to set once the SIM is unlocked. Bạn cúng cần cung cấp một mã PIN mới để đặt sau khi thể SIM bị mở khóa. SIM PUK REQUIRED CẦN MÃ PUK CỦA THẺ SIM Unlock SIM Card Mở khóa thẻ SIM New SIM PIN Mã PIN mới Confirm SIM PIN Xác nhận mã PIN Don't guess the PUK! Đừng có đoán mã PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. Sau khi bạn hết lần thử lại, thể SIM này sẽ bị chặn mãi mãi. Bạn sẽ cần liên hệ với nhà cung cấp dịch vụ của bạn và yêu cầu một thế SIM mới. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. Nếu bạn điền vào mã PIN sai một lần nữa, thể SIM của bạn sẽ bị chặn, và bạn sẽ cần liên hệ với nhà cung cấp dịch vụ của bạn. You have %n remaining tries Bạn còn %n lần thử lại This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. Đây là cơ hội cuối cùng của bạn để nhập mã PUK đúng trước khi bạn sẽ cần nhận một thẻ SIM mới. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. Liên hệ với nhà cung cấp dịch vụ của bạn và nhận <b>mã PUK của thẻ SIM</b>, rồi điền nó dưới đây để mở khóa %1. WifiConnectionEditorPane Wi-Fi Wi-Fi Mode Chế độ SSID SSID Infrastructure Hạ tầng Ad-Hoc Ad-Hoc Access Point Điểm truy cập WifiDevicePane STATUS TRẠNG THÁI This Device Thiết bị này ACTIONS HOẠT ĐỘNG Select Network Chọn mạng Disconnect Ngắt kết nối TETHERING CHIA SẺ KẾT NỐI Network Key Mặt khẩu mạng Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** Sử dụng chia sẻ kết nối để chia sẻ kết nối của bạn với thiết bị khác bằng Wi-Fi. **Khi chia sẻ kết nối bị bật, bạn không thể kết nối với Internet bằng Wi-Fi, vì vậy bạn cần bảo đảm bạn có một phương pháp kết nối Internet khác.** Enable Tethering Bật chia sẻ kết nối SSID SSID Set Tethering Settings Cài đặt chia sẻ kết nối Wi-Fi is off Wi-Fi bị tắt Switch Wi-Fi on to connect to a wireless network Bật Wi-Fi để kết nối với mạng không dây Switch Wi-Fi On Bật Wi-Fi Wi-Fi is disabled Wi-Fi bị vô hiệu Use the Wi-Fi switch to enable Wi-Fi and connect to a network Sử dụng công tắc Wi-Fi để bật Wi-Fi và kết nối với mạng You're in flight mode Bằng đang ở chế độ trên máy bay Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Bật Wi-Fi để kết nối với mạng không dây. Chế độ trên máy bay sẽ không có bị tắt. Tethering Chia sẻ kết nối Disable Tethering Tất chia sẻ kết nối Wi-Fi Wi-Fi Disconnected Bị ngắt kết nối Active Đang hoạt động Connected Đã kết nối Failed Thất bại Connection Failure Kết nối thất bại Connecting to %1 failed because %2. Kết nối với %1 không có thành công tại vì %2. the network mạng 0 Devices 0 thiết bị Unknown Không xác định Couldn't configure tethering Không thể cấu hình chia sẻ kết nối Couldn't switch off tethering Không thể tắt chia sẻ kết nối WiredChunkUpdater Wired Mạng dây WiredDevicePane Wired Mạng dây STATUS TRẠNG THÁI This Device Thiết bị này ACTIONS HOẠT ĐỘNG Connect Kết nối Disconnect Ngắt kết nối Disconnected Đã ngắt kết nối Connected Đã kết nối Failed Thất bại Router Bộ định tuyến Unavailable Không có sẵn Connect an Ethernet cable. Vùi lòng cắm dây Ethernet. This network is unavailable because %2. Mạng này không có sẵn tại vì %2. Connection Failure Kết nối thất bại Connecting to the network failed because %2. Kết nối với mạng không có thành công tại vì %2. WiredOnboardingSetup WIRED MẠNG DÂY Use Wired Connection Sử dụng mạng dây Connect to the Internet using a wired network Kết nối với Internet dùng mạng dây To connect to the Internet using a wired network, connect the network cable. Để kết nối với Internet dùng mạng dây, hãy cắm dây mạng vào. WirelessNetworkListDelegate Connected Đã kết nối In Range Trong phạm vi Out of range Ngoài phạm vi Not Secured Không có bảo đảm Secured with Static WEP Bảo đảm với WEP tĩnh Secured with Dynamic WEP Bảo đảm với WEP động Secured with LEAP Bảo đảm với LEAP Secured with WPA-PSK Bảo đảm với WPA-PSK Secured with WPA Enterprise Bảo đảm với WPA Doanh nghiệp Secured with WPA2-PSK Bảo đảm với WPA2-PSK Secured with WPA2 Enterprise Bảo đảm với WPA2 Doanh nghiệp Secured with WPA3 Bảo đảm với WPA3 WirelessNetworkSelectionPopover Connect to a Wireless Network Kết nối với mạng không dây KNOWN NETWORKS MẠNG ĐÃ BIẾT NEW NETWORKS MẠNG MỚI New Manual Connection Kết nối thu công mới Enter the security key Điền vào mặt khẩu Network Security Bảo đảm mạng Select the EAP method. If you don't know what to select, contact your system administrator for the details. Chon phương pháp EAP. Nếu bạn không có biết chọn tùy chọn nào, vùi lòng liên hệ với quản trị viên của bạn cho chi tiết. TLS TLS LEAP LEAP PWD PWD FAST FAST TTLS TTLS PEAP PEAP Unknown Security Bảo mật không xác định Not sure how to connect to this network. Use manual setup to connect to it. Không có biết tuy chọn kết nối mạng này. Vùi lòng sử dụng kết nối thu công để kết nối. For network %1 Cho mạng %1 Edit Sửa Forget Network Quên Wireless Mạng không dây Connect Kết nối WirelessOnboardingSetup WI-FI Wi-Fi Connect to the Internet using a Wi-Fi network Kết nối với mạng dùng mạng Wi-Fi Select Network Chọn mạng ================================================ FILE: plugins/NetworkPlugin/translations/zh_CN.ts ================================================ CellularPane STATUS 状态 This Device 此设备 ACTIONS 行动 Connect 连接 Disconnect 断开 Cellular 蜂窝 Disconnected 断开 Connected 连接的 Failed 失败 Unavailable 不可用 This network is unavailable because %2. 由于%2,该网络不可用。 Connection Failure 连接失败 Connecting to the network failed because %2. 由于%2,连接到网络失败。 Enter SIM PIN SIM PIN Required Enter SIM PUK SIM PUK Required A SIM PIN is required to connect to the cellular network. A SIM PUK is required to connect to the cellular network. Modem Settings Disable Cellular Enable Cellular No SIM Card Insert a SIM card to connect to cellular services. No SIM Common an unknown error occurred 出现未知错误 the device is no longer managed by NetworkManager 设备不再由NetworkManager管理 configuration of the device failed 设备配置失败 configuration of the device is unavailable 设备的配置不可用 configuration of the device expired 设备配置已过期 required secrets were not provided 没有提供所需的密码 the authentication supplicant disconnected 身份验证请求者已断开连接 configuration of the authentication supplicant failed 身份验证请求者配置失败 the authentication supplicant failed 认证请求者失败 the authentication supplicant timed out 身份验证请求方超时 the PPP network failed to start PPP网络无法启动 the PPP network was disconnected PPP网络已断开连接 the PPP network failed PPP网络失败 DHCP configuration failed to start DHCP配置无法启动 DHCP configuration had an error DHCP配置出错 DHCP configuration failed DHCP配置失败 the modem is busy 调制解调器忙 there is no dial tone on the modem 调制解调器上没有拨号音 no carrier is available on the modem 调制解调器上没有可用的运营商 dialling the number on the modem timed out 拨打调制解调器上的号码超时 dialling the number on the modem failed 在调制解调器上拨号失败 initialising the modem failed 初始化调制解调器失败 APN selection failed APN选择失败 the modem is not searching 调制解调器没有搜索 the cell tower denied registration of the modem 基站拒绝注册调制解调器 registration of the modem on the cell tower timed out 调制解调器在手机信号塔上的注册超时 registration of the modem on the cell tower failed 调制解调器在手机信号塔上的注册失败 the device firmware is missing 设备固件丢失 the device was removed 设备已删除 the device is sleeping 设备正在休眠 the connection was removed 连接已删除 you requested the action 您要求采取行动 the modem was not found 找不到调制解调器 Bluetooth is not available 蓝牙不可用 the SIM card is not inserted 未插入SIM卡 the SIM PIN is required 需要SIM卡PIN码 the SIM PUK is required 需要SIM PUK the SIM PUK is exhausted SIM PUK已耗尽 ModemManager is not operational on this device ModemManager在此设备上无法运行 the wireless network wasn't found 找不到无线网络 Cellular 蜂窝 ConnectionSelectionPopover Select Connection Profile 选择连接配置文件 Select a connection profile to use 选择要使用的连接配置文件 DevicePane ACTIONS 行动 Disconnect 断开 STATUS 状态 theDesk doesn't support this network interface, so you won't be able to configure it fully here. theDesk不支持此网络接口,因此您将无法在此处完全配置它。 GenericChunkUpdater Connected 连接的 IPv4ConnectionEditorPane IPv4 IPv4 DHCP DHCP DHCP with manual DNS 具有手动DNS的DHCP Manual 手册 Shared 共享 Disabled 关闭 Configuration Method 配置方式 Require IPv4 需要IPv4 IP Address IP地址 Default Gateway 默认网关 Subnet Length 子网长度 ADDRESSES 地址 1.1.1.1 1.1.1.1 DNS 域名解析 Set the IP address that this device will be assigned. 设置此设备将分配的IP地址。 Configure the DNS servers that will be used to resolve domain names. 配置将用于解析域名的DNS服务器。 For DNS server %1 对于DNS服务器%1 Remove 移除 NetworkChunk Disconnected 断开 Login Required 需要登录 Can't get to the Internet 无法连接到互联网 Network Settings NetworkConnectionEditor General Connection Name 连接名称 DONE? 结束? Save 保存 Couldn't save settings 无法保存设置 SETTINGS MODIFIED 设置已更改 Revert 还原 NetworkPluginCommon the device is no longer managed by NetworkManager 设备不再由NetworkManager管理 configuration of the device failed 设备配置失败 configuration of the device is unavailable 设备的配置不可用 configuration of the device expired 设备配置已过期 required secrets were not provided 没有提供所需的密码 the authentication supplicant disconnected 身份验证请求者已断开连接 configuration of the authentication supplicant failed 身份验证请求者配置失败 the authentication supplicant failed 认证请求者失败 the authentication supplicant timed out 身份验证请求方超时 the PPP network failed to start PPP网络无法启动 the PPP network was disconnected PPP网络已断开连接 the PPP network failed PPP网络失败 DHCP configuration failed to start DHCP配置无法启动 DHCP configuration had an error DHCP配置出错 DHCP configuration failed DHCP配置失败 the modem is busy 调制解调器忙 there is no dial tone on the modem 调制解调器上没有拨号音 no carrier is available on the modem 调制解调器上没有可用的运营商 dialling the number on the modem timed out 拨打调制解调器上的号码超时 dialling the number on the modem failed 在调制解调器上拨号失败 initialising the modem failed 初始化调制解调器失败 APN selection failed APN选择失败 the modem is not searching 调制解调器没有搜索 the cell tower denied registration of the modem 基站拒绝注册调制解调器 registration of the modem on the cell tower timed out 调制解调器在手机信号塔上的注册超时 registration of the modem on the cell tower failed 调制解调器在手机信号塔上的注册失败 the device firmware is missing 设备固件丢失 the device was removed 设备已删除 the device is sleeping 设备正在休眠 the connection was removed 连接已删除 you requested the action 您要求采取行动 the modem was not found 找不到调制解调器 Bluetooth is not available 蓝牙不可用 the SIM card is not inserted 未插入SIM卡 the SIM PIN is required 需要SIM卡PIN码 the SIM PUK is required 需要SIM PUK the SIM PUK is exhausted SIM PUK已耗尽 ModemManager is not operational on this device ModemManager在此设备上无法运行 the wireless network wasn't found 找不到无线网络 an unknown error occurred 出现未知错误 Cellular 蜂窝 NetworkStatusCenterLeftPane Network 网络 NetworkStatusCenterPane Network 网络 NetworkManager is not operational NetworkManager无法运行 Contact your system administrator 与系统管理员联系 OnboardingNetwork Network 网络 Connect to the Internet to get updates and install new software. Next You're connected! Disconnect and connect to a different network Continue without Internet You can always set up the network connection later. SecurityEapPeap PEAP PEAP Enter the settings for this network 输入此网络的设置 CA Certificate CA证书 Anonymous Identity 匿名身份 Phase-2 Authentication 第二阶段认证 MSCHAPv2 MSCHAPv2 MD5 MD5 GTC GTC Username 用户名 Password 密码 Connect 连接 PEAP version PEAP版本 Automatic 自动 Version 0 版本 0 Version 1 版本 1 Browse... 浏览。。。 Certificates (*.pem, *.cer) 证书(* .pem,*。cer) SecurityEapUnsupported Unsupported Security Settings 不支持的安全设置 Sorry, theDesk doesn't support those security settings at the moment. You can try using the terminal to configure this network. 抱歉,theDesk目前不支持这些安全设置。 您可以尝试使用终端配置此网络。 SimSettingsPopover Enable SIM PIN Enter the current SIM PIN Disable SIM PIN Change SIM PIN You have %n remaining tries Enter the new SIM PIN Modem Settings SIM PIN IMSI IMEI MODEM INFORMATION Carrier No SIM card CALLS Call Waiting Enable Call Waiting Call Waiting allows you to receive calls while another call is currently active. Error Couldn't get current Call Waiting status from carrier SwitchManager Flight Mode 飞行模式 Wi-Fi Wi-Fi Cellular 蜂窝 Switch off Flight Mode TetheringSettingsPopover Tethering Settings SSID SSID Network Key 网络密钥 These settings will be used to set up a Wi-Fi network that other devices can connect to when tethering is enabled. Network key needs to be at least 8 characters long UnlockModemPopover Enter the SIM PIN You have %n remaining tries SIM PUK REQUIRED Confirm SIM PIN SIM PUK New SIM PIN You'll also need to provide a new SIM PIN to set once the SIM is unlocked. Unlock SIM Card Don't guess the PUK! Once you exhaust your attempts, the SIM card will be blocked forever. You'll need to contact your carrier for a new SIM card. Contact your carrier to obtain the <b>SIM PUK</b>, and enter it below to unlock %1. If you enter the incorrect PIN again, your SIM card will be PUK locked, and you'll need to contact your carrier. This is your final chance to get the PUK right before you'll need to obtain a new SIM card from your carrier. WifiConnectionEditorPane Wi-Fi Wi-Fi SSID SSID Mode 模式 Infrastructure 基础设施 Ad-Hoc Ad-Hoc Access Point 切入点 WifiDevicePane STATUS 状态 ACTIONS 行动 Disconnect 断开 Wi-Fi Wi-Fi This Device 此设备 Disconnected 断开 Failed 失败 Unknown 未知 0 Devices 0 设备 Connected 连接的 Select Network 选择网络 Connection Failure 连接失败 Connecting to %1 failed because %2. 由于%2连接到%1失败。 the network 网络 SSID SSID Network Key 网络密钥 Enable Tethering 启用网络共享 TETHERING 共享 Set Tethering Settings 设置网络共享 Couldn't configure tethering 无法配置网络共享 Tethering 共享 Active 活跃 Use Tethering to share your internet connection with other devices over Wi-Fi. **While Tethering is active, you won't be able to connect to the Internet with Wi-Fi, so you'll need to make sure you have an alternate way to connect to the Internet.** 使用网络共享可通过Wi-Fi与其他设备共享互联网连接。 **虽然启用了网络共享,但您将无法使用Wi-Fi连接到Internet,因此,您需要确保您有另一种连接到Internet的方式。** Couldn't switch off tethering 无法关闭网络共享 Wi-Fi is off Switch Wi-Fi On Wi-Fi is disabled Switch Wi-Fi on to connect to a wireless network Use the Wi-Fi switch to enable Wi-Fi and connect to a network You're in flight mode Switch Wi-Fi on to connect to a wireless network. Flight mode won't be disabled. Disable Tethering WiredChunkUpdater Wired 有线 WiredDevicePane STATUS 状态 This Device 此设备 ACTIONS 行动 Connect 连接 Disconnect 断开 Wired 有线 Disconnected 断开 Connected 连接的 Failed 失败 Connection Failure 连接失败 Connecting to the network failed because %2. 由于%2,连接到网络失败。 Router 路由器 Unavailable 不可用 Connect an Ethernet cable. 连接以太网电缆。 This network is unavailable because %2. 由于%2,该网络不可用。 WiredOnboardingSetup WIRED Use Wired Connection To connect to the Internet using a wired network, connect the network cable. Connect to the Internet using a wired network WirelessNetworkListDelegate In Range 在范围内 Out of range 超出范围 Not Secured 不安全 Secured with Static WEP 通过静态WEP进行保护 Secured with Dynamic WEP 通过动态WEP进行保护 Secured with LEAP 用LEAP保护 Secured with WPA-PSK 使用WPA-PSK进行保护 Secured with WPA Enterprise 由WPA Enterprise保护 Secured with WPA2-PSK 使用WPA2-PSK进行保护 Secured with WPA2 Enterprise 使用WPA2 Enterprise保护 Connected 连接的 Secured with WPA3 用WPA3保护 WirelessNetworkSelectionPopover Connect to a Wireless Network 连接到无线网络 KNOWN NETWORKS 已知网络 NEW NETWORKS 新网络 New Manual Connection 新的手动连接 For network %1 对于网络%1 Forget Network 忘记网络 Network Security 网络安全 Unknown Security 未知的安全性 Not sure how to connect to this network. Use manual setup to connect to it. 不确定如何连接到该网络。 使用手动设置进行连接。 Enter the security key 输入安全密钥 Select the EAP method. If you don't know what to select, contact your system administrator for the details. 选择EAP方法。 如果您不知道要选择什么,请与系统管理员联系以获取详细信息。 TLS TLS LEAP LEAP PWD PWD FAST 快速 TTLS TTLS PEAP PEAP Wireless 无线 Edit 编辑 Connect 连接 WirelessOnboardingSetup WI-FI Connect to the Internet using a Wi-Fi network Select Network 选择网络 ================================================ FILE: plugins/NotificationsPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets DBus) find_package(libcontemporary) set(SOURCES chunks/mprischunk.cpp dbus/notifications_adaptor.cpp dbus/notificationsinterface.cpp drawer/hudwidget.cpp drawer/notificationsdrawer.cpp drawer/notificationsdrawerwidget.cpp notification.cpp notificationtracker.cpp plugin.cpp statuscenter/notificationappgroup.cpp statuscenter/notificationsstatuscenterpane.cpp statuscenter/notificationwidget.cpp chunks/mprischunk.ui drawer/hudwidget.ui drawer/notificationsdrawer.ui drawer/notificationsdrawerwidget.ui statuscenter/notificationappgroup.ui statuscenter/notificationsstatuscenterpane.ui statuscenter/notificationwidget.ui statuscenter/jobwidget.cpp statuscenter/jobwidget.ui ) set(HEADERS chunks/mprischunk.h dbus/notifications_adaptor.h dbus/notificationsinterface.h drawer/hudwidget.h drawer/notificationsdrawer.h drawer/notificationsdrawerwidget.h notification.h notificationtracker.h plugin.h statuscenter/notificationappgroup.h statuscenter/notificationsstatuscenterpane.h statuscenter/notificationwidget.h statuscenter/jobwidget.h ) set(PLUGIN_NAME notifications) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-notifications.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets Qt::Multimedia libcontemporary libthedesk) ================================================ FILE: plugins/NotificationsPlugin/NotificationsPlugin.pro ================================================ QT += widgets TEMPLATE = lib DEFINES += NOTIFICATIONSPLUGIN_LIBRARY # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) CONFIG += c++11 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ chunks/mprischunk.cpp \ dbus/notifications_adaptor.cpp \ dbus/notificationsinterface.cpp \ drawer/hudwidget.cpp \ drawer/notificationsdrawer.cpp \ drawer/notificationsdrawerwidget.cpp \ notification.cpp \ notificationtracker.cpp \ plugin.cpp \ statuscenter/notificationappgroup.cpp \ statuscenter/notificationsstatuscenterpane.cpp \ statuscenter/notificationwidget.cpp HEADERS += \ chunks/mprischunk.h \ dbus/notifications_adaptor.h \ dbus/notificationsinterface.h \ drawer/hudwidget.h \ drawer/notificationsdrawer.h \ drawer/notificationsdrawerwidget.h \ notification.h \ notificationtracker.h \ plugin.h \ statuscenter/notificationappgroup.h \ statuscenter/notificationsstatuscenterpane.h \ statuscenter/notificationwidget.h unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/NotificationsPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/NotificationsPlugin/ INSTALLS += translations defaults INSTALLS += translations } include(../plugins.pri) DISTFILES += \ Plugin.json \ defaults.conf FORMS += \ chunks/mprischunk.ui \ drawer/hudwidget.ui \ drawer/notificationsdrawer.ui \ drawer/notificationsdrawerwidget.ui \ statuscenter/notificationappgroup.ui \ statuscenter/notificationsstatuscenterpane.ui \ statuscenter/notificationwidget.ui ================================================ FILE: plugins/NotificationsPlugin/Plugin.json ================================================ { "name": "Notifications", "icon": "preferences-system-notifications", "uuid": "dc34359b-43fe-4bb9-bbf1-0c0ff1501bff", "vi": { "name": "Thông báo" } } ================================================ FILE: plugins/NotificationsPlugin/chunks/mprischunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "mprischunk.h" #include "ui_mprischunk.h" #include #include #include #include #include #include #include #include struct MprisChunkPrivate { MprisPlayerPtr currentPlayer; QString currentPlayerService; ApplicationPointer currentPlayerApplication; QMenu* playersMenu; QActionGroup* playersGroup; QMap playerActions; BarManager::BarLockPtr barLocker; }; MprisChunk::MprisChunk() : Chunk(), ui(new Ui::MprisChunk) { ui->setupUi(this); d = new MprisChunkPrivate(); d->playersGroup = new QActionGroup(this); d->playersMenu = new QMenu(this); d->playersMenu->addSection(tr("Media Players")); connect(d->playersMenu, &QMenu::aboutToShow, this, [=] { d->barLocker = StateManager::barManager()->acquireLock(); }); connect(d->playersMenu, &QMenu::aboutToHide, this, [=] { d->barLocker->unlock(); }); ui->playersButton->setMenu(d->playersMenu); ui->playersButton->setVisible(MprisEngine::players().count() > 1); connect(MprisEngine::instance(), &MprisEngine::newPlayer, this, [=](QString service, MprisPlayerPtr player) { Q_UNUSED(player) setupPlayer(service); if (d->currentPlayer == nullptr) setCurrentPlayer(service); }); connect(MprisEngine::instance(), &MprisEngine::playerGone, this, [=](QString service) { QAction* action = d->playerActions.take(service); d->playersMenu->removeAction(action); action->deleteLater(); ui->playersButton->setVisible(MprisEngine::players().count() > 1); if (d->currentPlayerService == service) { // Find another player if (!MprisEngine::players().isEmpty()) { setCurrentPlayer(MprisEngine::players().first()->service()); } else { setCurrentPlayer(""); } } }); if (!MprisEngine::players().isEmpty()) { for (MprisPlayerPtr player : MprisEngine::players()) { setupPlayer(player->service()); } setCurrentPlayer(MprisEngine::players().first()->service()); } else { setCurrentPlayer(""); } connect(StateManager::barManager(), &BarManager::barHeightTransitioning, this, [=](qreal percentage) { if (qFuzzyCompare(percentage, 1)) { ui->buttonWidget->setFixedWidth(QWIDGETSIZE_MAX); ui->playersButton->setFixedWidth(QWIDGETSIZE_MAX); ui->stateIcon->setFixedWidth(0); } else if (qFuzzyIsNull(percentage)) { ui->buttonWidget->setFixedWidth(0); ui->playersButton->setFixedWidth(0); ui->stateIcon->setFixedWidth(QWIDGETSIZE_MAX); } else { ui->buttonWidget->setFixedWidth(static_cast(ui->buttonWidget->sizeHint().width() * percentage)); ui->playersButton->setFixedWidth(static_cast(ui->playersButton->sizeHint().width() * percentage)); ui->stateIcon->setFixedWidth(static_cast(ui->stateIcon->sizeHint().width() * (1 - percentage))); } }); ui->stateIcon->setFixedWidth(0); ui->stateIcon->setPixmap(QIcon::fromTheme("media-playback-start").pixmap(SC_DPI_T(QSize(16, 16), QSize))); // Ensure that the player controls are always LTR // if (this->layoutDirection() == Qt::RightToLeft) { ui->playerControlsWidget->setLayoutDirection(Qt::LeftToRight); // ui->playerControlsLayout->setDirection(QBoxLayout::RightToLeft); // } } MprisChunk::~MprisChunk() { if (StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->removeChunk(this); delete d; delete ui; } void MprisChunk::setupPlayer(QString service) { MprisPlayerPtr player = MprisEngine::instance()->playerForInterface(service); QAction* action = new QAction(); action->setText(player->identity()); action->setCheckable(true); connect(action, &QAction::triggered, this, [=] { setCurrentPlayer(service); }); d->playerActions.insert(service, action); d->playersGroup->addAction(action); d->playersMenu->addAction(action); ui->playersButton->setVisible(MprisEngine::players().count() > 1); } void MprisChunk::setCurrentPlayer(QString player) { d->currentPlayer->disconnect(this); d->currentPlayerService = player; if (player == "") { d->currentPlayer = nullptr; d->currentPlayerApplication = nullptr; if (StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->removeChunk(this); } else { d->currentPlayer = MprisEngine::playerForInterface(player); connect(d->currentPlayer.data(), &MprisPlayerInterface::desktopEntryChanged, this, &MprisChunk::updateApplication); connect(d->currentPlayer.data(), &MprisPlayerInterface::metadataChanged, this, &MprisChunk::updateMetadata); connect(d->currentPlayer.data(), &MprisPlayerInterface::playbackStatusChanged, this, &MprisChunk::updateState); updateApplication(); updateMetadata(); updateState(); if (!StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->addChunk(this); d->playerActions.value(player)->setChecked(true); } } void MprisChunk::updateMetadata() { MetadataMap meta = d->currentPlayer->metadata(); QStringList parts; if (meta.contains("xesam:title")) parts.append(meta.value("xesam:title").toString()); if (meta.contains("xesam:artist")) parts.append(QLocale().createSeparatedList(meta.value("xesam:artist").toStringList())); if (parts.isEmpty()) { if (d->currentPlayerApplication) { parts.append(d->currentPlayerApplication->getProperty("Name").toString()); } else { parts.append(d->currentPlayer->identity()); } } ui->metadataLabel->setText(parts.join(" · ")); } void MprisChunk::updateApplication() { if (d->currentPlayer) { d->currentPlayerApplication = ApplicationPointer(new Application(d->currentPlayer->desktopEntry())); } else { d->currentPlayerApplication = nullptr; } } void MprisChunk::updateState() { switch (d->currentPlayer->playbackStatus()) { case MprisPlayerInterface::Playing: ui->stateIcon->setPixmap(QIcon::fromTheme("media-playback-start").pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->playPauseButton->setIcon(QIcon::fromTheme("media-playback-pause")); break; case MprisPlayerInterface::Paused: ui->stateIcon->setPixmap(QIcon::fromTheme("media-playback-pause").pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->playPauseButton->setIcon(QIcon::fromTheme("media-playback-start")); break; case MprisPlayerInterface::Stopped: ui->stateIcon->setPixmap(QIcon::fromTheme("media-playback-stop").pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->playPauseButton->setIcon(QIcon::fromTheme("media-playback-start")); break; } } QString MprisChunk::name() { return "mpris"; } int MprisChunk::expandedHeight() { return this->sizeHint().height(); } int MprisChunk::statusBarHeight() { return ui->metadataLabel->sizeHint().height(); } void MprisChunk::on_playPauseButton_clicked() { if (d->currentPlayer) d->currentPlayer->playPause(); } void MprisChunk::on_backButton_clicked() { if (d->currentPlayer) d->currentPlayer->previous(); } void MprisChunk::on_forwardButton_clicked() { if (d->currentPlayer) d->currentPlayer->next(); } ================================================ FILE: plugins/NotificationsPlugin/chunks/mprischunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef MPRISCHUNK_H #define MPRISCHUNK_H #include namespace Ui { class MprisChunk; } struct MprisChunkPrivate; class MprisChunk : public Chunk { Q_OBJECT public: explicit MprisChunk(); ~MprisChunk(); private: Ui::MprisChunk* ui; MprisChunkPrivate* d; void setupPlayer(QString service); void setCurrentPlayer(QString player); void updateMetadata(); void updateApplication(); void updateState(); // Chunk interface public: QString name(); int expandedHeight(); int statusBarHeight(); private slots: void on_playPauseButton_clicked(); void on_backButton_clicked(); void on_forwardButton_clicked(); }; #endif // MPRISCHUNK_H ================================================ FILE: plugins/NotificationsPlugin/chunks/mprischunk.ui ================================================ MprisChunk 0 0 400 41 Form 0 0 0 0 0 TextLabel 0 0 .. QToolButton::InstantPopup 6 6 TextLabel 0 0 0 0 0 0 0 0 0 0 0 0 .. 0 0 .. 0 0 .. ================================================ FILE: plugins/NotificationsPlugin/dbus/notifications_adaptor.cpp ================================================ /* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp -i notifications_adaptor.h -a :notifications_adaptor.cpp ../../../theDesk/plugins/NotificationsPlugin/dbus/org.freedesktop.Notifications.xml * * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. * * This is an auto-generated file. * Do not edit! All changes made to it will be lost. */ #include "notifications_adaptor.h" #include #include #include #include #include #include #include #include "notificationsinterface.h" /* * Implementation of adaptor class NotificationsAdaptor */ NotificationsAdaptor::NotificationsAdaptor(QObject* parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(true); } NotificationsAdaptor::~NotificationsAdaptor() { // destructor } void NotificationsAdaptor::CloseNotification(uint id) { // handle method call org.freedesktop.Notifications.CloseNotification QMetaObject::invokeMethod(parent(), "CloseNotification", Q_ARG(uint, id)); } QStringList NotificationsAdaptor::GetCapabilities() { // handle method call org.freedesktop.Notifications.GetCapabilities QStringList out0; QMetaObject::invokeMethod(parent(), "GetCapabilities", Q_RETURN_ARG(QStringList, out0)); return out0; } QString NotificationsAdaptor::GetServerInformation(QString& vendor, QString& version, QString& specVersion) { // handle method call org.freedesktop.Notifications.GetServerInformation return static_cast(parent())->GetServerInformation(vendor, version, specVersion); } uint NotificationsAdaptor::Notify(const QString& appName, uint replacesId, const QString& appIcon, const QString& summary, const QString& body, const QStringList& actions, const QVariantMap& hints, int expireTimeout) { // handle method call org.freedesktop.Notifications.Notify uint out0; QMetaObject::invokeMethod(parent(), "Notify", Q_RETURN_ARG(uint, out0), Q_ARG(QString, appName), Q_ARG(uint, replacesId), Q_ARG(QString, appIcon), Q_ARG(QString, summary), Q_ARG(QString, body), Q_ARG(QStringList, actions), Q_ARG(QVariantMap, hints), Q_ARG(int, expireTimeout)); return out0; } ================================================ FILE: plugins/NotificationsPlugin/dbus/notifications_adaptor.h ================================================ /* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp -a notifications_adaptor.h: ../../../theDesk/plugins/NotificationsPlugin/dbus/org.freedesktop.Notifications.xml * * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. * * This is an auto-generated file. * This file may have been hand-edited. Look for HAND-EDIT comments * before re-generating it. */ #ifndef NOTIFICATIONS_ADAPTOR_H #define NOTIFICATIONS_ADAPTOR_H #include #include QT_BEGIN_NAMESPACE class QByteArray; template class QList; template class QMap; class QString; class QVariant; QT_END_NAMESPACE /* * Adaptor class for interface org.freedesktop.Notifications */ class NotificationsAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Notifications") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: NotificationsAdaptor(QObject* parent); virtual ~NotificationsAdaptor(); public: // PROPERTIES public Q_SLOTS: // METHODS void CloseNotification(uint id); QStringList GetCapabilities(); QString GetServerInformation(QString& vendor, QString& version, QString& specVersion); uint Notify(const QString& appName, uint replacesId, const QString& appIcon, const QString& summary, const QString& body, const QStringList& actions, const QVariantMap& hints, int expireTimeout); Q_SIGNALS: // SIGNALS void ActionInvoked(uint id, const QString& actionKey); void NotificationClosed(uint id, uint reason); }; #endif ================================================ FILE: plugins/NotificationsPlugin/dbus/notificationsinterface.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "notificationsinterface.h" #include #include "notification.h" #include "notificationtracker.h" #include "notifications_adaptor.h" struct NotificationsInterfacePrivate { NotificationTracker* tracker; }; NotificationsInterface::NotificationsInterface(NotificationTracker* tracker, QObject* parent) : QObject(parent) { new NotificationsAdaptor(this); QDBusConnection::sessionBus().registerService("org.freedesktop.Notifications"); QDBusConnection::sessionBus().registerObject("/org/freedesktop/Notifications", this); d = new NotificationsInterfacePrivate(); d->tracker = tracker; connect(tracker, &NotificationTracker::destroyed, this, &NotificationsInterface::deleteLater); } NotificationsInterface::~NotificationsInterface() { delete d; QDBusConnection::sessionBus().unregisterObject("/org/freedesktop/Notifications"); QDBusConnection::sessionBus().unregisterService("org.freedesktop.Notifications"); } QStringList NotificationsInterface::GetCapabilities() { return {"body", "actions", "action-icons", "body-markup"}; } quint32 NotificationsInterface::Notify(QString appName, quint32 replacesId, QString appIcon, QString summary, QString body, QStringList actions, QVariantMap hints, qint32 expireTimeout) { NotificationPtr notification = d->tracker->get(replacesId); if (!notification) { notification = d->tracker->createNotification(); connect(notification.data(), &Notification::dismissed, this, [ = ](Notification::NotificationCloseReason closeReason) { emit NotificationClosed(notification->id(), closeReason); }); connect(notification.data(), &Notification::actionInvoked, this, [ = ](Notification::Action action) { emit ActionInvoked(notification->id(), action.identifier); }); } notification->setBody(body); notification->setSummary(summary); notification->setTimeout(expireTimeout); if (actions.count() % 2 == 0) { QList actionList; for (int i = 0; i < actions.count(); i += 2) { Notification::Action action; action.identifier = actions.at(i); action.text = actions.at(i + 1); if (hints.value("action-icons", false).toBool()) action.icon = QIcon::fromTheme(action.identifier); actionList.append(action); } notification->setActions(actionList); } if (hints.contains("desktop-entry") && Application::allApplications().contains(hints.value("desktop-entry").toString())) { notification->setApplication(ApplicationPointer(new Application(hints.value("desktop-entry").toString()))); } else { notification->setApplication(ApplicationPointer(new Application({ {"Icon", "generic-app"}, {"Name", appName} }))); } if (hints.contains("urgency")) { notification->setUrgency(static_cast(hints.value("urgency").toInt())); } return notification->id(); } void NotificationsInterface::CloseNotification(quint32 id) { NotificationPtr notification = d->tracker->get(id); if (notification) { notification->dismiss(Notification::NotificationClosedByDBus); } } QString NotificationsInterface::GetServerInformation(QString& vendor, QString& version, QString& specVersion) { vendor = "theSuite"; version = "1.0"; specVersion = "1.2"; return "theDesk"; } ================================================ FILE: plugins/NotificationsPlugin/dbus/notificationsinterface.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NOTIFICATIONSINTERFACE_H #define NOTIFICATIONSINTERFACE_H #include #include class NotificationTracker; struct NotificationsInterfacePrivate; class NotificationsInterface : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Notifications") public: explicit NotificationsInterface(NotificationTracker* tracker, QObject* parent = nullptr); ~NotificationsInterface(); public Q_SLOTS: Q_SCRIPTABLE QStringList GetCapabilities(); Q_SCRIPTABLE quint32 Notify(QString appName, quint32 replacesId, QString appIcon, QString summary, QString body, QStringList actions, QVariantMap hints, qint32 expireTimeout); Q_SCRIPTABLE void CloseNotification(quint32 id); Q_SCRIPTABLE QString GetServerInformation(QString& vendor, QString& version, QString& specVersion); signals: Q_SCRIPTABLE void NotificationClosed(quint32 id, quint32 reason); Q_SCRIPTABLE void ActionInvoked(quint32 id, QString actionKey); private: NotificationsInterfacePrivate* d; }; #endif // NOTIFICATIONSINTERFACE_H ================================================ FILE: plugins/NotificationsPlugin/dbus/org.freedesktop.Notifications.xml ================================================ ================================================ FILE: plugins/NotificationsPlugin/drawer/hudwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "hudwidget.h" #include "ui_hudwidget.h" #include #include #include #include #include #include #include struct HudWidgetPrivate { QTimer* hideTimer; bool shouldShow = false; int state = 0; double value = 0; QColor color; }; HudWidget::HudWidget(QWidget* parent) : QWidget(parent), ui(new Ui::HudWidget) { ui->setupUi(this); d = new HudWidgetPrivate(); this->setFixedHeight(0); d->hideTimer = new QTimer(this); d->hideTimer->setInterval(3000); d->hideTimer->setSingleShot(true); connect(d->hideTimer, &QTimer::timeout, this, &HudWidget::animateHide); connect(StateManager::hudManager(), &HudManager::requestHud, this, [ = ](QVariantMap params) { QPixmap icon = QIcon::fromTheme(params.value("icon", "").toString()).pixmap(SC_DPI_T(QSize(32, 32), QSize)); QString title = params.value("title", "").toString().toUpper(); QString text = params.value("text", "").toString(); double value = params.value("value", 0).toDouble(); int timeout = params.value("timeout", 3000).toInt(); QColor color = params.value("color", QColor(Qt::white)).value(); ui->iconValueIcon->setPixmap(icon); ui->iconTextIcon->setPixmap(icon); ui->iconValueTitle->setText(title); ui->iconTextTitle->setText(title); ui->iconTextText->setText(text); ui->iconValueValue->setText(QLocale().toString(value * 100, 'f', 0) + "%"); d->hideTimer->setInterval(timeout); color.setAlpha(50); d->color = color; //Decide on the layout to use if (params.contains("icon") && params.contains("title") && params.contains("text")) { //Use the icon/text HUD ui->stackedWidget->setCurrentWidget(ui->iconTextPage); d->value = value; ui->iconTextPage->update(); } else if (params.contains("icon") && params.contains("title") && params.contains("value")) { //Use the icon/value HUD ui->stackedWidget->setCurrentWidget(ui->iconValuePage); d->value = value; ui->iconValuePage->update(); } this->animateShow(); }, Qt::QueuedConnection); connect(StateManager::hudManager(), &HudManager::requestHideHud, this, [ = ] { //Immediately hide the HUD this->animateHide(); }); ui->iconValuePage->installEventFilter(this); ui->iconTextPage->installEventFilter(this); } HudWidget::~HudWidget() { delete d; delete ui; } bool HudWidget::shouldShow() { return d->shouldShow; } void HudWidget::resizeEvent(QResizeEvent* event) { ui->stackedWidget->setFixedWidth(this->width() - SC_DPI(18)); ui->stackedWidget->setFixedHeight(ui->stackedWidget->sizeHint().height()); ui->stackedWidget->move(SC_DPI(9), this->height() - ui->stackedWidget->height()); } bool HudWidget::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Paint && (watched == ui->iconValuePage || watched == ui->iconTextPage)) { QWidget* w = static_cast(watched); QPainter painter(w); painter.setBrush(d->color); painter.setPen(Qt::transparent); double val = d->value; while (val > 1) { painter.drawRect(0, 0, w->width(), w->height()); val -= 1; } painter.drawRect(0, 0, static_cast(w->width() * val), w->height()); return true; } return false; } void HudWidget::animateShow() { //Make sure we're idle if (d->state != 0) { if (d->state == 2) { d->hideTimer->stop(); d->hideTimer->start(); } return; } d->state = 1; d->hideTimer->stop(); d->shouldShow = true; emit shouldShowChanged(); tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(0); anim->setEndValue(ui->stackedWidget->height() + SC_DPI(9)); anim->setEasingCurve(QEasingCurve::OutCubic); anim->setDuration(250); connect(anim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { this->setFixedHeight(value.toInt()); emit shouldShowChanged(); }); connect(anim, &tVariantAnimation::finished, this, [ = ] { anim->deleteLater(); d->hideTimer->start(); d->state = 2; }); anim->start(); } void HudWidget::animateHide() { if (d->state != 2) return; //Make sure we're showing d->state = 3; d->hideTimer->stop(); tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(this->height()); anim->setEndValue(0); anim->setEasingCurve(QEasingCurve::OutCubic); anim->setDuration(250); connect(anim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { this->setFixedHeight(value.toInt()); emit shouldShowChanged(); }); connect(anim, &tVariantAnimation::finished, this, [ = ] { anim->deleteLater(); d->state = 0; d->shouldShow = false; emit shouldShowChanged(); }); anim->start(); } ================================================ FILE: plugins/NotificationsPlugin/drawer/hudwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef HUDWIDGET_H #define HUDWIDGET_H #include namespace Ui { class HudWidget; } struct HudWidgetPrivate; class HudWidget : public QWidget { Q_OBJECT public: explicit HudWidget(QWidget* parent = nullptr); ~HudWidget(); bool shouldShow(); signals: void shouldShowChanged(); private: Ui::HudWidget* ui; HudWidgetPrivate* d; void resizeEvent(QResizeEvent* event); bool eventFilter(QObject* watched, QEvent* event); void animateShow(); void animateHide(); }; #endif // HUDWIDGET_H ================================================ FILE: plugins/NotificationsPlugin/drawer/hudwidget.ui ================================================ HudWidget 0 0 400 58 Form 9 9 381 41 true QFrame::StyledPanel 0 Icon 0 0 true VOLUME 50% Icon true VOLUME 0 0 Text true ================================================ FILE: plugins/NotificationsPlugin/drawer/notificationsdrawer.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "notificationsdrawer.h" #include "ui_notificationsdrawer.h" #include "notificationsdrawerwidget.h" #include "notificationtracker.h" #include #include #include #include #include #include #include #include struct NotificationsDrawerPrivate { NotificationTracker* tracker; QList widgets; QScreen* oldPrimaryScreen = nullptr; }; NotificationsDrawer::NotificationsDrawer(NotificationTracker* tracker) : QDialog(nullptr), ui(new Ui::NotificationsDrawer) { ui->setupUi(this); d = new NotificationsDrawerPrivate(); d->tracker = tracker; connect(tracker, &NotificationTracker::destroyed, this, &NotificationsDrawer::deleteLater); connect(tracker, &NotificationTracker::newNotification, this, &NotificationsDrawer::showNotification); this->setAttribute(Qt::WA_TranslucentBackground); this->setAttribute(Qt::WA_ShowWithoutActivating); this->setWindowFlag(Qt::FramelessWindowHint); this->setWindowFlag(Qt::WindowStaysOnTopHint); DesktopWm::setSystemWindow(this, DesktopWm::SystemWindowTypeNotification); connect(StateManager::barManager(), &BarManager::barHeightChanged, this, &NotificationsDrawer::updateGeometry); connect(StateManager::gatewayManager(), &GatewayManager::gatewayWidthChanged, this, &NotificationsDrawer::updateGeometry); connect(ui->hudWidget, &HudWidget::shouldShowChanged, this, &NotificationsDrawer::updateGeometry); connect(qApp, &QApplication::primaryScreenChanged, this, &NotificationsDrawer::updateGeometry); updateGeometry(); } NotificationsDrawer::~NotificationsDrawer() { delete ui; } void NotificationsDrawer::setFixedHeight(int height) { QDialog::setFixedHeight(height); // Work around a Qt bug that causes the native window not to be updated on Wayland for some reason this->windowHandle()->setGeometry(this->geometry()); } void NotificationsDrawer::setFixedWidth(int width) { QWidget::setFixedWidth(width); // Work around a Qt bug that causes the native window not to be updated on Wayland for some reason this->windowHandle()->setGeometry(this->geometry()); } bool NotificationsDrawer::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::LayoutRequest) { this->updateGeometry(); } return false; } void NotificationsDrawer::updateGeometry() { QScreen* primaryScreen = qApp->primaryScreen(); if (d->oldPrimaryScreen != primaryScreen && d->oldPrimaryScreen) { disconnect(d->oldPrimaryScreen, &QScreen::geometryChanged, this, &NotificationsDrawer::updateGeometry); } if (!d->oldPrimaryScreen) { connect(primaryScreen, &QScreen::geometryChanged, this, &NotificationsDrawer::updateGeometry); } d->oldPrimaryScreen = primaryScreen; this->setFixedWidth(400); this->setFixedHeight(this->sizeHint().height()); QRect geometry; geometry.setSize(this->size()); if (this->layoutDirection() == Qt::RightToLeft) { geometry.moveTopRight(primaryScreen->geometry().topRight() + QPoint(-StateManager::gatewayManager()->gatewayWidth(), StateManager::barManager()->barHeight())); } else { geometry.moveTopLeft(primaryScreen->geometry().topLeft() + QPoint(StateManager::gatewayManager()->gatewayWidth(), StateManager::barManager()->barHeight())); } if (geometry.bottom() > primaryScreen->geometry().bottom()) geometry.moveBottom(primaryScreen->geometry().bottom()); this->move(geometry.topLeft()); if (d->widgets.count() == 0 && !ui->hudWidget->shouldShow()) { this->hide(); } else { this->show(); } } void NotificationsDrawer::showNotification(NotificationPtr notification) { switch (StateManager::quietModeManager()->currentMode()) { case QuietModeManagerTd::CriticalOnly: if (notification->urgency() != Notification::Critical) return; break; case QuietModeManagerTd::NoNotifications: case QuietModeManagerTd::Mute: return; default: break; } NotificationsDrawerWidget* w = new NotificationsDrawerWidget(notification, d->tracker, this); w->installEventFilter(this); d->widgets.append(w); ui->notificationsLayout->addWidget(w); this->updateGeometry(); connect(w, &NotificationsDrawerWidget::dismiss, this, [=] { d->widgets.removeOne(w); ui->notificationsLayout->removeWidget(w); w->deleteLater(); this->updateGeometry(); }); w->show(); this->updateGeometry(); } ================================================ FILE: plugins/NotificationsPlugin/drawer/notificationsdrawer.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NOTIFICATIONSDRAWER_H #define NOTIFICATIONSDRAWER_H #include "notification.h" #include namespace Ui { class NotificationsDrawer; } class NotificationTracker; struct NotificationsDrawerPrivate; class NotificationsDrawer : public QDialog { Q_OBJECT public: explicit NotificationsDrawer(NotificationTracker* tracker); ~NotificationsDrawer(); void setFixedHeight(int height); void setFixedWidth(int width); private: Ui::NotificationsDrawer* ui; NotificationsDrawerPrivate* d; bool eventFilter(QObject* watched, QEvent* event); void updateGeometry(); void showNotification(NotificationPtr notification); }; #endif // NOTIFICATIONSDRAWER_H ================================================ FILE: plugins/NotificationsPlugin/drawer/notificationsdrawer.ui ================================================ NotificationsDrawer 0 0 400 17 Dialog 0 0 0 0 0 0 Qt::Vertical 20 5 HudWidget QWidget
drawer/hudwidget.h
1
================================================ FILE: plugins/NotificationsPlugin/drawer/notificationsdrawerwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "notificationsdrawerwidget.h" #include "ui_notificationsdrawerwidget.h" #include #include #include #include #include "notificationtracker.h" #include "notification.h" struct NotificationsDrawerWidgetPrivate { NotificationTracker* tracker; tVariantAnimation* timeout; tVariantAnimation* actionsWidgetHeight; NotificationPtr n; QList actions; QGraphicsOpacityEffect* effect; bool shouldTimeoutRun = false; }; NotificationsDrawerWidget::NotificationsDrawerWidget(NotificationPtr notification, NotificationTracker* tracker, QWidget* parent) : QWidget(parent), ui(new Ui::NotificationsDrawerWidget) { ui->setupUi(this); d = new NotificationsDrawerWidgetPrivate(); d->n = notification; d->tracker = tracker; ui->summaryLabel->setText(notification->summary()); ui->bodyLabel->setText(notification->body()); connect(notification, &Notification::summaryChanged, ui->summaryLabel, &QLabel::setText); connect(notification, &Notification::bodyChanged, ui->bodyLabel, &QLabel::setText); connect(notification, &Notification::dismissed, this, &NotificationsDrawerWidget::animateDismiss); d->timeout = new tVariantAnimation(this); d->timeout->setStartValue(1.0); d->timeout->setEndValue(0.0); d->timeout->setEasingCurve(QEasingCurve::Linear); d->timeout->setForceAnimation(true); if (notification->timeout() == 0) { d->timeout->setDuration(-1); } else { d->timeout->setDuration(notification->timeout()); } connect(d->timeout, &tVariantAnimation::finished, this, &NotificationsDrawerWidget::animateDismiss); connect(d->tracker, &NotificationTracker::pauseTimeouts, this, [ = ] { d->timeout->pause(); }); connect(d->tracker, &NotificationTracker::resumeTimeouts, this, [ = ] { if (d->shouldTimeoutRun && d->n->timeout() != 0) { d->timeout->start(); } }); connect(notification, &Notification::timeoutChanged, this, [ = ](qint32 timeout) { if (timeout == 0) { d->timeout->setDuration(-1); } else { d->timeout->setDuration(timeout); } }); ui->appIconLabel->setPixmap(QIcon::fromTheme(notification->application()->getProperty("Icon").toString()).pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->appNameLabel->setText(notification->application()->getProperty("Name").toString()); connect(notification, &Notification::applicationChanged, this, [ = ] { ui->appIconLabel->setPixmap(QIcon::fromTheme(notification->application()->getProperty("Icon").toString()).pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->appNameLabel->setText(notification->application()->getProperty("Name").toString()); }); ui->actionsWidget->setFixedHeight(0); connect(notification, &Notification::actionsChanged, this, &NotificationsDrawerWidget::setupActions); setupActions(); d->actionsWidgetHeight = new tVariantAnimation(this); d->actionsWidgetHeight->setDuration(250); d->actionsWidgetHeight->setEasingCurve(QEasingCurve::OutCubic); connect(d->actionsWidgetHeight, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { ui->actionsWidget->setFixedHeight(value.toInt()); ui->mainFrame->setFixedHeight(ui->mainFrame->sizeHint().height()); this->updateGeometry(); }); connect(d->actionsWidgetHeight, &tVariantAnimation::finished, this, [ = ] { ui->mainFrame->setFixedHeight(ui->mainFrame->sizeHint().height()); this->updateGeometry(); }); ui->buttonBox->setParent(ui->mainFrame); ui->buttonBox->move(this->layoutDirection() == Qt::RightToLeft ? 0 : ui->mainFrame->width() - ui->buttonBox->width(), 0); ui->buttonBox->setVisible(false); ui->mainFrame->installEventFilter(this); d->effect = new QGraphicsOpacityEffect(this); d->effect->setEnabled(false); this->setGraphicsEffect(d->effect); } NotificationsDrawerWidget::~NotificationsDrawerWidget() { delete ui; delete d; } void NotificationsDrawerWidget::show() { QWidget::show(); tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(this->layoutDirection() == Qt::RightToLeft ? ui->mainFrame->width() : -ui->mainFrame->width()); anim->setEndValue(SC_DPI(9)); anim->setEasingCurve(QEasingCurve::OutCubic); anim->setDuration(250); connect(anim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { ui->mainFrame->move(value.toInt(), SC_DPI(9)); }); connect(anim, &tVariantAnimation::finished, this, [ = ] { d->shouldTimeoutRun = true; if (d->n->timeout() != 0) { d->timeout->start(); } }); anim->start(); } void NotificationsDrawerWidget::animateDismiss() { d->shouldTimeoutRun = false; tVariantAnimation* opacityAnim = new tVariantAnimation(this); opacityAnim->setStartValue(1.0); opacityAnim->setEndValue(0.0); opacityAnim->setEasingCurve(QEasingCurve::OutCubic); opacityAnim->setDuration(250); connect(opacityAnim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { d->effect->setOpacity(value.toDouble()); }); connect(opacityAnim, &tVariantAnimation::finished, this, [ = ] { opacityAnim->deleteLater(); tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(this->height()); anim->setEndValue(0); anim->setEasingCurve(QEasingCurve::OutCubic); anim->setDuration(250); connect(anim, &tVariantAnimation::valueChanged, this, [ = ](QVariant value) { this->setFixedHeight(value.toInt()); }); connect(anim, &tVariantAnimation::finished, this, [ = ] { anim->deleteLater(); emit dismiss(); }); anim->start(); }); d->effect->setEnabled(true); opacityAnim->start(); } QSize NotificationsDrawerWidget::sizeHint() const { QSize sizeHint = QWidget::sizeHint(); sizeHint.setHeight(ui->mainFrame->sizeHint().height() + SC_DPI(9)); return sizeHint; } void NotificationsDrawerWidget::resizeEvent(QResizeEvent* event) { ui->mainFrame->setFixedWidth(this->width() - SC_DPI(18)); ui->mainFrame->setFixedHeight(ui->mainFrame->sizeHint().height()); ui->buttonBox->move(this->layoutDirection() == Qt::RightToLeft ? 0 : ui->mainFrame->width() - ui->buttonBox->width(), 0); } bool NotificationsDrawerWidget::eventFilter(QObject* watched, QEvent* event) { if (watched == ui->mainFrame) { switch (event->type()) { case QEvent::Enter: showButtons(); break; case QEvent::Leave: hideButtons(); break; default: break; } } return false; } void NotificationsDrawerWidget::setupActions() { for (QPushButton* button : d->actions) { ui->actionsLayout->removeWidget(button); button->deleteLater(); } d->actions.clear(); for (Notification::Action action : d->n->actions()) { QPushButton* button = new QPushButton(); button->setText(action.text); button->setIcon(action.icon); connect(button, &QPushButton::clicked, this, [ = ] { emit d->n->actionInvoked(action); this->animateDismiss(); }); ui->actionsLayout->addWidget(button); d->actions.append(button); } } void NotificationsDrawerWidget::showButtons() { d->tracker->pauseTimeouts(); ui->buttonBox->setVisible(true); d->actionsWidgetHeight->stop(); d->actionsWidgetHeight->setStartValue(ui->actionsWidget->height()); d->actionsWidgetHeight->setEndValue(ui->actionsWidget->sizeHint().height()); d->actionsWidgetHeight->start(); } void NotificationsDrawerWidget::hideButtons() { d->tracker->resumeTimeouts(); ui->buttonBox->setVisible(false); d->actionsWidgetHeight->stop(); d->actionsWidgetHeight->setStartValue(ui->actionsWidget->height()); d->actionsWidgetHeight->setEndValue(0); d->actionsWidgetHeight->start(); } void NotificationsDrawerWidget::on_closeButton_clicked() { d->n->dismiss(Notification::NotificationUserDismissed); } void NotificationsDrawerWidget::on_dismissButton_clicked() { this->animateDismiss(); } ================================================ FILE: plugins/NotificationsPlugin/drawer/notificationsdrawerwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NOTIFICATIONSDRAWERWIDGET_H #define NOTIFICATIONSDRAWERWIDGET_H #include namespace Ui { class NotificationsDrawerWidget; } class Notification; typedef QPointer NotificationPtr; struct NotificationsDrawerWidgetPrivate; class NotificationTracker; class NotificationsDrawerWidget : public QWidget { Q_OBJECT public: explicit NotificationsDrawerWidget(NotificationPtr notification, NotificationTracker* tracker, QWidget* parent = nullptr); ~NotificationsDrawerWidget(); void show(); void animateDismiss(); QSize sizeHint() const; signals: void dismiss(); private slots: void on_closeButton_clicked(); void on_dismissButton_clicked(); private: Ui::NotificationsDrawerWidget* ui; NotificationsDrawerWidgetPrivate* d; void resizeEvent(QResizeEvent* event); bool eventFilter(QObject* watched, QEvent* event); void setupActions(); void showButtons(); void hideButtons(); }; #endif // NOTIFICATIONSDRAWERWIDGET_H ================================================ FILE: plugins/NotificationsPlugin/drawer/notificationsdrawerwidget.ui ================================================ NotificationsDrawerWidget 0 0 551 173 Form 0 0 331 111 true QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 Icon 8 App Name Qt::Horizontal 40 20 true Summary Body true 0 0 0 0 0 481 0 71 42 0 0 0 0 0 .. true .. true ================================================ FILE: plugins/NotificationsPlugin/notification.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "notification.h" #include struct NotificationPrivate { quint32 id; qint32 timeout; QString summary; QString body; Notification::Urgency urgency = Notification::Normal; QList actions; ApplicationPointer application; bool isActive = true; }; Notification::Notification(quint32 id) { d = new NotificationPrivate(); d->id = id; } Notification::~Notification() { delete d; } quint32 Notification::id() { return d->id; } void Notification::setSummary(QString summary) { d->summary = summary; emit summaryChanged(summary); } QString Notification::summary() { return d->summary; } void Notification::setBody(QString body) { d->body = body; emit bodyChanged(body); } QString Notification::body() { return d->body; } void Notification::setTimeout(qint32 timeout) { if (timeout == -1) timeout = 5000; d->timeout = timeout; emit timeoutChanged(timeout); } qint32 Notification::timeout() { return d->timeout; } void Notification::setApplication(ApplicationPointer application) { d->application = application; emit applicationChanged(application); } ApplicationPointer Notification::application() { return d->application; } void Notification::setActions(QList actions) { d->actions = actions; emit actionsChanged(actions); } QList Notification::actions() { return d->actions; } void Notification::setUrgency(Notification::Urgency urgency) { d->urgency = urgency; } Notification::Urgency Notification::urgency() { return d->urgency; } void Notification::dismiss(Notification::NotificationCloseReason reason) { if (!d->isActive) return; d->isActive = false; emit dismissed(reason); } ================================================ FILE: plugins/NotificationsPlugin/notification.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NOTIFICATION_H #define NOTIFICATION_H #include #include #include #include class NotificationTracker; struct NotificationPrivate; class Notification : public QObject { Q_OBJECT public: enum NotificationCloseReason : quint32 { NotificationExpired = 1, NotificationUserDismissed = 2, NotificationClosedByDBus = 3, NotificationCloseReasonUndefined = 4 }; enum Urgency { Low = 0, Normal = 1, Critical = 2 }; struct Action { QString text; QString identifier; QIcon icon; }; ~Notification(); quint32 id(); void setSummary(QString summary); QString summary(); void setBody(QString body); QString body(); void setTimeout(qint32 timeout); qint32 timeout(); void setApplication(ApplicationPointer application); ApplicationPointer application(); void setActions(QList actions); QList actions(); void setUrgency(Urgency urgency); Urgency urgency(); void dismiss(NotificationCloseReason reason); signals: void summaryChanged(QString summary); void bodyChanged(QString body); void timeoutChanged(qint32 timeout); void applicationChanged(ApplicationPointer application); void actionsChanged(QList actions); void dismissed(NotificationCloseReason reason); void actionInvoked(Action action); protected: friend NotificationTracker; explicit Notification(quint32 id); private: NotificationPrivate* d; }; typedef QPointer NotificationPtr; #endif // NOTIFICATION_H ================================================ FILE: plugins/NotificationsPlugin/notificationtracker.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "notificationtracker.h" #include #include #include #include "notification.h" struct NotificationTrackerPrivate { quint32 lastNotification = 1; QMap notifications; }; NotificationTracker::NotificationTracker(QObject* parent) : QObject(parent) { d = new NotificationTrackerPrivate(); } NotificationTracker::~NotificationTracker() { delete d; } NotificationPtr NotificationTracker::createNotification() { quint32 notificationId = d->lastNotification; NotificationPtr n(new Notification(notificationId)); connect(n.data(), &Notification::dismissed, this, [ = ] { d->notifications.remove(notificationId); }); d->notifications.insert(notificationId, n); d->lastNotification++; QTimer::singleShot(0, this, std::bind(&NotificationTracker::newNotification, this, n)); return n; } NotificationPtr NotificationTracker::get(quint32 id) { if (id == 0) return nullptr; return d->notifications.value(id); } ================================================ FILE: plugins/NotificationsPlugin/notificationtracker.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NOTIFICATIONTRACKER_H #define NOTIFICATIONTRACKER_H #include #include class Notification; typedef QPointer NotificationPtr; struct NotificationTrackerPrivate; class NotificationTracker : public QObject { Q_OBJECT public: explicit NotificationTracker(QObject* parent = nullptr); ~NotificationTracker(); NotificationPtr createNotification(); NotificationPtr get(quint32 id); signals: void newNotification(NotificationPtr notification); void pauseTimeouts(); void resumeTimeouts(); private: NotificationTrackerPrivate* d; }; #endif // NOTIFICATIONTRACKER_H ================================================ FILE: plugins/NotificationsPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "chunks/mprischunk.h" #include "dbus/notificationsinterface.h" #include "drawer/notificationsdrawer.h" #include "notificationtracker.h" #include "statuscenter/notificationsstatuscenterpane.h" #include #include #include #include #include #include #include #include #include #include #include #include struct PluginPrivate { NotificationTracker* tracker; NotificationsInterface* interface; NotificationsDrawer* drawer; NotificationsStatusCenterPane* statusCenter; SystemJobController* jobController; MprisChunk* mprisChunk; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/NotificationsPlugin/thedesk-notifications.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-notifications.conf"); d->tracker = new NotificationTracker(); d->interface = new NotificationsInterface(d->tracker); d->drawer = new NotificationsDrawer(d->tracker); d->jobController = new SystemJobController(QDBusConnection::sessionBus()); d->statusCenter = new NotificationsStatusCenterPane(d->tracker, d->jobController); StateManager::statusCenterManager()->addPane(d->statusCenter, StatusCenterManager::Informational); d->mprisChunk = new MprisChunk(); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->statusCenter); d->tracker->deleteLater(); d->statusCenter->deleteLater(); d->mprisChunk->deleteLater(); d->jobController->deleteLater(); // Everything else will delete itself once the tracker is gone tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/NotificationsPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/NotificationsPlugin/statuscenter/jobwidget.cpp ================================================ #include "jobwidget.h" #include "ui_jobwidget.h" struct JobWidgetPrivate { bool loadingData = true; SystemJobPtr job; }; JobWidget::JobWidget(SystemJobPtr job, QWidget* parent) : QWidget(parent), ui(new Ui::JobWidget) { ui->setupUi(this); d = new JobWidgetPrivate(); d->job = job; connect(job.data(), &SystemJob::titleChanged, ui->summaryLabel, &QLabel::setText); connect(job.data(), &SystemJob::statusChanged, ui->bodyLabel, &QLabel::setText); connect(job.data(), &SystemJob::totalProgressChanged, this, [this](quint64 totalProgress) { ui->progressBar->setMaximum(totalProgress); }); connect(job.data(), &SystemJob::progressChanged, ui->progressBar, &QProgressBar::setValue); connect(job.data(), &SystemJob::stateChanged, this, &JobWidget::updateState); connect(job.data(), &SystemJob::validChanged, this, [this](bool valid) { if (!valid && !d->loadingData) this->deleteLater(); }); loadData(); } JobWidget::~JobWidget() { delete ui; delete d; } void JobWidget::setIsLast(bool isLast) { ui->line->setVisible(!isLast); } QCoro::Task<> JobWidget::loadData() { d->loadingData = true; ui->summaryLabel->setText(co_await d->job->title()); ui->bodyLabel->setText(co_await d->job->status()); ui->progressBar->setMaximum(co_await d->job->totalProgress()); ui->progressBar->setValue(co_await d->job->progress()); updateState(co_await d->job->state()); if (!d->job->valid()) this->deleteLater(); d->loadingData = false; } void JobWidget::updateState(QString state) { if (state == QStringLiteral("Processing")) { } else if (state == QStringLiteral("Finished")) { this->deleteLater(); } else if (state == QStringLiteral("Failed")) { this->deleteLater(); } else if (state == QStringLiteral("RequiresAttention")) { } } ================================================ FILE: plugins/NotificationsPlugin/statuscenter/jobwidget.h ================================================ #ifndef JOBWIDGET_H #define JOBWIDGET_H #include #include namespace Ui { class JobWidget; } struct JobWidgetPrivate; class JobWidget : public QWidget { Q_OBJECT public: explicit JobWidget(SystemJobPtr job, QWidget* parent = nullptr); ~JobWidget(); void setIsLast(bool isLast); private: Ui::JobWidget* ui; JobWidgetPrivate* d; QCoro::Task<> loadData(); void updateState(QString state); }; #endif // JOBWIDGET_H ================================================ FILE: plugins/NotificationsPlugin/statuscenter/jobwidget.ui ================================================ JobWidget 0 0 400 90 Form 0 0 0 0 0 6 9 9 9 9 true Summary Body true 24 16777215 1 Qt::Horizontal ================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationappgroup.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "notificationappgroup.h" #include "ui_notificationappgroup.h" #include #include #include #include "jobwidget.h" #include "notificationwidget.h" struct NotificationAppGroupPrivate { ApplicationPointer application; QMap widgets; QList ordering; QList jobOrdering; }; NotificationAppGroup::NotificationAppGroup(ApplicationPointer application, QWidget* parent) : QWidget(parent), ui(new Ui::NotificationAppGroup) { ui->setupUi(this); d = new NotificationAppGroupPrivate(); d->application = application; if (d->application) { ui->iconLabel->setPixmap(QIcon::fromTheme(application->getProperty("Icon").toString()).pixmap(QSize(16, 16))); ui->appNameLabel->setText(application->getProperty("Name").toString()); } else { ui->iconLabel->setPixmap(QIcon::fromTheme("generic-app").pixmap(QSize(16, 16))); ui->appNameLabel->setText(tr("Uncategorised")); } } NotificationAppGroup::~NotificationAppGroup() { delete d; delete ui; } void NotificationAppGroup::pushNotification(NotificationPtr notification) { NotificationWidget* w = new NotificationWidget(notification); connect( w, &NotificationWidget::destroyed, this, [=] { d->widgets.remove(notification); d->ordering.removeOne(w); this->dismissOrReorder(); }, Qt::QueuedConnection); ui->notificationsLayout->insertWidget(0, w); d->widgets.insert(notification, w); d->ordering.insert(0, w); setOrdering(); } void NotificationAppGroup::pushJob(SystemJobPtr job) { auto w = new JobWidget(job); connect(w, &JobWidget::destroyed, this, [this, w] { d->jobOrdering.removeOne(w); this->dismissOrReorder(); }); ui->jobsLayout->insertWidget(0, w); d->jobOrdering.insert(0, w); setOrdering(); } void NotificationAppGroup::dismissAll() { for (NotificationPtr notification : d->widgets.keys()) { notification->dismiss(Notification::NotificationUserDismissed); } } void NotificationAppGroup::setOrdering() { ui->dismissAllButton->setVisible(!d->ordering.isEmpty()); for (JobWidget* w : d->jobOrdering) { w->setIsLast(false); } if (d->ordering.isEmpty()) d->jobOrdering.constLast()->setIsLast(true); for (NotificationWidget* w : d->ordering) { w->setIsLast(false); } if (!d->ordering.isEmpty()) d->ordering.last()->setIsLast(true); } void NotificationAppGroup::dismissOrReorder() { if (d->ordering.isEmpty() && d->jobOrdering.isEmpty()) { this->deleteLater(); } else { setOrdering(); } } void NotificationAppGroup::on_dismissAllButton_clicked() { dismissAll(); } ================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationappgroup.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NOTIFICATIONAPPGROUP_H #define NOTIFICATIONAPPGROUP_H #include "notification.h" #include #include #include namespace Ui { class NotificationAppGroup; } struct NotificationAppGroupPrivate; class NotificationAppGroup : public QWidget { Q_OBJECT public: explicit NotificationAppGroup(ApplicationPointer application, QWidget* parent = nullptr); ~NotificationAppGroup(); void pushNotification(NotificationPtr notification); void pushJob(SystemJobPtr job); void dismissAll(); private slots: void on_dismissAllButton_clicked(); private: Ui::NotificationAppGroup* ui; NotificationAppGroupPrivate* d; void setOrdering(); void dismissOrReorder(); }; #endif // NOTIFICATIONAPPGROUP_H ================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationappgroup.ui ================================================ NotificationAppGroup 0 0 533 339 Form 0 0 0 0 0 0 0 0 0 0 6 9 9 9 TextLabel 0 0 TextLabel .. QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationsstatuscenterpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "notificationsstatuscenterpane.h" #include "ui_notificationsstatuscenterpane.h" #include "notification.h" #include "notificationappgroup.h" #include "notificationtracker.h" #include #include #include #include #include struct NotificationsStatusCenterPanePrivate { NotificationTracker* tracker; SystemJobController* jobController; QMap groups; }; NotificationsStatusCenterPane::NotificationsStatusCenterPane(NotificationTracker* tracker, SystemJobController* jobController) : StatusCenterPane(), ui(new Ui::NotificationsStatusCenterPane) { ui->setupUi(this); d = new NotificationsStatusCenterPanePrivate(); d->tracker = tracker; d->jobController = jobController; ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->notificationsWidget->setFixedWidth(contentWidth); ui->quietModeWidget->setFixedWidth(contentWidth); connect(d->tracker, &NotificationTracker::newNotification, this, [=](NotificationPtr notification) { auto application = notification->application(); QString desktopEntry; if (application) { desktopEntry = application->desktopEntry(); } auto group = appGroupForDesktopEntry(desktopEntry, application); group->pushNotification(notification); ui->stackedWidget->setCurrentWidget(ui->notificationsPage); }); connect(d->jobController, &SystemJobController::newJob, this, &NotificationsStatusCenterPane::registerJob); for (const auto& job : d->jobController->jobs()) { registerJob(job); } ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->notificationSplash->setPixmap(QIcon::fromTheme("notifications").pixmap(QSize(128, 128))); for (QuietModeManagerTd::QuietMode mode : StateManager::quietModeManager()->availableQuietModes()) { QuietModeManagerTd::QuietMode m = mode; QPushButton* button = new QPushButton(this); button->setText(StateManager::quietModeManager()->name(m)); button->setIcon(QIcon::fromTheme(StateManager::quietModeManager()->icon(m))); button->setCheckable(true); button->setAutoExclusive(true); button->setChecked(StateManager::quietModeManager()->currentMode() == m); connect(button, &QPushButton::toggled, this, [=](bool checked) { if (checked) { StateManager::quietModeManager()->setQuietMode(m); } }); connect(StateManager::quietModeManager(), &QuietModeManagerTd::quietModeChanged, this, [=](QuietModeManagerTd::QuietMode newMode, QuietModeManagerTd::QuietMode oldMode) { Q_UNUSED(oldMode); button->setChecked(newMode == m); }); ui->quietModesLayout->addWidget(button); } } NotificationsStatusCenterPane::~NotificationsStatusCenterPane() { delete d; delete ui; } void NotificationsStatusCenterPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } NotificationAppGroup* NotificationsStatusCenterPane::appGroupForDesktopEntry(QString desktopEntry, ApplicationPointer application) { if (d->groups.contains(desktopEntry)) { return d->groups.value(desktopEntry); } else { auto group = new NotificationAppGroup(application, this); connect( group, &NotificationAppGroup::destroyed, this, [=] { ui->notificationsLayout->removeWidget(group); d->groups.remove(desktopEntry); if (d->groups.isEmpty()) ui->stackedWidget->setCurrentWidget(ui->noNotificationsPage); }, Qt::QueuedConnection); ui->notificationsLayout->insertWidget(0, group); d->groups.insert(desktopEntry, group); return group; } } void NotificationsStatusCenterPane::registerJob(SystemJobPtr job) { auto desktopEntry = d->jobController->desktopEntryForService(job->service()); auto app = ApplicationPointer(new Application(desktopEntry)); auto group = appGroupForDesktopEntry(desktopEntry, app); group->pushJob(job); ui->stackedWidget->setCurrentWidget(ui->notificationsPage); } QString NotificationsStatusCenterPane::name() { return "NotificationsPane"; } QString NotificationsStatusCenterPane::displayName() { return tr("Notifications"); } QIcon NotificationsStatusCenterPane::icon() { return QIcon::fromTheme("thedesk-notifications"); } QWidget* NotificationsStatusCenterPane::leftPane() { return nullptr; } void NotificationsStatusCenterPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationsstatuscenterpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NOTIFICATIONSSTATUSCENTERPANE_H #define NOTIFICATIONSSTATUSCENTERPANE_H #include #include #include namespace Ui { class NotificationsStatusCenterPane; } class NotificationAppGroup; class SystemJobController; class NotificationTracker; struct NotificationsStatusCenterPanePrivate; class NotificationsStatusCenterPane : public StatusCenterPane { Q_OBJECT public: explicit NotificationsStatusCenterPane(NotificationTracker* tracker, SystemJobController* jobController); ~NotificationsStatusCenterPane(); private slots: void on_titleLabel_backButtonClicked(); private: Ui::NotificationsStatusCenterPane* ui; NotificationsStatusCenterPanePrivate* d; NotificationAppGroup* appGroupForDesktopEntry(QString desktopEntry, ApplicationPointer application); void registerJob(SystemJobPtr job); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // NOTIFICATIONSSTATUSCENTERPANE_H ================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationsstatuscenterpane.ui ================================================ NotificationsStatusCenterPane 0 0 572 429 Form 0 0 0 0 0 Notifications 75 true QUIET MODE 0 0 Qt::Horizontal 40 20 0 Qt::Vertical 20 117 20 Is it Friday yet? Qt::AlignCenter false TextLabel Qt::AlignCenter You've caught up with your notifications! Qt::AlignCenter Qt::Vertical 20 117 0 0 0 0 0 QFrame::NoFrame true 0 0 100 30 0 0 0 0 0 16777215 1 Qt::Horizontal 0 0 0 0 0 6 Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "notificationwidget.h" #include "ui_notificationwidget.h" #include struct NotificationWidgetPrivate { NotificationPtr notification; QToolButton* dismissButton; }; NotificationWidget::NotificationWidget(NotificationPtr notification, QWidget* parent) : QWidget(parent), ui(new Ui::NotificationWidget) { ui->setupUi(this); d = new NotificationWidgetPrivate(); d->notification = notification; connect(notification, &Notification::dismissed, this, &NotificationWidget::deleteLater); connect(notification, &Notification::summaryChanged, this, [ = ](QString summary) { ui->summaryLabel->setText(summary); }); connect(notification, &Notification::bodyChanged, this, [ = ](QString body) { ui->bodyLabel->setText(body); }); ui->summaryLabel->setText(notification->summary()); ui->bodyLabel->setText(notification->body()); d->dismissButton = new QToolButton(this); d->dismissButton->setIcon(QIcon::fromTheme("window-close")); d->dismissButton->setFixedSize(d->dismissButton->sizeHint()); connect(d->dismissButton, &QToolButton::clicked, this, [ = ] { notification->dismiss(Notification::NotificationUserDismissed); }); d->dismissButton->hide(); } NotificationWidget::~NotificationWidget() { delete d; delete ui; } void NotificationWidget::setIsLast(bool isLast) { ui->line->setVisible(!isLast); } void NotificationWidget::resizeEvent(QResizeEvent* event) { d->dismissButton->move(this->width() - d->dismissButton->width(), 0); } void NotificationWidget::enterEvent(QEvent* event) { d->dismissButton->show(); } void NotificationWidget::leaveEvent(QEvent* event) { d->dismissButton->hide(); } ================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef NOTIFICATIONWIDGET_H #define NOTIFICATIONWIDGET_H #include #include "notification.h" namespace Ui { class NotificationWidget; } struct NotificationWidgetPrivate; class NotificationWidget : public QWidget { Q_OBJECT public: explicit NotificationWidget(NotificationPtr notification, QWidget* parent = nullptr); ~NotificationWidget(); void setIsLast(bool isLast); private: Ui::NotificationWidget* ui; NotificationWidgetPrivate* d; void resizeEvent(QResizeEvent* event); void enterEvent(QEvent* event); void leaveEvent(QEvent* event); }; #endif // NOTIFICATIONWIDGET_H ================================================ FILE: plugins/NotificationsPlugin/statuscenter/notificationwidget.ui ================================================ NotificationWidget 0 0 400 59 Form 0 0 0 0 0 9 9 9 9 75 true Summary Body true 16777215 1 Qt::Horizontal ================================================ FILE: plugins/NotificationsPlugin/thedesk-notifications.conf ================================================ ================================================ FILE: plugins/NotificationsPlugin/translations/ar_SA.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/au_AU.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/cy.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/da.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/de.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/en_GB.ts ================================================ JobWidget Form MprisChunk Media Players Media Players NotificationAppGroup Uncategorised Uncategorised NotificationsStatusCenterPane Notifications Notifications Is it Friday yet? Is it Friday yet? You've caught up with your notifications! You've caught up with your notifications! QUIET MODE QUIET MODE ================================================ FILE: plugins/NotificationsPlugin/translations/en_US.qm ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/es.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/es_VE.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/id.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/nl.ts ================================================ JobWidget Form MprisChunk Media Players Mediaspelers NotificationAppGroup Uncategorised Ongecategoriseerd NotificationsStatusCenterPane Notifications Meldingen QUIET MODE STILTEMODUS Is it Friday yet? Is het al vrijdag? You've caught up with your notifications! Je hebt al je meldingen gezien! ================================================ FILE: plugins/NotificationsPlugin/translations/pt_BR.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/ro_RO.ts ================================================ JobWidget Form MprisChunk Media Players Playere media NotificationAppGroup Uncategorised Necategorisite NotificationsStatusCenterPane Notifications Notificări Is it Friday yet? Este vineri azi? You've caught up with your notifications! Ați citit toate notificările! QUIET MODE MOD SILENȚIOS ================================================ FILE: plugins/NotificationsPlugin/translations/sv.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised NotificationsStatusCenterPane Notifications QUIET MODE Is it Friday yet? You've caught up with your notifications! ================================================ FILE: plugins/NotificationsPlugin/translations/tr_TR.ts ================================================ JobWidget Form MprisChunk Media Players Medya Oynatıcılar NotificationAppGroup Uncategorised Kategorize edilmemiş NotificationsStatusCenterPane Notifications Bildirimler Is it Friday yet? Cuma oldu mu? You've caught up with your notifications! Bildirimlerinizi yakaladınız! QUIET MODE SESSİZ MOD ================================================ FILE: plugins/NotificationsPlugin/translations/vi.ts ================================================ JobWidget Form MprisChunk Media Players Trình phát phương tiện NotificationAppGroup Uncategorised Không phân loại NotificationsStatusCenterPane Notifications Thông báo QUIET MODE CHẾ ĐỘ IM Is it Friday yet? Có phải thứ sáu chưa? You've caught up with your notifications! Bạn đã cập nhật về các thông báo! ================================================ FILE: plugins/NotificationsPlugin/translations/vi_VN.ts ================================================ JobWidget Form MprisChunk Media Players Bộ phát phường tiện NotificationAppGroup Uncategorised Chưa được phân loại NotificationsStatusCenterPane Notifications Thông báo QUIET MODE CHẾ ĐỘ IM LẶNG Is it Friday yet? Có phải thứ sáu chưa? You've caught up with your notifications! Bạn đã cập nhật thông báo của mình! ================================================ FILE: plugins/NotificationsPlugin/translations/zh_CN.ts ================================================ JobWidget Form MprisChunk Media Players NotificationAppGroup Uncategorised 未分类的 NotificationsStatusCenterPane Notifications 通知 Is it Friday yet? 今天是周五嘛? You've caught up with your notifications! 通知已阅! QUIET MODE 安静模式 ================================================ FILE: plugins/OverviewPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets DBus) find_package(libcontemporary) set(SOURCES OverviewPane/overviewpane.cpp OverviewPane/worldclock.cpp clockchunk.cpp plugin.cpp OverviewPane/overviewpane.ui OverviewPane/worldclock.ui clockchunk.ui ) set(HEADERS OverviewPane/overviewpane.h OverviewPane/worldclock.h clockchunk.h plugin.h ) set(PLUGIN_NAME overview) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets Qt::Multimedia libcontemporary libthedesk) ================================================ FILE: plugins/OverviewPlugin/OverviewPane/overviewpane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "overviewpane.h" #include "ui_overviewpane.h" #include "worldclock.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct OverviewPanePrivate { OverviewPanePrivate() : worldClockSettings("theSuite", "the24"){}; QToolButton* hamburgerButton; QList worldClocks; tSettings worldClockSettings; }; OverviewPane::OverviewPane() : StatusCenterPane(), ui(new Ui::OverviewPane) { ui->setupUi(this); d = new OverviewPanePrivate(); d->hamburgerButton = new QToolButton(this); d->hamburgerButton->setIcon(QIcon::fromTheme("application-menu")); d->hamburgerButton->move(0, 0); d->hamburgerButton->setFixedSize(d->hamburgerButton->sizeHint()); d->hamburgerButton->setVisible(StateManager::statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, d->hamburgerButton, &QToolButton::setVisible); connect(d->hamburgerButton, &QToolButton::clicked, StateManager::statusCenterManager(), &StatusCenterManager::showStatusCenterHamburgerMenu); ui->dstIcon->setPixmap(QIcon::fromTheme("chronometer").pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->weatherIcon->setPixmap(QIcon::fromTheme("weather-clear").pixmap(SC_DPI_T(QSize(16, 16), QSize))); ui->dstPanel->setVisible(false); ui->weatherPanel->setVisible(false); QTimer* timer = new QTimer(); timer->setInterval(60000); connect(timer, &QTimer::timeout, this, &OverviewPane::updateGreeting); timer->start(); updateGreeting(); DesktopTimeDate::makeTimeLabel(ui->date, DesktopTimeDate::StandardDate); DesktopTimeDate::makeTimeLabel(ui->time, DesktopTimeDate::Time); DesktopTimeDate::makeTimeLabel(ui->timeAmPm, DesktopTimeDate::AmPm); connect(DesktopTimeDate::timeUpdateTimer(), &QTimer::timeout, this, [=] { for (WorldClock* wc : d->worldClocks) { wc->updateClock(); } }); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->mainWidget->setFixedWidth(contentWidth); ui->scrollAreaWidgetContents->installEventFilter(this); connect(&d->worldClockSettings, &tSettings::settingChanged, this, [=](QString key, QVariant value) { if (key == "WorldClock/timezones") { updateWorldClocks(); } }); updateWorldClocks(); updateDSTNotification(); } OverviewPane::~OverviewPane() { delete d; delete ui; } void OverviewPane::updateGreeting() { QString userDisplayName = DesktopWm::userDisplayName(); QTime now = QTime::currentTime(); if (now.hour() < 6) { ui->greetingLabel->setText(tr("Hi %1!").arg(userDisplayName)); } else if (now.hour() < 12) { ui->greetingLabel->setText(tr("Good morning, %1!").arg(userDisplayName)); } else if (now.hour() < 17) { ui->greetingLabel->setText(tr("Good afternoon, %1!").arg(userDisplayName)); } else { ui->greetingLabel->setText(tr("Good evening, %1!").arg(userDisplayName)); } } void OverviewPane::updateWorldClocks() { for (WorldClock* wc : d->worldClocks) { ui->worldClocksLayout->removeWidget(wc); wc->deleteLater(); } d->worldClocks.clear(); for (QString tz : d->worldClockSettings.delimitedList("WorldClock/timezones").mid(0, 4)) { WorldClock* wc = new WorldClock(QTimeZone(tz.toUtf8())); ui->worldClocksLayout->addWidget(wc); d->worldClocks.append(wc); } } void OverviewPane::updateDSTNotification() { QDBusInterface dateTimeInterface("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", QDBusConnection::systemBus()); QString currentTimezone = dateTimeInterface.property("Timezone").toString(); QString timezoneInfoPath = "/usr/share/zoneinfo/" + currentTimezone; QProcess* timezoneProcess = new QProcess(); connect(timezoneProcess, QOverload::of(&QProcess::finished), [=](int exitCode, QProcess::ExitStatus exitStatus) { timezoneProcess->deleteLater(); struct Changeover { QDateTime changeoverDate; bool isDST; int gmtOffset; }; QList changeovers; while (!timezoneProcess->atEnd()) { QStringList parts = QString(timezoneProcess->readLine()).split(" ", Qt::SkipEmptyParts); if (parts.length() == 16) { QStringList dateText; const QStringList months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; dateText.append(parts.at(3)); dateText.append(QString::number(months.indexOf(parts.at(2)) + 1).rightJustified(2, '0')); dateText.append(parts.at(5)); dateText.append(parts.at(4)); Changeover c; QString dateConnectedText = dateText.join("."); QDate date = QDate(parts.at(5).toInt(), months.indexOf(parts.at(2)) + 1, parts.at(3).toInt()); QTime time = QTime::fromString(parts.at(4), "hh:mm:ss"); c.changeoverDate = QDateTime(date, time, Qt::LocalTime); c.changeoverDate.setTimeSpec(Qt::UTC); c.isDST = parts.at(14).endsWith("1"); c.gmtOffset = parts.at(15).mid(7).toInt(); changeovers.append(c); } } bool showDaylightSavingsPanel = false; Changeover changeover; QDateTime current = QDateTime::currentDateTimeUtc(); QDateTime currentLocal = QDateTime::currentDateTime(); for (int i = 0; i < changeovers.count(); i++) { Changeover c = changeovers.at(i); int days = current.daysTo(c.changeoverDate); if (days > 0 && days < 14) { if ((currentLocal.isDaylightTime() && !c.isDST) || (!currentLocal.isDaylightTime() && c.isDST)) { showDaylightSavingsPanel = true; changeover = c; } } } if (showDaylightSavingsPanel) { ui->dstPanel->setVisible(true); if (currentLocal.isDaylightTime()) { ui->dstLabel->setText(tr("Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s).", nullptr, 1).arg(QLocale().toString(changeover.changeoverDate.toLocalTime().date()))); } else { ui->dstLabel->setText(tr("Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s).", nullptr, 1).arg(QLocale().toString(changeover.changeoverDate.toLocalTime().date()))); } } else { ui->dstPanel->setVisible(false); } }); timezoneProcess->start("zdump", {"-v", currentTimezone}); } void OverviewPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } bool OverviewPane::eventFilter(QObject* watched, QEvent* event) { if (watched == ui->scrollAreaWidgetContents && event->type() == QEvent::Paint) { QPainter p(ui->scrollAreaWidgetContents); p.setRenderHint(QPainter::Antialiasing); QColor newTextColor; QColor top, bottom; QTime now = QTime::currentTime(); /*if (currentCondition.isValid && currentCondition.properties.value(WeatherCondition::isCloudy, false).toBool()) { top = QColor(150, 150, 150); bottom = QColor(100, 100, 100); newTextColor = QColor(Qt::black); } else*/ if (now.hour() < 4 || now.hour() > 20) { // Assume night top = QColor(0, 36, 85); bottom = QColor(0, 17, 40); newTextColor = QColor(Qt::white); } else if (now.hour() > 8 && now.hour() < 16) { // Assume day top = QColor(126, 195, 255); bottom = QColor(64, 149, 185); newTextColor = QColor(Qt::black); } else { // Calculate interpolation int interpolation; // From 4-8 interpolate sunrise if (now.hour() > 4 && now.hour() < 8) { interpolation = now.msecsSinceStartOfDay() - 14400000; // 4 hours in milliseconds } else { interpolation = 14400000 - (now.msecsSinceStartOfDay() - 57600000); // 16 hours in milliseconds } QVariantAnimation a; a.setDuration(14400000); a.setCurrentTime(interpolation); a.setStartValue(QColor(0, 36, 85)); a.setKeyValueAt(0.5, QColor(255, 140, 0)); a.setEndValue(QColor(126, 195, 255)); top = a.currentValue().value(); a.setStartValue(QColor(0, 17, 40)); a.setKeyValueAt(0.5, QColor(167, 70, 25)); a.setEndValue(QColor(64, 149, 185)); bottom = a.currentValue().value(); bool dark = ((top.red() + top.green() + top.blue()) / 3) < 127; if (dark) { newTextColor = QColor(Qt::white); } else { newTextColor = QColor(Qt::black); } } QLinearGradient mainBackground; mainBackground.setStart(0, 0); mainBackground.setFinalStop(0, 500); mainBackground.setColorAt(0, top); mainBackground.setColorAt(1, bottom); p.setBrush(mainBackground); p.setPen(Qt::transparent); p.drawRect(0, 0, ui->scrollAreaWidgetContents->width(), ui->scrollAreaWidgetContents->height()); // Draw background objects if neccessary // if (currentCondition.isValid) { // if (currentCondition.properties.value(WeatherCondition::isRainy, false).toBool()) drawRaindrops(&p); // if (currentCondition.properties.value(WeatherCondition::WindBeaufort, 0).toInt() >= 4) drawWind(&p); // } // drawObjects(&p); // Draw celestial object if neccessary int daySegmentPassed = -1; bool isMoon = true; if (now.hour() < 5 || (now.hour() == 5 && now.minute() <= 30)) { // Draw moon daySegmentPassed = now.msecsSinceStartOfDay() + 19800000; // 5.5 hours in milliseconds } else if (now.hour() > 18 || (now.hour() == 18 && now.minute() >= 30)) { // Draw moon daySegmentPassed = now.msecsSinceStartOfDay() - 66600000; // 18.5 hours in milliseconds } else if ((now.hour() > 6 && now.hour() < 17) || (now.hour() == 6 && now.minute() >= 30) || (now.hour() == 17 && now.minute() <= 30)) { // Draw sun daySegmentPassed = now.msecsSinceStartOfDay() - 23400000; // 6.5 hours in milliseconds isMoon = false; } if (isMoon) { p.setBrush(QColor(127, 127, 127)); } else { p.setBrush(QColor(255, 224, 130)); } if (daySegmentPassed >= 0) { double percentageThroughArc = daySegmentPassed / 39600000.0; // 11 hours in milliseconds double sinArg = percentageThroughArc * M_PI; double heightDisplacement = -sin(sinArg) + 1; int top = static_cast((heightDisplacement * 100) + 70); int left = static_cast((ui->scrollAreaWidgetContents->width() + 100) * percentageThroughArc - 50); QPoint center(left, top); if (isMoon) { p.drawEllipse(center, 30, 30); } else { p.drawEllipse(center, 50, 50); } } QPalette pal = ui->scrollAreaWidgetContents->palette(); pal.setColor(QPalette::WindowText, newTextColor); ui->scrollAreaWidgetContents->setPalette(pal); } return false; } QString OverviewPane::name() { return "OverviewPane"; } QString OverviewPane::displayName() { return tr("Overview"); } QIcon OverviewPane::icon() { return QIcon::fromTheme("thedesk-overview", QIcon::fromTheme("weather-clear")); } QWidget* OverviewPane::leftPane() { return nullptr; } ================================================ FILE: plugins/OverviewPlugin/OverviewPane/overviewpane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef OVERVIEWPANE_H #define OVERVIEWPANE_H #include namespace Ui { class OverviewPane; } struct OverviewPanePrivate; class OverviewPane : public StatusCenterPane { Q_OBJECT public: explicit OverviewPane(); ~OverviewPane(); private: Ui::OverviewPane* ui; OverviewPanePrivate* d; void updateGreeting(); void updateWorldClocks(); void updateDSTNotification(); void changeEvent(QEvent* event); bool eventFilter(QObject* watched, QEvent* event); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); }; #endif // OVERVIEWPANE_H ================================================ FILE: plugins/OverviewPlugin/OverviewPane/overviewpane.ui ================================================ OverviewPane 0 0 669 448 Form 0 0 0 0 0 QFrame::NoFrame true 0 -188 655 636 0 0 Qt::Horizontal QSizePolicy::Preferred 0 20 50 50 50 50 20 Hi user! Hope you're having a great day. Here's what we've got for you: true Qt::Vertical QSizePolicy::Fixed 20 40 0 0 0 0 0 0 0 0 0 40 16:20:00 0 0 40 a 15 Sunday, 1 Janurary 1111 0 20 0 0 QFrame::NoFrame QFrame::Raised 0 0 9 0 Icon Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 On Tableday, 1 April 2018, Daylight Savings Time will end. The clock will automatically adjust backwards by 1 hour. true 0 0 0 0 Icon Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 Weather Information true 0 0 0 0 Qt::Vertical QSizePolicy::Fixed 20 40 Qt::Horizontal 40 20 QFrame::StyledPanel QFrame::Raised 0 0 0 0 false Qt::Horizontal 40 20 Qt::Vertical 20 0 Qt::Horizontal QSizePolicy::Preferred 0 20 ================================================ FILE: plugins/OverviewPlugin/OverviewPane/worldclock.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "worldclock.h" #include "ui_worldclock.h" #include #include #include #include #include struct WorldClockPrivate { QTimeZone tz; bool mouseDown = false; }; WorldClock::WorldClock(QTimeZone tz, QWidget* parent) : QWidget(parent), ui(new Ui::WorldClock) { ui->setupUi(this); d = new WorldClockPrivate(); d->tz = tz; QString city = QString(tz.id()).replace("_", " "); if (city.contains("/")) city = city.split("/").at(1); city = city.toUpper(); ui->tzLabel->setText(city); this->setMouseTracking(true); updateClock(); } WorldClock::~WorldClock() { delete d; delete ui; } void WorldClock::updateClock() { QString text; QDateTime date = QDateTime::currentDateTimeUtc(); date = date.addSecs(d->tz.offsetFromUtc(date)); text = DesktopTimeDate::timeString(date, DesktopTimeDate::Time); int dayDifference = QDateTime::currentDateTime().daysTo(date); if (dayDifference < 0) { text.append(QStringLiteral("-%1").arg(dayDifference * -1)); } else if (dayDifference > 0) { text.append(QStringLiteral("+%1").arg(dayDifference)); } ui->clockLabel->setText(text); } void WorldClock::mousePressEvent(QMouseEvent* event) { d->mouseDown = true; this->update(); } void WorldClock::mouseReleaseEvent(QMouseEvent* event) { d->mouseDown = false; if (this->underMouse()) { StateManager::statusCenterManager()->hide(); QProcess::startDetached("the24", {}); } this->update(); } void WorldClock::enterEvent(QEvent* event) { this->update(); } void WorldClock::leaveEvent(QEvent* event) { this->update(); } void WorldClock::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.setPen(Qt::transparent); painter.setBrush(Qt::transparent); if (d->mouseDown) { painter.setBrush(QColor(0, 0, 0, 100)); } else if (this->underMouse()) { painter.setBrush(QColor(255, 255, 255, 100)); } painter.drawRect(0, 0, this->width(), this->height()); } ================================================ FILE: plugins/OverviewPlugin/OverviewPane/worldclock.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef WORLDCLOCK_H #define WORLDCLOCK_H #include #include namespace Ui { class WorldClock; } struct WorldClockPrivate; class WorldClock : public QWidget { Q_OBJECT public: explicit WorldClock(QTimeZone tz, QWidget* parent = nullptr); ~WorldClock(); void updateClock(); private: Ui::WorldClock* ui; WorldClockPrivate* d; // QWidget interface protected: void mousePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); void enterEvent(QEvent* event); void leaveEvent(QEvent* event); void paintEvent(QPaintEvent* event); }; #endif // WORLDCLOCK_H ================================================ FILE: plugins/OverviewPlugin/OverviewPane/worldclock.ui ================================================ WorldClock 0 0 186 58 Form 3 0 0 75 true TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ================================================ FILE: plugins/OverviewPlugin/OverviewPlugin.pro ================================================ QT += widgets TEMPLATE = lib CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ OverviewPane/overviewpane.cpp \ OverviewPane/worldclock.cpp \ clockchunk.cpp \ plugin.cpp HEADERS += \ OverviewPane/overviewpane.h \ OverviewPane/worldclock.h \ clockchunk.h \ plugin.h unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/OverviewPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/OverviewPlugin/ INSTALLS += translations defaults INSTALLS += translations } include(../plugins.pri) DISTFILES += \ Plugin.json \ defaults.conf FORMS += \ OverviewPane/overviewpane.ui \ OverviewPane/worldclock.ui \ clockchunk.ui ================================================ FILE: plugins/OverviewPlugin/Plugin.json ================================================ { "name": "theDesk Overview", "icon": "preferences-desktop-overview", "uuid": "2ad5c596-3633-45fd-9f3a-89ae88bdd60c", "vi": { "name": "Tổng Quan theDesk" } } ================================================ FILE: plugins/OverviewPlugin/clockchunk.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "clockchunk.h" #include "ui_clockchunk.h" #include #include #include #include ClockChunk::ClockChunk() : Chunk(), ui(new Ui::ClockChunk) { ui->setupUi(this); DesktopTimeDate::makeTimeLabel(ui->time, DesktopTimeDate::Time); DesktopTimeDate::makeTimeLabel(ui->ampmLabel, DesktopTimeDate::AmPm); DesktopTimeDate::makeTimeLabel(ui->date, DesktopTimeDate::StandardDate); connect(StateManager::barManager(), &BarManager::barHeightTransitioning, this, [ = ](qreal percentage) { qreal pointSize = (15 - this->font().pointSizeF()) * percentage + this->font().pointSizeF(); QFont font = this->font(); font.setBold(true); font.setPointSizeF(pointSize); ui->time->setFont(font); ui->ampmLabel->setFont(font); int padding = 3 + 6 * percentage; this->layout()->setContentsMargins(0, padding, 0, padding); if (qFuzzyCompare(percentage, 1)) { ui->date->setFixedWidth(QWIDGETSIZE_MAX); } else { ui->date->setFixedWidth(ui->date->sizeHint().width() * percentage); } }); connect(this, &ClockChunk::clicked, this, [ = ] { StateManager::instance()->statusCenterManager()->show(); }); } ClockChunk::~ClockChunk() { delete ui; } QString ClockChunk::name() { return "OverviewClock"; } int ClockChunk::expandedHeight() { QFontMetrics metrics(QFont(this->font().family(), 15)); return metrics.height() + 18; } int ClockChunk::statusBarHeight() { return this->fontMetrics().height() + 6; } ================================================ FILE: plugins/OverviewPlugin/clockchunk.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CLOCKCHUNK_H #define CLOCKCHUNK_H #include namespace Ui { class ClockChunk; } class ClockChunk : public Chunk { Q_OBJECT public: explicit ClockChunk(); ~ClockChunk(); private: Ui::ClockChunk* ui; // Chunk interface public: QString name(); int expandedHeight(); int statusBarHeight(); }; #endif // CLOCKCHUNK_H ================================================ FILE: plugins/OverviewPlugin/clockchunk.ui ================================================ ClockChunk 0 0 261 44 Form 0 0 0 0 0 15 75 true &16:20:00 0 0 15 75 true a 0 0 10 Sunday 1st &Jan 1111 ================================================ FILE: plugins/OverviewPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "OverviewPane/overviewpane.h" #include #include #include #include #include #include #include #include #include #include #include #include struct PluginPrivate { ClockChunk* chunk; OverviewPane* overviewPane; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults("theSuite", "the24", "/usr/share/defaults/the24.conf"); d->chunk = new ClockChunk(); StateManager::barManager()->addChunk(d->chunk); d->overviewPane = new OverviewPane(); StateManager::statusCenterManager()->addPane(d->overviewPane); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->overviewPane); StateManager::barManager()->removeChunk(d->chunk); d->overviewPane->deleteLater(); d->chunk->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/OverviewPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/OverviewPlugin/translations/ar_SA.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/au_AU.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/cy.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/da.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/de.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/en_GB.ts ================================================ OverviewPane Hi %1! Hi %1! Good morning, %1! Good morning, %1! Good afternoon, %1! Good afternoon, %1! Good evening, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview Overview Hope you're having a great day. Here's what we've got for you: Hope you're having a great day. Here's what we've got for you: ================================================ FILE: plugins/OverviewPlugin/translations/en_US.qm ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/es.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/es_VE.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/id.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/nl.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hopelijk heb je een geweldige dag. Dit hebben we voor je: Hi %1! Hoi %1! Good morning, %1! Goedemorgen, %1! Good afternoon, %1! Goedemiddag, %1! Good evening, %1! Goedenavond, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview Overzicht ================================================ FILE: plugins/OverviewPlugin/translations/pt_BR.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/ro_RO.ts ================================================ OverviewPane Hi %1! Salut %1! Good morning, %1! Bună dimineața, %1! Good afternoon, %1! Bună ziua, %1! Good evening, %1! Bună seara, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Daylight Savings Time is ending on %2. The clock will automatically shift backwards by %n hour(s). Ora de vară se va încheia pe data de %2. Ceasul va fi dat cu o oră în urmă. Ora de vară se va încheia pe data de %2. Ceasul va fi dat cu %n ore în urmă. Ora de vară se va încheia pe data de %2. Ceasul va fi dat cu %n ore în urmă. Daylight Savings Time is starting on %2. The clock will automatically shift forwards by %n hour(s). Ora de vară va începe pe data de %2. Ceasul va fi dat cu o oră în față. Ora de vară va începe pe data de %2. Ceasul va fi dat cu %n ore în față. Ora de vară va începe pe data de %2. Ceasul va fi dat cu %n ore în față. Overview Privire de ansamblu Hope you're having a great day. Here's what we've got for you: Sperăm că vă simțiți minunat. Uitați ce avem pentru dumneavoastră: ================================================ FILE: plugins/OverviewPlugin/translations/sk_SK.ts ================================================ OverviewPane Hi %1! Ahoj% 1! Good morning, %1! Dobré ráno,% 1! Good afternoon, %1! Dobré popoludnie,% 1! Good evening, %1! Dobrý večer,% 1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview Prehľad Hope you're having a great day. Here's what we've got for you: Dúfam, že máš skvelý deň. Tu je to, čo pre vás máme: ================================================ FILE: plugins/OverviewPlugin/translations/sv.ts ================================================ OverviewPane Hope you're having a great day. Here's what we've got for you: Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview ================================================ FILE: plugins/OverviewPlugin/translations/tr_TR.ts ================================================ OverviewPane Hi %1! Merhaba %1! Good morning, %1! Günaydın %1! Good afternoon, %1! İyi günler %1! Good evening, %1! İyi akşamlar %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview Genel Bakış Hope you're having a great day. Here's what we've got for you: Umarım harika bir gün geçiriyorsundur. İşte sizin için hazırladıklarımız: ================================================ FILE: plugins/OverviewPlugin/translations/vi_VN.ts ================================================ OverviewPane Hi %1! Chào %1! Good morning, %1! Chào buổi sáng, %1! Good afternoon, %1! Chào buổi chiều, %1! Good evening, %1! Chào buổi tối, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Giờ mùa hè sẽ kết thúc ngày %1. Đồng hồ sẽ tự động quay ngược %n giờ. Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Giờ mùa hè sẽ bắt đầu ngày %1. Đồng hồ sẽ tự động tua đi %n giờ. Daylight Savings Time is ending on %2. The clock will automatically shift backwards by %n hour(s). Giờ mùa hè sẽ kết thúc ngày %2. Đồng hồ sẽ tự động quay ngược %n giờ. Daylight Savings Time is starting on %2. The clock will automatically shift forwards by %n hour(s). Giờ mùa hè sẽ bắt đầu ngày %2. Đồng hồ sẽ tự động tua đi %n giờ. Overview Tổng quan Hope you're having a great day. Here's what we've got for you: Chúng tôi hy vọng ngày nay tuyệt vời. Chúng tôi có điều này cho bạn: ================================================ FILE: plugins/OverviewPlugin/translations/zh_CN.ts ================================================ OverviewPane Hi %1! 你好 %1! Good morning, %1! 早上好, %1! Good afternoon, %1! 下午好, %1! Good evening, %1! 晚上好, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview 总览 Hope you're having a great day. Here's what we've got for you: 希望你有个很棒的一天。 这里是我为你收集的东西: ================================================ FILE: plugins/OverviewPlugin/translations/zu_ZA.qm ================================================ OverviewPane Hi %1! Good morning, %1! Good afternoon, %1! Good evening, %1! Daylight Savings Time is ending on %1. The clock will automatically shift backwards by %n hour(s). Daylight Savings Time is starting on %1. The clock will automatically shift forwards by %n hour(s). Overview Hope you're having a great day. Here's what we've got for you: ================================================ FILE: plugins/PowerPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) set(SOURCES eventhandler.cpp plugin.cpp settings/powersettings.cpp sleepmonitor.cpp settings/powersettings.ui ) set(HEADERS eventhandler.h plugin.h settings/powersettings.h sleepmonitor.h ) set(PLUGIN_NAME power) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-power.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets libcontemporary libthedesk) ================================================ FILE: plugins/PowerPlugin/Plugin.json ================================================ { "name": "Power Management", "icon": "preferences-system-power", "uuid": "859a8d5e-21c3-4de6-9a77-8ff4131bdfe6", "vi": { "name": "Quản lý nguồn điện" } } ================================================ FILE: plugins/PowerPlugin/PowerPlugin.pro ================================================ QT += widgets TEMPLATE = lib DEFINES += POWERPLUGIN_LIBRARY # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) CONFIG += c++11 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/PowerPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/PowerPlugin/ INSTALLS += translations defaults } include(../plugins.pri) HEADERS += \ eventhandler.h \ plugin.h \ settings/powersettings.h \ sleepmonitor.h SOURCES += \ eventhandler.cpp \ plugin.cpp \ settings/powersettings.cpp \ sleepmonitor.cpp DISTFILES += \ Plugin.json \ defaults.conf FORMS += \ settings/powersettings.ui ================================================ FILE: plugins/PowerPlugin/eventhandler.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "eventhandler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct EventHandlerPrivate { KeyGrab* powerKey; KeyGrab* ctrlAltDelKey; QDBusUnixFileDescriptor buttonInhibitor; QuickSwitch* caffeinateSwitch; IconTextChunk* caffeinateChunk; DesktopUPower* upower; tSettings settings; quint64 oldIdleTimer = 0; bool screenOffActionPerformed = false; bool suspendActionPerformed = false; tVariantAnimation* suspendNotificationAnimation = new tVariantAnimation(); const static QMap timeoutFactors; const static QMap powerOffActions; }; const QMap EventHandlerPrivate::timeoutFactors = { {"sec", 1000 }, {"min", 60000 }, {"hr", 360000}, {"never", 0 } }; const QMap EventHandlerPrivate::powerOffActions = { {"ask", PowerManager::All }, {"poweroff", PowerManager::PowerOff }, {"reboot", PowerManager::Reboot }, {"suspend", PowerManager::Suspend }, {"hibernate", PowerManager::Hibernate}, {"ignore", -1 } }; EventHandler::EventHandler(QObject* parent) : QObject(parent) { d = new EventHandlerPrivate(); d->upower = new DesktopUPower(); QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Inhibit"); message.setArguments(QList() << "handle-power-key:idle" << "theDesk" << "theDesk handles hardware power keys and idling" << "block"); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(QDBusConnection::systemBus().asyncCall(message)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { qWarning() << tr("Unable to inhibit logind power management"); } else { d->buttonInhibitor = watcher->reply().arguments().first().value(); } }); d->powerKey = new KeyGrab(QKeySequence(Qt::Key_PowerOff)); connect(d->powerKey, &KeyGrab::activated, this, [=] { int action = d->powerOffActions.value(d->settings.value("Power/actions.powerbutton").toString(), -1); if (action == -1) return; // Ignore if (action == PowerManager::All) { // Ask StateManager::powerManager()->showPowerOffConfirmation(); } else { StateManager::powerManager()->performPowerOperation(static_cast(action)); } }); d->ctrlAltDelKey = new KeyGrab(QKeySequence(Qt::ControlModifier | Qt::AltModifier | Qt::Key_Delete)); connect(d->ctrlAltDelKey, &KeyGrab::activated, this, [=] { StateManager::powerManager()->showPowerOffConfirmation(); }); d->caffeinateChunk = new IconTextChunk("caffeinate"); d->caffeinateChunk->setIcon(QIcon::fromTheme("caffeinate")); d->caffeinateChunk->setText(tr("Caffeinated")); d->caffeinateSwitch = new QuickSwitch("PowerCaffeinate"); d->caffeinateSwitch->setTitle(tr("Caffeinate")); connect(d->caffeinateSwitch, &QuickSwitch::toggled, this, [this](bool checked) { if (checked && !d->caffeinateChunk->chunkRegistered()) { StateManager::barManager()->addChunk(d->caffeinateChunk); } else if (!checked && d->caffeinateChunk->chunkRegistered()) { StateManager::barManager()->removeChunk(d->caffeinateChunk); } }); StateManager::statusCenterManager()->addSwitch(d->caffeinateSwitch); ActionQuickWidget* caffeinateChunkQuickWidget = new ActionQuickWidget(d->caffeinateChunk); caffeinateChunkQuickWidget->addAction(QIcon::fromTheme("caffeinate"), tr("Decaffeinate"), [this] { d->caffeinateSwitch->setChecked(false); }); d->caffeinateChunk->setQuickWidget(caffeinateChunkQuickWidget); QTimer* timer = new QTimer(this); timer->setInterval(1000); connect(timer, &QTimer::timeout, this, &EventHandler::checkIdleTimer); timer->start(); d->suspendNotificationAnimation = new tVariantAnimation(this); d->suspendNotificationAnimation->setStartValue(1.0); d->suspendNotificationAnimation->setEndValue(0.0); d->suspendNotificationAnimation->setForceAnimation(true); d->suspendNotificationAnimation->setDuration(15000); connect(d->suspendNotificationAnimation, &tVariantAnimation::valueChanged, this, [=](QVariant value) { StateManager::instance()->hudManager()->showHud({ {"icon", "system-suspend"}, {"title", tr("Suspend") }, {"text", tr("%n seconds", nullptr, (15000 - d->suspendNotificationAnimation->currentTime()) / 1000 + 1)}, {"value", value.toDouble() }, {"timeout", 15000 } }); // Immediately do an idle timer check if the idle timer has changed if (DesktopWm::msecsIdle() < d->oldIdleTimer) checkIdleTimer(); }); connect(d->suspendNotificationAnimation, &tVariantAnimation::stateChanged, this, [=](tVariantAnimation::State newState, tVariantAnimation::State oldState) { if (newState == tVariantAnimation::Stopped) { StateManager::instance()->hudManager()->hideHud(); } }); connect(d->suspendNotificationAnimation, &tVariantAnimation::finished, this, [=] { // Suspend now StateManager::powerManager()->performPowerOperation(PowerManager::Suspend); }); connect(d->upower, QOverload::of(&DesktopUPower::deviceAdded), this, &EventHandler::trackDevice); connect(d->upower, QOverload::of(&DesktopUPower::deviceRemoved), this, &EventHandler::removeDevice); for (DesktopUPowerDevice* device : d->upower->devices()) { trackDevice(device); } } EventHandler::~EventHandler() { d->upower->deleteLater(); d->powerKey->deleteLater(); d->ctrlAltDelKey->deleteLater(); delete d; } void EventHandler::checkIdleTimer() { quint64 idleTimer = DesktopWm::msecsIdle(); if (idleTimer < d->oldIdleTimer) { if (d->suspendNotificationAnimation->state() == tVariantAnimation::Running) { d->suspendNotificationAnimation->stop(); } // Reset all variables d->screenOffActionPerformed = false; d->suspendActionPerformed = false; } d->oldIdleTimer = idleTimer; // Ensure that there are no full screen windows so we don't switch off the screen if someone is watching a video for instance for (DesktopWmWindowPtr window : DesktopWm::openWindows()) { if (window->isFullScreen()) return; } // Ensure caffeinate is not switched on if (!d->caffeinateSwitch->isChecked()) { if (!d->screenOffActionPerformed) { // See if we need to turn the screen off quint64 timeout = d->settings.value("Power/timeouts.screenoff.value").toInt() * d->timeoutFactors.value(d->settings.value("Power/timeouts.screenoff.unit").toString(), 0); if (idleTimer > timeout && timeout != 0) { // Turn the screen off now StateManager::powerManager()->performPowerOperation(PowerManager::TurnOffScreen); d->screenOffActionPerformed = true; } } if (!d->suspendActionPerformed) { // See if we need to suspend quint64 timeout = d->settings.value("Power/timeouts.suspend.value").toInt() * d->timeoutFactors.value(d->settings.value("Power/timeouts.suspend.unit").toString(), 0); if (idleTimer > timeout && timeout != 0) { // Notify the user about the impending suspension and then suspend d->suspendActionPerformed = true; d->suspendNotificationAnimation->start(); } } } } void EventHandler::trackDevice(DesktopUPowerDevice* device) { connect(device, &DesktopUPowerDevice::lowBatteryNotification, this, [=](QString description) { StateManager::instance()->hudManager()->showHud({ {"icon", device->iconName() }, {"title", tr("Battery") }, {"text", description }, {"value", device->percentage() / 100.0}, {"timeout", 10000 }, {"color", QColor(Qt::red) } }); }); connect(device, &DesktopUPowerDevice::chargingNotification, this, [=] { StateManager::instance()->hudManager()->showHud({ {"icon", device->iconName() }, {"title", tr("Battery") }, {"text", tr("Charging") }, {"value", device->percentage() / 100.0}, {"timeout", 10000 }, {"color", QColor(Qt::green) } }); }); connect(device, &DesktopUPowerDevice::fullNotification, this, [=] { StateManager::instance()->hudManager()->showHud({ {"icon", device->iconName() }, {"title", tr("Battery") }, {"text", tr("Full") }, {"value", device->percentage() / 100.0}, {"timeout", 10000 }, {"color", QColor(Qt::green) } }); }); connect(device, &DesktopUPowerDevice::dischargingNotification, this, [=] { StateManager::instance()->hudManager()->showHud({ {"icon", device->iconName() }, {"title", tr("Battery") }, {"text", tr("Discharging") }, {"value", device->percentage() / 100.0}, {"timeout", 10000 } }); }); } void EventHandler::removeDevice(DesktopUPowerDevice* device) { } ================================================ FILE: plugins/PowerPlugin/eventhandler.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef EVENTHANDLER_H #define EVENTHANDLER_H #include class DesktopUPowerDevice; struct EventHandlerPrivate; class EventHandler : public QObject { Q_OBJECT public: explicit EventHandler(QObject* parent = nullptr); ~EventHandler(); signals: private: EventHandlerPrivate* d; void checkIdleTimer(); void trackDevice(DesktopUPowerDevice* device); void removeDevice(DesktopUPowerDevice* device); }; #endif // KEYBOARDHANDLER_H ================================================ FILE: plugins/PowerPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "eventhandler.h" #include "settings/powersettings.h" #include "sleepmonitor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct PluginPrivate { DesktopPowerProfiles* powerProfiles; DesktopUPower* upower; IconTextChunk* powerChunk; EventHandler* logind; PowerSettings* powerSettings; QuickSwitch* powerStretchSwitch; IconTextChunk* powerStretchChunk; SleepMonitor* sleepMonitor; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/PowerPlugin/thedesk-power.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-power.conf"); d->powerProfiles = new DesktopPowerProfiles(); d->upower = new DesktopUPower(this); d->powerChunk = new IconTextChunk("Power"); connect(d->upower, &DesktopUPower::overallStateChanged, this, [=] { d->powerChunk->setIcon(d->upower->overallStateIcon()); d->powerChunk->setText(d->upower->overallStateDescription()); if (d->upower->shouldShowOverallState() && !d->powerChunk->chunkRegistered()) { // Register the chunk StateManager::barManager()->addChunk(d->powerChunk); } else if (!d->upower->shouldShowOverallState() && d->powerChunk->chunkRegistered()) { // Deregister the chunk StateManager::barManager()->removeChunk(d->powerChunk); } }); d->logind = new EventHandler(); d->powerSettings = new PowerSettings(d->powerProfiles); StateManager::statusCenterManager()->addPane(d->powerSettings, StatusCenterManager::SystemSettings); d->powerStretchSwitch = new QuickSwitch("PowerStretch"); d->powerStretchSwitch->setTitle(tr("Power Stretch")); d->powerStretchSwitch->setChecked(d->powerProfiles->currentPowerProfile() == DesktopPowerProfiles::PowerStretch); connect(d->powerStretchSwitch, &QuickSwitch::toggled, this, [=](bool powerStretch) { if (powerStretch) { d->powerProfiles->setCurrentPowerProfile(DesktopPowerProfiles::PowerStretch); } else { d->powerProfiles->setCurrentPowerProfile(DesktopPowerProfiles::Balanced); } }); d->powerStretchChunk = new IconTextChunk("PowerStretch"); d->powerStretchChunk->setIcon(QIcon::fromTheme("battery-stretch")); d->powerStretchChunk->setText(tr("Power Stretch")); if (d->powerProfiles->currentPowerProfile() == DesktopPowerProfiles::PowerStretch) StateManager::barManager()->addChunk(d->powerStretchChunk); ActionQuickWidget* quickWidget = new ActionQuickWidget(d->powerStretchChunk); quickWidget->addAction(QIcon::fromTheme("battery-stretch"), tr("Disable Power Stretch"), [=] { d->powerProfiles->setCurrentPowerProfile(DesktopPowerProfiles::Balanced); }); d->powerStretchChunk->setQuickWidget(quickWidget); connect(d->powerProfiles, &DesktopPowerProfiles::powerProfileChanged, this, [=] { d->powerStretchSwitch->setChecked(d->powerProfiles->currentPowerProfile() == DesktopPowerProfiles::PowerStretch); if (d->powerProfiles->currentPowerProfile() == DesktopPowerProfiles::PowerStretch && !d->powerStretchChunk->chunkRegistered()) { // Register the chunk StateManager::barManager()->addChunk(d->powerStretchChunk); } else if (d->powerProfiles->currentPowerProfile() != DesktopPowerProfiles::PowerStretch && d->powerStretchChunk->chunkRegistered()) { // Deregister the chunk StateManager::barManager()->removeChunk(d->powerStretchChunk); } }); StateManager::statusCenterManager()->addSwitch(d->powerStretchSwitch); d->sleepMonitor = new SleepMonitor(); } void Plugin::deactivate() { if (d->powerChunk->chunkRegistered()) { // Deregister the chunk StateManager::barManager()->removeChunk(d->powerChunk); } if (d->powerStretchChunk->chunkRegistered()) { // Deregister the chunk StateManager::barManager()->removeChunk(d->powerStretchChunk); } StateManager::statusCenterManager()->removeSwitch(d->powerStretchSwitch); StateManager::statusCenterManager()->removePane(d->powerSettings); d->powerStretchSwitch->deleteLater(); d->powerChunk->deleteLater(); d->powerStretchChunk->deleteLater(); d->upower->deleteLater(); d->logind->deleteLater(); d->powerSettings->deleteLater(); d->powerProfiles->deleteLater(); d->sleepMonitor->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/PowerPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/PowerPlugin/settings/powersettings.cpp ================================================ #include "powersettings.h" #include "ui_powersettings.h" #include #include #include #include #include struct PowerSettingsPrivate { tSettings settings; DesktopPowerProfiles* profiles; const static QStringList timeoutUnits; const static QStringList powerActions; }; const QStringList PowerSettingsPrivate::timeoutUnits = { "sec", "min", "hr", "never"}; const QStringList PowerSettingsPrivate::powerActions = { "ask", "poweroff", "reboot", "suspend", "hibernate", "ignore"}; PowerSettings::PowerSettings(DesktopPowerProfiles* powerProfiles) : StatusCenterPane(), ui(new Ui::PowerSettings) { ui->setupUi(this); d = new PowerSettingsPrivate(); d->profiles = powerProfiles; ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->powerProfileWidget->setFixedWidth(contentWidth); ui->timeoutsWidget->setFixedWidth(contentWidth); ui->buttonsWidget->setFixedWidth(contentWidth); connect(&d->settings, &tSettings::settingChanged, this, &PowerSettings::settingChanged); for (QString setting : { "Power/timeouts.screenoff.value", "Power/timeouts.screenoff.unit", "Power/timeouts.suspend.value", "Power/timeouts.suspend.unit", "Power/actions.powerbutton", "Power/suspend.lockScreen"}) { settingChanged(setting, d->settings.value(setting)); } connect(d->profiles, &DesktopPowerProfiles::powerProfileChanged, this, &PowerSettings::updatePowerProfiles); updatePowerProfiles(); } PowerSettings::~PowerSettings() { delete d; delete ui; } QString PowerSettings::name() { return "PowerSettings"; } QString PowerSettings::displayName() { return tr("Power"); } QIcon PowerSettings::icon() { return QIcon::fromTheme("preferences-system-power"); } QWidget* PowerSettings::leftPane() { return nullptr; } void PowerSettings::on_titleLabel_backButtonClicked() { StateManager::instance()->statusCenterManager()->showStatusCenterHamburgerMenu(); } void PowerSettings::on_screenOffSpin_valueChanged(int arg1) { d->settings.setValue("Power/timeouts.screenoff.value", arg1); } void PowerSettings::on_screenOffUnit_currentIndexChanged(int index) { d->settings.setValue("Power/timeouts.screenoff.unit", d->timeoutUnits.value(index)); } void PowerSettings::settingChanged(QString key, QVariant value) { if (key == "Power/timeouts.screenoff.value") { ui->screenOffSpin->setValue(value.toInt()); } else if (key == "Power/timeouts.screenoff.unit") { QString unit = value.toString(); ui->screenOffUnit->setCurrentIndex(d->timeoutUnits.indexOf(unit)); ui->screenOffSpin->setEnabled(unit != "never"); } else if (key == "Power/timeouts.suspend.value") { ui->suspendSpin->setValue(value.toInt()); } else if (key == "Power/timeouts.suspend.unit") { QString unit = value.toString(); ui->suspendUnit->setCurrentIndex(d->timeoutUnits.indexOf(unit)); ui->suspendSpin->setEnabled(unit != "never"); } else if (key == "Power/actions.powerbutton") { ui->powerButtonActionBox->setCurrentIndex(d->powerActions.indexOf(value.toString())); } else if (key == "Power/suspend.lockScreen") { ui->lockScreenAfterSuspendSwitch->setChecked(value.toBool()); } } void PowerSettings::updatePowerProfiles() { bool powerProfilesAvailable = d->profiles->powerProfilesAvailable(); ui->powerProfileWidget->setVisible(powerProfilesAvailable); ui->powerProfileLine->setVisible(powerProfilesAvailable); bool isPerformanceAvailable = d->profiles->isPerformanceAvailable(); ui->performanceProfileButton->setVisible(isPerformanceAvailable); ui->performanceDescription->setVisible(isPerformanceAvailable); switch (d->profiles->currentPowerProfile()) { case DesktopPowerProfiles::PowerStretch: ui->powerStretchProfileButton->setChecked(true); break; case DesktopPowerProfiles::Balanced: ui->balancedProfileButton->setChecked(true); break; case DesktopPowerProfiles::Performance: ui->performanceProfileButton->setChecked(true); break; case DesktopPowerProfiles::Unknown: break; } if (!d->profiles->performanceInhibited().isEmpty()) { ui->performanceInhibition->setTitle(tr("Performance mode unavailable")); ui->performanceInhibition->setText(performanceInhibitionReason(d->profiles->performanceInhibited()).arg(tr("unavailable"))); ui->performanceInhibition->setState(tStatusFrame::Error); ui->performanceProfileButton->setEnabled(false); ui->performanceInhibition->setVisible(true); } else if (!d->profiles->performanceDegraded().isEmpty()) { ui->performanceInhibition->setTitle(tr("Performance mode temporarily unavailable")); ui->performanceInhibition->setText(performanceInhibitionReason(d->profiles->performanceDegraded()).arg(tr("temporarily unavailable"))); ui->performanceInhibition->setState(tStatusFrame::Warning); ui->performanceProfileButton->setEnabled(true); ui->performanceInhibition->setVisible(true); } else { ui->performanceInhibition->setVisible(false); ui->performanceProfileButton->setEnabled(true); } } QString PowerSettings::performanceInhibitionReason(QString reason) { if (reason == "lap-detected") return tr("Performance mode is %1 because the device is on your lap."); if (reason == "high-operating-temperature") return tr("Performance mode is %1 because your device is getting warm."); return tr("Performance mode is %1."); } void PowerSettings::on_suspendSpin_valueChanged(int arg1) { d->settings.setValue("Power/timeouts.suspend.value", arg1); } void PowerSettings::on_suspendUnit_currentIndexChanged(int index) { d->settings.setValue("Power/timeouts.suspend.unit", d->timeoutUnits.value(index)); } void PowerSettings::on_powerButtonActionBox_currentIndexChanged(int index) { d->settings.setValue("Power/actions.powerbutton", d->powerActions.value(index)); } void PowerSettings::on_balancedProfileButton_toggled(bool checked) { if (checked) d->profiles->setCurrentPowerProfile(DesktopPowerProfiles::Balanced); } void PowerSettings::on_powerStretchProfileButton_toggled(bool checked) { if (checked) d->profiles->setCurrentPowerProfile(DesktopPowerProfiles::PowerStretch); } void PowerSettings::on_performanceProfileButton_toggled(bool checked) { if (checked) d->profiles->setCurrentPowerProfile(DesktopPowerProfiles::Performance); } void PowerSettings::on_lockScreenAfterSuspendSwitch_toggled(bool checked) { d->settings.setValue("Power/suspend.lockScreen", checked); } void PowerSettings::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/PowerPlugin/settings/powersettings.h ================================================ #ifndef POWERSETTINGS_H #define POWERSETTINGS_H #include #include namespace Ui { class PowerSettings; } class DesktopPowerProfiles; struct PowerSettingsPrivate; class PowerSettings : public StatusCenterPane { Q_OBJECT public: explicit PowerSettings(DesktopPowerProfiles* powerProfiles); ~PowerSettings(); private slots: void on_titleLabel_backButtonClicked(); void on_screenOffSpin_valueChanged(int arg1); void on_screenOffUnit_currentIndexChanged(int index); void on_suspendSpin_valueChanged(int arg1); void on_suspendUnit_currentIndexChanged(int index); void on_powerButtonActionBox_currentIndexChanged(int index); void on_balancedProfileButton_toggled(bool checked); void on_powerStretchProfileButton_toggled(bool checked); void on_performanceProfileButton_toggled(bool checked); void on_lockScreenAfterSuspendSwitch_toggled(bool checked); private: Ui::PowerSettings* ui; PowerSettingsPrivate* d; void settingChanged(QString key, QVariant value); void updatePowerProfiles(); QString performanceInhibitionReason(QString reason); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); // QWidget interface protected: void changeEvent(QEvent* event); }; #endif // POWERSETTINGS_H ================================================ FILE: plugins/PowerPlugin/settings/powersettings.ui ================================================ PowerSettings 0 0 725 556 Form 0 0 0 0 0 Power QFrame::NoFrame true 0 0 725 539 0 0 0 0 0 true POWER PROFILE A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. true Power Stretch powerProfilesGroup false Reduce the performance of your device to save on power true Balanced powerProfilesGroup false Performance and power consumption will be average true Performance powerProfilesGroup false Performance will be increased at the cost of power consumption true 16777215 1 Qt::Horizontal true TIMEOUTS 0 0 Switch off the screen after 1 200 If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. true seconds minutes hours never Suspend after 1 200 seconds minutes hours never 16777215 1 Qt::Horizontal 0 0 When pressing the Power button true BUTTONS Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen LockScreenAfterSuspendSwitch Qt::Vertical 20 0 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tSwitch QPushButton
tswitch.h
tStatusFrame QFrame
tstatusframe.h
1
================================================ FILE: plugins/PowerPlugin/sleepmonitor.cpp ================================================ #include "sleepmonitor.h" #include #include #include #include struct SleepMonitorPrivate { tSettings settings; }; SleepMonitor::SleepMonitor(QObject* parent) : QObject{parent} { d = new SleepMonitorPrivate(); QDBusConnection::systemBus().connect("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PrepareForSleep", this, SLOT(PrepareForSleep(bool))); } SleepMonitor::~SleepMonitor() { delete d; } void SleepMonitor::PrepareForSleep(bool sleeping) { if (sleeping) { if (d->settings.value("Power/suspend.lockScreen").toBool()) { //Lock the screen now StateManager::powerManager()->performPowerOperation(PowerManager::Lock); } } } ================================================ FILE: plugins/PowerPlugin/sleepmonitor.h ================================================ #ifndef SLEEPMONITOR_H #define SLEEPMONITOR_H #include struct SleepMonitorPrivate; class SleepMonitor : public QObject { Q_OBJECT public: explicit SleepMonitor(QObject* parent = nullptr); ~SleepMonitor(); private slots: void PrepareForSleep(bool sleeping); signals: private: SleepMonitorPrivate* d; }; #endif // SLEEPMONITOR_H ================================================ FILE: plugins/PowerPlugin/thedesk-power.conf ================================================ [Power] timeouts.screenoff.value=5 timeouts.screenoff.unit=min timeouts.suspend.value=15 timeouts.suspend.unit=min actions.powerbutton=ask suspend.lockScreen=true ================================================ FILE: plugins/PowerPlugin/translations/ar_SA.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/au_AU.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/cy.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/da.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/de.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/en_GB.ts ================================================ EventHandler Unable to inhibit logind power management Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend Suspend %n seconds %n second %n seconds Battery Battery Charging Charging Full Full Discharging Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power Power TIMEOUTS TIMEOUTS Switch off the screen after Switch off the screen after seconds seconds minutes minutes hours hours never never If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. Suspend after Suspend after When pressing the Power button When pressing the Power button Ask Ask Power Off Power Off Reboot Reboot Suspend Suspend Hibernate Hibernate Do Nothing Do Nothing BUTTONS BUTTONS POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance Performance mode unavailable unavailable Performance mode is %1 because your device is getting warm. Performance mode is %1. Performance mode is %1 because the device is on your lap. Performance mode temporarily unavailable temporarily unavailable A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption After suspending, lock the screen ================================================ FILE: plugins/PowerPlugin/translations/en_US.qm ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/es.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/es_VE.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/id_ID.ts ================================================ EventHandler Unable to inhibit logind power management Tidak dapat menghalangi manajemen daya dari logind Caffeinated Caffeinate Decaffeinate Suspend %n seconds %n detik Battery Baterai Charging Mengisi Full Penuh Discharging Discharge Plugin Power Stretch Disable Power Stretch PowerSettings Power Daya TIMEOUTS Switch off the screen after seconds minutes hours never If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing BUTTONS POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance Performance mode unavailable unavailable Performance mode is %1 because your device is getting warm. Performance mode is %1. Performance mode is %1 because the device is on your lap. Performance mode temporarily unavailable temporarily unavailable A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption After suspending, lock the screen ================================================ FILE: plugins/PowerPlugin/translations/nl.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/pt_BR.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/ro_RO.ts ================================================ EventHandler Unable to inhibit logind power management Nu s-a putut opri gestionarea de curent logind Caffeinated Caffeinate Decaffeinate Suspend Suspendare %n seconds O secundă %n secunde %n de secunde Battery Baterie Charging Se încarcă Full Încărcat complet Discharging Se descarcă Plugin Power Stretch Disable Power Stretch PowerSettings Power Energie TIMEOUTS OPRIRE AUTOMATĂ Switch off the screen after Închide ecranul după seconds secunde minutes minute hours ore never niciodată If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. În lipsa activității, putem opri ecranul sau intra în modul de suspendare automat pentru dumneavoastră. Suspend after Intră în modul de suspendare după When pressing the Power button Când se apasă butonul de oprire Ask Întreabă Power Off Oprire Reboot Repronire Suspend Suspendare Hibernate Hibernare Do Nothing Nimic BUTTONS BUTOANE POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance Performance mode unavailable unavailable Performance mode is %1 because your device is getting warm. Performance mode is %1. Performance mode is %1 because the device is on your lap. Performance mode temporarily unavailable temporarily unavailable A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption After suspending, lock the screen ================================================ FILE: plugins/PowerPlugin/translations/sv.ts ================================================ EventHandler Unable to inhibit logind power management Caffeinated Caffeinate Decaffeinate Suspend %n seconds Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption TIMEOUTS Switch off the screen after If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. seconds minutes hours never Suspend after When pressing the Power button Ask Power Off Reboot Suspend Hibernate Do Nothing After suspending, lock the screen BUTTONS Performance mode unavailable unavailable Performance mode temporarily unavailable temporarily unavailable Performance mode is %1 because the device is on your lap. Performance mode is %1 because your device is getting warm. Performance mode is %1. ================================================ FILE: plugins/PowerPlugin/translations/tr_TR.ts ================================================ EventHandler Unable to inhibit logind power management Logind güç yönetimi engellenemiyor Caffeinated Caffeinate Decaffeinate Suspend Askıya al %n seconds %n saniye Battery Pil Charging Doluyor Full Tam Discharging Taburcu Plugin Power Stretch Disable Power Stretch PowerSettings Power Güç TIMEOUTS ZAMAN AŞIMI Switch off the screen after Sonra ekranı kapatın seconds saniye minutes dakika hours saatler never asla If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. Cihazınızı bir süre boşta bırakırsanız, sizin için ekranı otomatik olarak kapatabilir veya askıya alabiliriz. Suspend after Sonra askıya al When pressing the Power button Güç düğmesine basıldığında Ask Sor Power Off Kapat Reboot Yeniden başlat Suspend Askıya al Hibernate Hazırda beklet Do Nothing Hiçbir şey yapma BUTTONS BUTONLAR POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance Performance mode unavailable unavailable Performance mode is %1 because your device is getting warm. Performance mode is %1. Performance mode is %1 because the device is on your lap. Performance mode temporarily unavailable temporarily unavailable A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption After suspending, lock the screen ================================================ FILE: plugins/PowerPlugin/translations/vi.ts ================================================ EventHandler Unable to inhibit logind power management Không thể ngăn cản việc quản lý điện logind Caffeinated Caffeinate Decaffeinate Suspend Tạm dừng %n seconds %n giây Battery Pin Charging Đang sạc Full Đã đầy Discharging Đang xả Plugin Power Stretch Tiết kiệm pin Disable Power Stretch Tắt chế độ tiết kiệm pin PowerSettings Power Điện POWER PROFILE HỒ SƠ ĐIỆN Balanced Cân bằng Power Stretch Tiết kiệm pin Reduce the performance of your device to save on power Giảm hiệu suất của thiết bị để tiết kiệm năng lượng Performance Hiệu suất A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Một hồ sơ điện điều chỉnh cách hệ thống của bạn chạy để ưu tiên hiệu suất hoặc giảm mức tiêu năng lượng. Performance and power consumption will be average Cân bằng hiệu suất và mục tiêu năng lượng Performance will be increased at the cost of power consumption Hiệu suất cũng như mục tiêu năng lượng sẽ được tăng lên TIMEOUTS THỜI GIAN CHỜ Switch off the screen after Tắt màn hình sau If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. Nếu bạn để thiết bị chờ trong một khoảng thời gian, chúng tôi có thể tự động tắt màn hình hoặc tạm dừng nó cho bạn. seconds giây minutes phút hours giờ never không bao giờ Suspend after Tạm dừng sau When pressing the Power button Khi nút nguồn bị bấm Ask Hỏi tôi Power Off Tắt nguồn Reboot Khởi động lại Suspend Tạm dừng Hibernate Ngủ đông Do Nothing Không làm gì After suspending, lock the screen Khóa màn hình sau khi thiết bị bị tạm dừng BUTTONS NÚT Performance mode unavailable Chế độ hiệu suất không có sẵn unavailable không sẵn Performance mode temporarily unavailable Chế độ hiệu suất không sẵn tạm thời temporarily unavailable không sẵn tạm thời Performance mode is %1 because the device is on your lap. Chế độ hiệu suất tại vì thiết bị này đang nằm trên đùi của bạn. Performance mode is %1 because your device is getting warm. Chế độ hiệu suất tại vì thiết bị của bạn đang nóng lên. Performance mode is %1. Chế độ hiệu suất %1. ================================================ FILE: plugins/PowerPlugin/translations/vi_VN.ts ================================================ EventHandler Unable to inhibit logind power management Không thể che quản lý năng lượng của logind Caffeinated Phá tạp caffeine Caffeinate Pha tạp caffeine Decaffeinate Khử caffeine Suspend Tạm dừng %n seconds %n giay Battery Pin Charging Đang sạc Full Đầy Discharging Xả Plugin Power Stretch Tiết kiệm pin Disable Power Stretch Tất tiết kiệm pin PowerSettings Power Năng lượng POWER PROFILE Hồ sơ năng lượng Balanced Cân bằng Power Stretch Tiết kiệm năng lượng Reduce the performance of your device to save on power Giảm hiệu suất của thiết bị để tiết kiệm năng lượng Performance Hiệu suất A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Hồ sơ năng lượng điều chỉnh cách hệ thống của bạn chạy để ưu tiên hiệu suất hoặc giảm tiêu năng lượng. Performance and power consumption will be average Hiệu suất và độ tiêu năng lượng là trung bình Performance will be increased at the cost of power consumption Hiệu suất tốt nhất với chi phí tiêu thụ năng lượng TIMEOUTS HẠN THỜI GIAN CHẠY KHÔNG DÙNG Switch off the screen after Tất màn hình sau If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. Nếu bạn để thiết bị nhàn rỗi trong một khoảng thời gian, chúng tôi có thể tắt màn hình hoặc tạm dừng thiết bị cho bạn. seconds giay minutes phút hours giờ never không bao giờ Suspend after Tạm dừng sau When pressing the Power button Khi nút nguồn bị nhấn Ask Hỏi tôi Power Off Tất nguồn Reboot Khởi động lại Suspend Tạm dừng Hibernate Ngủ đông Do Nothing Không làm gì After suspending, lock the screen Sau khi tạm dừng, khóa màn hình BUTTONS NÚT Performance mode unavailable Chế độ hiệu suất không có sẵn unavailable không có sẵn Performance mode temporarily unavailable Chế độ hiệu suất tạm không sẵn temporarily unavailable tạm không sẵn Performance mode is %1 because the device is on your lap. Chế độ hiệu suất %1 tại vì thiết bị nằm trong lòng bạn Performance mode is %1 because your device is getting warm. Chế độ hiệu suất %1 tại vì thiết bị của bạn đang trở nên ấm áp Performance mode is %1. Chế độ hiệu suất %1. ================================================ FILE: plugins/PowerPlugin/translations/zh_CN.ts ================================================ EventHandler Unable to inhibit logind power management 无法禁止登录电源管理 Caffeinated Caffeinate Decaffeinate Suspend 暂停 %n seconds %n 秒 Battery Charging Full Discharging Plugin Power Stretch Disable Power Stretch PowerSettings Power 电源 TIMEOUTS 超时 Switch off the screen after 在时间过后关闭屏幕 seconds minutes hours never 永不 If you leave your device idle for a period of time, we can automatically turn off the screen or suspend it for you. 如果你的机器静置超过一定时间, 我可以将屏幕为您自动关闭或者暂停。 Suspend after 暂停在 When pressing the Power button 当按下电源键时 Ask 询问 Power Off 关机 Reboot 重启 Suspend 暂停 Hibernate 休眠 Do Nothing 什么都不做 BUTTONS 按键 POWER PROFILE Balanced Power Stretch Reduce the performance of your device to save on power Performance Performance mode unavailable unavailable Performance mode is %1 because your device is getting warm. Performance mode is %1. Performance mode is %1 because the device is on your lap. Performance mode temporarily unavailable temporarily unavailable A power profile tweaks the way your system runs in order to prioritise performance or reduce power consumption. Performance and power consumption will be average Performance will be increased at the cost of power consumption After suspending, lock the screen ================================================ FILE: plugins/ScreenshotPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg) find_package(libcontemporary) set(SOURCES eventhandler.cpp plugin.cpp ) set(HEADERS eventhandler.h plugin.h ) set(PLUGIN_NAME screenshot) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-screenshot.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets Qt::Svg libcontemporary libthedesk) ================================================ FILE: plugins/ScreenshotPlugin/Plugin.json ================================================ { "name": "Screenshots", "icon": "preferences-system-display", "uuid": "d8f3c551-f356-4d6e-830e-fa90e142224c", "vi": { "name": "Chụp màn hình" } } ================================================ FILE: plugins/ScreenshotPlugin/ScreenshotPlugin.pro ================================================ QT += gui widgets svg TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ eventhandler.cpp \ penbutton.cpp \ plugin.cpp \ screenshotwindow.cpp HEADERS += \ eventhandler.h \ penbutton.h \ plugin.h \ screenshotwindow.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/ScreenshotPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/ScreenshotPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ screenshotwindow.ui RESOURCES += \ screenshot_resources.qrc ================================================ FILE: plugins/ScreenshotPlugin/eventhandler.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "eventhandler.h" #include #include #include #include #include #include #include #include #include #include #include struct EventHandlerPrivate { KeyGrab* prtScr; KeyGrab* screenshotAlt; }; EventHandler::EventHandler(QObject* parent) : QObject(parent) { d = new EventHandlerPrivate(); d->prtScr = new KeyGrab(QKeySequence(Qt::Key_Print), "screenshot"); d->screenshotAlt = new KeyGrab(QKeySequence(Qt::MetaModifier | Qt::AltModifier | Qt::Key_P), "screenshotAlt"); connect(d->prtScr, &KeyGrab::activated, this, &EventHandler::takeScreenshot); connect(d->screenshotAlt, &KeyGrab::activated, this, &EventHandler::takeScreenshot); } EventHandler::~EventHandler() { d->prtScr->deleteLater(); d->screenshotAlt->deleteLater(); delete d; } QCoro::Task<> EventHandler::takeScreenshot() { // Delegate screenshot taking to the portal auto message = QDBusMessage::createMethodCall("org.freedesktop.impl.portal.desktop.thedesk", "/org/freedesktop/portal/desktop", "org.freedesktop.impl.portal.Screenshot", "Screenshot"); message.setArguments({ QDBusObjectPath("/"), "com.vicr123.thedesk", "", QVariantMap{{"interactive", true}, {"x-thedesk-screenshot", true}} }); auto reply = co_await QDBusConnection::sessionBus().asyncCall(message, 300000); if (reply.type() != QDBusMessage::ReplyMessage) { tWarn("EventHandler") << "Unable to take screenshot"; tWarn("EventHandler") << message.errorMessage(); // Send a notification auto notification = new tNotification(); notification->setSummary(tr("Unable to take screenshot")); notification->setText(tr("Sorry, the screenshot was unable to be taken.")); notification->post(); } } ================================================ FILE: plugins/ScreenshotPlugin/eventhandler.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef EVENTHANDLER_H #define EVENTHANDLER_H #include #include struct EventHandlerPrivate; class EventHandler : public QObject { Q_OBJECT public: explicit EventHandler(QObject* parent = nullptr); ~EventHandler(); signals: private: EventHandlerPrivate* d; QCoro::Task<> takeScreenshot(); }; #endif // EVENTHANDLER_H ================================================ FILE: plugins/ScreenshotPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "eventhandler.h" #include #include #include #include #include #include #include #include struct PluginPrivate { EventHandler* keyHandler; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/ScreenshotPlugin/thedesk-screenshot.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-screenshot.conf"); d->keyHandler = new EventHandler(); } void Plugin::deactivate() { d->keyHandler->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/ScreenshotPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/ScreenshotPlugin/thedesk-screenshot.conf ================================================ ================================================ FILE: plugins/ScreenshotPlugin/translations/ar_SA.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/au_AU.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/cy.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/da.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/de.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/en_GB.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. PenButton Erase-o This and the next translation span two lines. Be spiffy with these! Erase-o matic 2000 This and the previous translation span two lines. Be spiffy with these! matic 2000 ScreenshotWindow Discard Discard Copy Copy SCREENSHOT SCREENSHOT Crop Crop Redact Redact Reset Markup Reset Markup ================================================ FILE: plugins/ScreenshotPlugin/translations/en_US.qm ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/es.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/es_VE.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/id.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/nl.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. PenButton Erase-o Supergum matic 2000 2000 Erase-o This and the next translation span two lines. Be spiffy with these! Supergum matic 2000 This and the previous translation span two lines. Be spiffy with these! 2000 ScreenshotWindow SCREENSHOT SCHERMAFBEELDING Crop Bijsnijden Redact Redigeren Reset Markup Opmaak Herstellen Discard Verwijderen Copy Kopiëren ================================================ FILE: plugins/ScreenshotPlugin/translations/pt_BR.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/ro_RO.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. PenButton Erase-o This and the next translation span two lines. Be spiffy with these! Erase-o matic 2000 This and the previous translation span two lines. Be spiffy with these! matic 2000 ScreenshotWindow Discard Renunță Copy Copiază SCREENSHOT Captură de ecran Crop Decupează Redact Redactează Reset Markup Resetează însemnările ================================================ FILE: plugins/ScreenshotPlugin/translations/sv.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. ================================================ FILE: plugins/ScreenshotPlugin/translations/tr_TR.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. PenButton Erase-o This and the next translation span two lines. Be spiffy with these! Sil-o matic 2000 This and the previous translation span two lines. Be spiffy with these! matik 2000 ScreenshotWindow Discard At Copy Kopyala SCREENSHOT EKRAN GÖRÜNTÜSÜ Crop Kırp Redact Yazıya dökmek Reset Markup İşaretlemeyi Sıfırla ================================================ FILE: plugins/ScreenshotPlugin/translations/vi.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. PenButton Erase-o This and the next translation span two lines. Be spiffy with these! Cục tẩy matic 2000 This and the previous translation span two lines. Be spiffy with these! đẹp xinh ScreenshotWindow SCREENSHOT ẢNH CHỤP MÀN HÌNH Crop Cắt xén Redact Ẩn Reset Markup Xóa đánh dấu Discard Bỏ Copy Chép ================================================ FILE: plugins/ScreenshotPlugin/translations/vi_VN.ts ================================================ EventHandler Unable to take screenshot Không thể chụp màn hình Sorry, the screenshot was unable to be taken. Rất tiếc, chúng tôi không thể chụp màn hình. ================================================ FILE: plugins/ScreenshotPlugin/translations/zh_CN.ts ================================================ EventHandler Unable to take screenshot Sorry, the screenshot was unable to be taken. PenButton Erase-o This and the next translation span two lines. Be spiffy with these! 清除-O matic 2000 This and the previous translation span two lines. Be spiffy with these! 统计2000 ScreenshotWindow Discard 取消 Copy 复制 SCREENSHOT 截图 Crop 裁剪 Redact 编辑 Reset Markup 重置绘图 ================================================ FILE: plugins/ThemePlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) set(SOURCES onboarding/onboardingtheme.cpp plugin.cpp settings/accentcolourpicker.cpp settings/themesettingspane.cpp onboarding/onboardingtheme.ui settings/themesettingspane.ui thedesk-themeplugin-resources.qrc ) set(HEADERS onboarding/onboardingtheme.h plugin.h settings/accentcolourpicker.h settings/themesettingspane.h ) set(PLUGIN_NAME theme) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-theme.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets libcontemporary libthedesk) ================================================ FILE: plugins/ThemePlugin/Plugin.json ================================================ { "name": "Theme Management", "icon": "preferences-desktop-theme", "uuid": "1e88a080-d7cf-41cc-beae-df7ed5777e5d", "vi": { "name": "Quản lý giao diện" } } ================================================ FILE: plugins/ThemePlugin/ThemePlugin.pro ================================================ QT += gui widgets TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ onboarding/onboardingtheme.cpp \ plugin.cpp \ settings/accentcolourpicker.cpp \ settings/themesettingspane.cpp HEADERS += \ onboarding/onboardingtheme.h \ plugin.h \ settings/accentcolourpicker.h \ settings/themesettingspane.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/ThemePlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/ThemePlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ onboarding/onboardingtheme.ui \ settings/themesettingspane.ui RESOURCES += \ thedesk-themeplugin-resources.qrc ================================================ FILE: plugins/ThemePlugin/onboarding/onboardingtheme.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingtheme.h" #include "ui_onboardingtheme.h" #include #include #include struct OnboardingThemePrivate { tSettings* platformSettings; }; OnboardingTheme::OnboardingTheme(QWidget* parent) : OnboardingPage(parent), ui(new Ui::OnboardingTheme) { ui->setupUi(this); d = new OnboardingThemePrivate(); d->platformSettings = new tSettings("theDesk.platform", this); ui->titleLabel->setBackButtonShown(true); connect(d->platformSettings, &tSettings::settingChanged, this, [ = ](QString key, QVariant value) { if (key == "Palette/base") { updateSettings(); } }); QPalette lightPal; lightPal.setColor(QPalette::Window, QColor(210, 210, 210)); lightPal.setColor(QPalette::WindowText, Qt::black); ui->lightContainer->setPalette(lightPal); QPalette darkPal; darkPal.setColor(QPalette::Window, QColor(40, 40, 40)); darkPal.setColor(QPalette::WindowText, Qt::white); ui->darkContainer->setPalette(darkPal); updateSettings(); } OnboardingTheme::~OnboardingTheme() { delete d; delete ui; } void OnboardingTheme::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } void OnboardingTheme::updateSettings() { QString baseColor = d->platformSettings->value("Palette/base").toString(); if (baseColor == "dark") { ui->darkButton->setChecked(true); ui->lightButton->setChecked(false); ui->emojiLabel->setPixmap(QPixmap(":/thedesk/themeplugin/icons/moonman.svg")); ui->quote->setText(tr("Intellect has spoken; blinding shall be no more!")); } else if (baseColor == "light") { ui->darkButton->setChecked(false); ui->lightButton->setChecked(true); ui->emojiLabel->setPixmap(QPixmap(":/thedesk/themeplugin/icons/sunglassesman.svg")); ui->quote->setText(tr("One whose wisdom has brought them the light of day!")); } } QString OnboardingTheme::name() { return "OnboardingTheme"; } QString OnboardingTheme::displayName() { return tr("Theme"); } void OnboardingTheme::on_titleLabel_backButtonClicked() { StateManager::onboardingManager()->previousStep(); } void OnboardingTheme::on_nextButton_clicked() { StateManager::onboardingManager()->nextStep(); } void OnboardingTheme::on_lightButton_toggled(bool checked) { if (checked) { d->platformSettings->setValue("Palette/base", "light"); } else { updateSettings(); } } void OnboardingTheme::on_darkButton_toggled(bool checked) { if (checked) { d->platformSettings->setValue("Palette/base", "dark"); } else { updateSettings(); } } ================================================ FILE: plugins/ThemePlugin/onboarding/onboardingtheme.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGTHEME_H #define ONBOARDINGTHEME_H #include namespace Ui { class OnboardingTheme; } struct OnboardingThemePrivate; class OnboardingTheme : public OnboardingPage { Q_OBJECT public: explicit OnboardingTheme(QWidget* parent = nullptr); ~OnboardingTheme(); private: Ui::OnboardingTheme* ui; OnboardingThemePrivate* d; void changeEvent(QEvent* event); void updateSettings(); // OnboardingPage interface public: QString name(); QString displayName(); private slots: void on_titleLabel_backButtonClicked(); void on_nextButton_clicked(); void on_lightButton_toggled(bool checked); void on_darkButton_toggled(bool checked); }; #endif // ONBOARDINGTHEME_H ================================================ FILE: plugins/ThemePlugin/onboarding/onboardingtheme.ui ================================================ OnboardingTheme 0 0 488 412 Form 0 0 0 0 0 Theme Select a theme. You'll be able to change this at any time. true 9 16777215 1 Qt::Horizontal 0 true Qt::Horizontal 40 20 Dark true Light Qt::Horizontal 40 20 Qt::Vertical 20 40 100 Qt::AlignCenter 20 TextLabel Qt::AlignCenter true 9 Qt::Vertical 20 40 16777215 1 Qt::Horizontal 9 9 9 9 Qt::Horizontal 40 20 Next ../../LocalePlugin/onboarding../../LocalePlugin/onboarding tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/ThemePlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "tsettings.h" #include #include #include #include #include #include #include #include #include "onboarding/onboardingtheme.h" #include "settings/themesettingspane.h" struct PluginPrivate { ThemeSettingsPane* themeSettingsPane; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/ThemePlugin/thedesk-theme.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-theme.conf"); d->themeSettingsPane = new ThemeSettingsPane(); StateManager::statusCenterManager()->addPane(d->themeSettingsPane, StatusCenterManager::SystemSettings); connect(StateManager::onboardingManager(), &OnboardingManager::onboardingRequired, this, [=] { StateManager::onboardingManager()->addOnboardingStep(new OnboardingTheme); }); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->themeSettingsPane); d->themeSettingsPane->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/ThemePlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/ThemePlugin/settings/accentcolourpicker.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "accentcolourpicker.h" #include #include #include #include struct AccentColourPickerPrivate { tSettings* settings; QString colorName; QColor color; bool checked; }; AccentColourPicker::AccentColourPicker(QWidget* parent) : QWidget(parent) { d = new AccentColourPickerPrivate(); d->settings = new tSettings("theDesk.platform", this); connect(d->settings, &tSettings::settingChanged, this, [ = ](QString key, QVariant value) { if (key == "Palette/accent") { d->checked = value.toString() == d->colorName; this->update(); } }); this->setFocusPolicy(Qt::StrongFocus); } AccentColourPicker::~AccentColourPicker() { delete d; } void AccentColourPicker::setColorName(QString name) { d->colorName = name; d->checked = d->settings->value("Palette/accent").toString() == name; updateColor(); } QSize AccentColourPicker::sizeHint() const { return SC_DPI_T(QSize(24, 24), QSize); } void AccentColourPicker::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.setBrush(d->color); painter.setPen(Qt::transparent); painter.drawRect(0, 0, this->width(), this->height()); if (d->checked) { QRect pxRect; pxRect.setSize(SC_DPI_T(QSize(16, 16), QSize)); pxRect.moveCenter(QPoint(this->width() / 2, this->height() / 2)); painter.drawPixmap(pxRect, QIcon::fromTheme("dialog-ok").pixmap(pxRect.size())); } } void AccentColourPicker::mousePressEvent(QMouseEvent* event) { event->accept(); } void AccentColourPicker::mouseReleaseEvent(QMouseEvent* event) { QRect geometry = this->geometry(); geometry.moveTopLeft(QPoint(0, 0)); if (geometry.contains(event->pos())) { d->settings->setValue("Palette/accent", d->colorName); d->settings->sync(); } } void AccentColourPicker::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Space || event->key() == Qt::Key_Return) { d->settings->setValue("Palette/accent", d->colorName); d->settings->sync(); } } void AccentColourPicker::updateColor() { if (d->colorName == "blue") { d->color = QColor(0, 50, 150); } else if (d->colorName == "green") { d->color = QColor(0, 85, 0); } else if (d->colorName == "orange") { d->color = QColor(200, 50, 0); } else if (d->colorName == "pink") { d->color = QColor(150, 0, 150); } this->update(); } ================================================ FILE: plugins/ThemePlugin/settings/accentcolourpicker.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ACCENTCOLOURPICKER_H #define ACCENTCOLOURPICKER_H #include struct AccentColourPickerPrivate; class AccentColourPicker : public QWidget { Q_OBJECT public: explicit AccentColourPicker(QWidget* parent = nullptr); ~AccentColourPicker(); void setColorName(QString name); QSize sizeHint() const; signals: private: AccentColourPickerPrivate* d; void paintEvent(QPaintEvent* event); void mousePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); void keyPressEvent(QKeyEvent* event); void updateColor(); }; #endif // ACCENTCOLOURPICKER_H ================================================ FILE: plugins/ThemePlugin/settings/themesettingspane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "themesettingspane.h" #include "ui_themesettingspane.h" #include #include #include #include #include #include #include #include struct ThemeSettingsPanePrivate { QSettings* kwinSettings; tSettings* themeSettings; tSettings settings; }; ThemeSettingsPane::ThemeSettingsPane() : StatusCenterPane(), ui(new Ui::ThemeSettingsPane) { ui->setupUi(this); d = new ThemeSettingsPanePrivate(); d->themeSettings = new tSettings("theDesk.platform", this); d->kwinSettings = new QSettings(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/kwinrc", QSettings::IniFormat); ui->titleLabel->setBackButtonIsMenu(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->coloursWidget->setFixedWidth(contentWidth); ui->fontsWidget->setFixedWidth(contentWidth); ui->widgetsWidget->setFixedWidth(contentWidth); ui->windowBordersWidget->setFixedWidth(contentWidth); ui->effectsWidget->setFixedWidth(contentWidth); ui->accentBlue->setColorName("blue"); ui->accentGreen->setColorName("green"); ui->accentOrange->setColorName("orange"); ui->accentPink->setColorName("pink"); for (QString key : QStyleFactory::keys()) { QSignalBlocker blocker(ui->widgetThemeBox); ui->widgetThemeBox->addItem(key); } connect(d->themeSettings, &tSettings::settingChanged, this, [ = ](QString key, QVariant value) { if (key == "Palette/base") { updateBaseColour(); } else if (key.startsWith("Fonts/")) { updateFonts(); } else if (key == "Platform/style") { updateWidgets(); } }); updateBaseColour(); updateFonts(); updateWidgets(); connect(&d->settings, &tSettings::settingChanged, this, [ = ](QString key, QVariant value) { if (key == "Appearance/translucent") { ui->transparencySwitch->setChecked(value.toBool()); } }); ui->transparencySwitch->setChecked(d->settings.value("Appearance/translucent").toBool()); } ThemeSettingsPane::~ThemeSettingsPane() { delete d; delete ui; } void ThemeSettingsPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } void ThemeSettingsPane::updateBaseColour() { d->kwinSettings->beginGroup("org.kde.kdecoration2"); QString theme = d->kwinSettings->value("theme").toString(); QString library = d->kwinSettings->value("library").toString(); d->kwinSettings->endGroup(); bool isHandlingWindowBorders = (library == "org.kde.kwin.aurorae" && theme.startsWith("__aurorae__svg__Contemporary")); QSignalBlocker blocker(ui->baseColourComboBox); QString baseColor = d->themeSettings->value("Palette/base").toString(); if (baseColor == "dark") { ui->baseColourComboBox->setCurrentIndex(0); } else if (baseColor == "light") { ui->baseColourComboBox->setCurrentIndex(1); } if (isHandlingWindowBorders) { writeWindowBorders(); } else { //Ensure that KWin is running and that the themes are (probably) installed if (QDir("/usr/share/aurorae/themes/Contemporary").exists() && QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.KWin").value()) { ui->windowBordersConditonalWidget->expand(); } } } void ThemeSettingsPane::updateFonts() { QSignalBlocker blocker1(ui->interfaceFont); QSignalBlocker blocker2(ui->interfaceFontSize); QSignalBlocker blocker3(ui->fixedFont); QSignalBlocker blocker4(ui->fixedFontSize); QStringList systemFont = d->themeSettings->value("Fonts/system").toStringList(); if (systemFont.count() == 2) { QFont font(systemFont.at(0)); ui->interfaceFont->setCurrentFont(font); ui->interfaceFontSize->setValue(systemFont.at(1).toDouble()); } QStringList fixedFont = d->themeSettings->value("Fonts/fixed").toStringList(); if (fixedFont.count() == 2) { QFont font(fixedFont.at(0)); ui->fixedFont->setCurrentFont(font); ui->fixedFontSize->setValue(fixedFont.at(1).toDouble()); } } void ThemeSettingsPane::updateWidgets() { QSignalBlocker blocker(ui->widgetThemeBox); QString name = d->themeSettings->value("Platform/style").toString(); ui->widgetThemeBox->setCurrentIndex(QStyleFactory::keys().indexOf(name)); } void ThemeSettingsPane::setFonts() { d->themeSettings->setValue("Fonts/system", QStringList({ ui->interfaceFont->currentFont().family(), QString::number(ui->interfaceFontSize->value()) })); d->themeSettings->setValue("Fonts/fixed", QStringList({ ui->fixedFont->currentFont().family(), QString::number(ui->fixedFontSize->value()) })); } void ThemeSettingsPane::writeWindowBorders() { QString theme; QString baseColor = d->themeSettings->value("Palette/base").toString(); if (baseColor == "dark") { theme = "__aurorae__svg__Contemporary"; } else { theme = "__aurorae__svg__Contemporary-light"; } d->kwinSettings->beginGroup("org.kde.kdecoration2"); if (d->kwinSettings->value("theme").toString() == theme && d->kwinSettings->value("library").toString() == "org.kde.kwin.aurorae") { //Nothing to do d->kwinSettings->endGroup(); return; } d->kwinSettings->setValue("library", "org.kde.kwin.aurorae"); d->kwinSettings->setValue("theme", theme); d->kwinSettings->endGroup(); d->kwinSettings->sync(); //Reload KWin QDBusMessage message = QDBusMessage::createMethodCall("org.kde.KWin", "/KWin", "org.kde.KWin", "reconfigure"); QDBusConnection::sessionBus().asyncCall(message); ui->windowBordersConditonalWidget->collapse(); } QString ThemeSettingsPane::name() { return "ThemeSettings"; } QString ThemeSettingsPane::displayName() { return tr("Theme"); } QIcon ThemeSettingsPane::icon() { return QIcon::fromTheme("preferences-desktop-theme"); } QWidget* ThemeSettingsPane::leftPane() { return nullptr; } void ThemeSettingsPane::on_baseColourComboBox_currentIndexChanged(int index) { switch (index) { case 0: d->themeSettings->setValue("Palette/base", "dark"); break; case 1: d->themeSettings->setValue("Palette/base", "light"); } } void ThemeSettingsPane::on_titleLabel_backButtonClicked() { StateManager::statusCenterManager()->showStatusCenterHamburgerMenu(); } void ThemeSettingsPane::on_fixedFont_currentFontChanged(const QFont& f) { setFonts(); } void ThemeSettingsPane::on_fixedFontSize_valueChanged(double arg1) { setFonts(); } void ThemeSettingsPane::on_interfaceFont_currentFontChanged(const QFont& f) { setFonts(); } void ThemeSettingsPane::on_interfaceFontSize_valueChanged(double arg1) { setFonts(); } void ThemeSettingsPane::on_widgetThemeBox_currentIndexChanged(int index) { QString name = QStyleFactory::keys().at(index); d->themeSettings->setValue("Platform/style", name); } void ThemeSettingsPane::on_setWindowBordersButton_clicked() { writeWindowBorders(); } void ThemeSettingsPane::on_transparencySwitch_toggled(bool checked) { d->settings.setValue("Appearance/translucent", checked); } ================================================ FILE: plugins/ThemePlugin/settings/themesettingspane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef THEMESETTINGSPANE_H #define THEMESETTINGSPANE_H #include namespace Ui { class ThemeSettingsPane; } struct ThemeSettingsPanePrivate; class ThemeSettingsPane : public StatusCenterPane { Q_OBJECT public: explicit ThemeSettingsPane(); ~ThemeSettingsPane(); private: Ui::ThemeSettingsPane* ui; ThemeSettingsPanePrivate* d; void changeEvent(QEvent* event); void updateBaseColour(); void updateFonts(); void updateWidgets(); void setFonts(); void writeWindowBorders(); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); private slots: void on_baseColourComboBox_currentIndexChanged(int index); void on_titleLabel_backButtonClicked(); void on_fixedFont_currentFontChanged(const QFont& f); void on_fixedFontSize_valueChanged(double arg1); void on_interfaceFont_currentFontChanged(const QFont& f); void on_interfaceFontSize_valueChanged(double arg1); void on_widgetThemeBox_currentIndexChanged(int index); void on_setWindowBordersButton_clicked(); void on_transparencySwitch_toggled(bool checked); }; #endif // THEMESETTINGSPANE_H ================================================ FILE: plugins/ThemePlugin/settings/themesettingspane.ui ================================================ ThemeSettingsPane 0 0 627 620 Form 0 0 0 0 0 Theme QFrame::NoFrame true 0 -124 613 735 0 0 0 0 0 0 0 0 0 0 Qt::StrongFocus Qt::StrongFocus Qt::StrongFocus Qt::StrongFocus Accent Colour 0 0 Dark Light Change the colours of the interface Base Colour 75 true COLOURS 16777215 1 Qt::Horizontal 0 0 0 0 0 75 true WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. true Set Window Borders 16777215 1 Qt::Horizontal Fixed Width Font Interface Font 0 0 75 true FONTS 0 0 QFontComboBox::MonospacedFonts 0 5.000000000000000 0 5.000000000000000 16777215 1 Qt::Horizontal Set the appearance of buttons, text boxes and other interface elements Widget Theme 75 true WIDGETS 0 0 QFrame::StyledPanel QFrame::Raised 0 -1 Qt::Horizontal 40 20 Button .. Radio Button 2 true Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 true 75 true DEMO Check Box 1 24 Type here! 16777215 1 Qt::Horizontal 0 0 Transparency Effects TransparencySwitch 75 true EFFECTS Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
AccentColourPicker QWidget
settings/accentcolourpicker.h
1
tSwitch QPushButton
tswitch.h
tConditionalWidget QWidget
tconditionalwidget.h
1
scrollArea baseColourComboBox accentBlue accentGreen accentOrange accentPink interfaceFont interfaceFontSize fixedFont fixedFontSize
================================================ FILE: plugins/ThemePlugin/thedesk-theme.conf ================================================ ================================================ FILE: plugins/ThemePlugin/thedesk-themeplugin-resources.qrc ================================================ icons/moonman.svg icons/sunglassesman.svg ================================================ FILE: plugins/ThemePlugin/translations/ar_SA.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/au_AU.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/cy.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/da.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/de.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/en_GB.ts ================================================ OnboardingTheme Theme Theme Select a theme. You'll be able to change this at any time. Select a theme. You'll be able to change this at any time. Dark Dark Light Light Next Next Intellect has spoken; blinding shall be no more! Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Theme Dark Dark Light Light Change the colours of the interface Change the colours of the interface COLOURS COLOURS WINDOW BORDERS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Set Window Borders Fixed Width Font Fixed Width Font Interface Font Interface Font FONTS FONTS Widget Theme Widget Theme Button Button Radio Button 2 Radio Button 2 Using the theme set above, interface elements will look like this: Using the theme set above, interface elements will look like this: Radio Button 1 Radio Button 1 Check Box 2 Check Box 2 DEMO DEMO Check Box 1 Check Box 1 Type here! Type here! Transparency Effects Transparency Effects EFFECTS EFFECTS Set the appearance of buttons, text boxes and other interface elements Set the appearance of buttons, text boxes and other interface elements WIDGETS WIDGETS Base Colour Base Colour Accent Colour Accent Colour ================================================ FILE: plugins/ThemePlugin/translations/en_US.qm ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/es.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/es_VE.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/id_ID.ts ================================================ OnboardingTheme Theme Tema Select a theme. You'll be able to change this at any time. Pilih tema. Anda dapat menggantinya kapan saja. Dark Gelap Light Terang Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Tema Dark Gelap Light Terang Change the colours of the interface Mengganti warna umum desktop COLOURS WARNA WINDOW BORDERS DEKORASI JENDELA If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Jika dekorasi tidak sesuai dengan tema yang Anda pilih, kami dapat memperbaikinya. Ini akan mengganti dekorasi jendela pada KDE serta desktop apapun yang menggunakan KWin sebagai manajer jendela. Set Window Borders Terapkan Fixed Width Font Font Kode Interface Font Font Antarmuka FONTS FONT Widget Theme Tema Widget Button Tombol Radio Button 2 Tombol Pilihan 2 Using the theme set above, interface elements will look like this: Dengan tema di atas, elemen antarmuka akan tampil seperti ini: Radio Button 1 Tombol Pilihan 1 Check Box 2 Centang 2 DEMO DEMO Check Box 1 Centang 1 Type here! Ketik di sini! Transparency Effects Efek Transparan EFFECTS EFEK Set the appearance of buttons, text boxes and other interface elements Mengatur tampilan tombol, kotak teks dan elemen antarmuka lainnya WIDGETS WIDGET Base Colour Warna Dasar Accent Colour Warna Aksen ================================================ FILE: plugins/ThemePlugin/translations/nl.ts ================================================ OnboardingTheme Theme Thema Select a theme. You'll be able to change this at any time. Selecteer een thema. Je kunt deze altijd aanpassen. Dark Donker Light Licht Next Volgende Intellect has spoken; blinding shall be no more! Kennis heeft gesproken; verblinding is voorbij! One whose wisdom has brought them the light of day! Een waarvan de wijsheid het daglicht heeft gebracht! ThemeSettingsPane Theme Thema Accent Colour Accentkleur Dark Donker Light Licht Change the colours of the interface De kleuren van de interface veranderen Base Colour Basiskleur COLOURS KLEUREN WINDOW BORDERS VENSTERRANDEN If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Als de vensterranden er niet goed uitzien, kunnen we dat voor je oplossen. Dat verandert ook de vensterranden in KDE en alle andere desktops die KWin als window manager gebruiken. Set Window Borders Vensterranden Instellen Fixed Width Font Lettertype met Gelijke Breedte Interface Font Lettertype voor Interface FONTS LETTERTYPES Set the appearance of buttons, text boxes and other interface elements Het uiterlijk van knoppen, tekstvakken en andere interface-elementen aanpassen Widget Theme Widgetthema WIDGETS WIDGETS Button Knop Radio Button 2 Radio-knop 2 Using the theme set above, interface elements will look like this: Met het thema van hierboven zien interface-elementen er zo uit: Radio Button 1 Radio-knop 1 Check Box 2 Checkbox 2 DEMO DEMO Check Box 1 Checkbox 1 Type here! Type hier! Transparency Effects Transparantie-effecten EFFECTS EFFECTEN ================================================ FILE: plugins/ThemePlugin/translations/pt_BR.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/ro.ts ================================================ OnboardingTheme Theme Temă Select a theme. You'll be able to change this at any time. Selectați o temă. O veți putea schimba oricând. Dark Întunecat Light Luminos Next Următorul Intellect has spoken; blinding shall be no more! Intelectul a vorbit; lumina orbitoare să dispară! One whose wisdom has brought them the light of day! Pentru cei pe care înțelepciunea le-a adus lumina zilei! ThemeSettingsPane Theme Temă Accent Colour Culoare de accent Dark Întunecat Light Luminos Change the colours of the interface Schimbați culorile interfeței Base Colour Culoarea de bază COLOURS CULORI WINDOW BORDERS CONTURUL FERESTRELOR If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Dacă nu arată corect conturul ferestrelor, putem rezolva acest lucru pentru dvs. Acest proces va schimba conturul ferestrelor în KDE cât și în orice alt desktop care folosește KWin pentru gestiunea ferestrelor. Set Window Borders Configurați conturul ferestrelor Fixed Width Font Font de lățime fixă Interface Font Font interfață FONTS FONTURI Set the appearance of buttons, text boxes and other interface elements Selectați aspectul butoanelor, căsuțelor de text și a altor elemente de interfață Widget Theme Temă widgeturi WIDGETS WIDGETURI Button Buton Radio Button 2 Buton radio 2 Using the theme set above, interface elements will look like this: Folosind tema setată mai sus, elementele de interfață vor arăta așa: Radio Button 1 Buton radio 1 Check Box 2 Casetă de selectare 2 DEMO DEMO Check Box 1 Casetă de selectare 1 Type here! Tastați aici! Transparency Effects Efecte de transparență EFFECTS EFECTE ================================================ FILE: plugins/ThemePlugin/translations/sv.ts ================================================ OnboardingTheme Theme Select a theme. You'll be able to change this at any time. Dark Light Next Intellect has spoken; blinding shall be no more! One whose wisdom has brought them the light of day! ThemeSettingsPane Theme Accent Colour Dark Light Change the colours of the interface Base Colour COLOURS WINDOW BORDERS If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Set Window Borders Fixed Width Font Interface Font FONTS Set the appearance of buttons, text boxes and other interface elements Widget Theme WIDGETS Button Radio Button 2 Using the theme set above, interface elements will look like this: Radio Button 1 Check Box 2 DEMO Check Box 1 Type here! Transparency Effects EFFECTS ================================================ FILE: plugins/ThemePlugin/translations/tr_TR.ts ================================================ OnboardingTheme Theme Tema Select a theme. You'll be able to change this at any time. Bir tema seç. Bunu istediğiniz zaman değiştirebileceksiniz. Dark Karanlık Light Aydınlık Next Sonraki Intellect has spoken; blinding shall be no more! Akıl konuştu; kör edici olmayacak artık! One whose wisdom has brought them the light of day! Hikmeti onlara gün ışığını getiren biri! ThemeSettingsPane Theme Tema Dark Karanlık Light Aydınlık Change the colours of the interface Arayüzün renklerini değiştirin COLOURS RENKLER WINDOW BORDERS PENCERE KENARLARI If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Pencere kenarlıkları doğru görünmüyorsa, bunu sizin için düzeltebiliriz. Bu aynı zamanda KDE'deki pencere kenarlıklarınızı ve pencere yöneticisi için KWin kullanan diğer masaüstlerini de değiştirecektir. Set Window Borders Pencere Kenarlıklarını Ayarlama Fixed Width Font Sabit Genişlikli Yazı Tipi Interface Font Arayüz Yazı Tipi FONTS FONTLAR Widget Theme Widget Teması Button Buton Radio Button 2 Radyo Düğmesi 2 Using the theme set above, interface elements will look like this: Yukarıdaki tema kümesini kullandığınızda, arayüz öğeleri şöyle görünecektir: Radio Button 1 Radyo Düğmesi 1 Check Box 2 Onay Kutusu 2 DEMO GÖSTERİM Check Box 1 Onay Kutusu 1 Type here! Buraya yaz! Transparency Effects Şeffaflık Etkileri EFFECTS ÖZEL EFEKTLER Set the appearance of buttons, text boxes and other interface elements Düğmelerin, metin kutularının ve diğer arayüz öğelerinin görünümünü ayarlayın WIDGETS WIDGET'LAR Base Colour Temel Renk Accent Colour Vurgu Rengi ================================================ FILE: plugins/ThemePlugin/translations/vi_VN.ts ================================================ OnboardingTheme Theme Giao diện Select a theme. You'll be able to change this at any time. Chọn một giao diện. Bạn có thể thay đổi điều này bất cứ lúc nào. Dark Tối Light Sáng Next Tiếp Intellect has spoken; blinding shall be no more! Người khôn ngoan đã nói; không bao giờ chói mắt nữa! One whose wisdom has brought them the light of day! Người mà sự khôn ngoan đã mang lại ánh sáng ban ngày! ThemeSettingsPane Theme Giao diện Dark Tối Light Sáng Change the colours of the interface Thay đổi màu giao diện COLOURS MÀU WINDOW BORDERS ĐƯỜNG VIỀN CỬA SỔ If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. Nếu viền cửa sổ không chính xác, chúng tôi có thể sửa lại cho bạn. Nếu viền cửa sổ không chính xác, chúng tôi có thể sửa lại cho bạn. Hoạt động này cũng sẽ thay đổi viền cửa sổ của bạn trong KDE và bất kỳ môi trường desktop khác sử dụng KWin cho trình quản lý cửa sổ. Set Window Borders Sửa viền cửa sổ Fixed Width Font Phông chữ đơn cách Interface Font Phông chữ giao diện FONTS PHÔNG Widget Theme Giao diện thành phần Button Nút Radio Button 2 Nút chọn 2 Using the theme set above, interface elements will look like this: Sử dụng giao diện được đặt ở trên, các thành phần sẽ hiện như thế này: Radio Button 1 Nút chọn 1 Check Box 2 Hộp kiểm 2 DEMO BẢN XEM TRƯỚC Check Box 1 Hộp kiểm 1 Type here! Nhập ở đây! Transparency Effects Hiệu ứng trong suốt EFFECTS HIỆU ỨNG Set the appearance of buttons, text boxes and other interface elements Đặt sự xuất hiện cho nút, hộp văn bản và các thành phần giao diện WIDGETS THÀNH PHẦN GIAO DIỆN Base Colour Màu nền Accent Colour Màu sắc ================================================ FILE: plugins/ThemePlugin/translations/zh_CN.ts ================================================ OnboardingTheme Theme 皮肤 Select a theme. You'll be able to change this at any time. 选择一个皮肤, 你可以对其随时更改。 Dark 暗黑 Light 日光 Next 下一项 Intellect has spoken; blinding shall be no more! 暗黑模式开启! One whose wisdom has brought them the light of day! 日光模式开启! ThemeSettingsPane Theme 皮肤 Dark 暗黑 Light 日光 Change the colours of the interface 更改界面的色彩 COLOURS 颜色 WINDOW BORDERS 窗框 If the window borders don't look correct, we can fix that up for you. This will also change your window borders in KDE, and any other desktop that uses KWin for the window manager. 如果窗框看上去不正确, 我们可以为您修复。 这也会更改你KDE里的窗框,或者其他任何桌面适用于KWin。 Set Window Borders 设置窗框 Fixed Width Font 修复了字体 Interface Font 界面字体 FONTS 字体 Widget Theme 小部件皮肤 Button 按键 Radio Button 2 按键 2 Using the theme set above, interface elements will look like this: 使用此皮肤, 界面将会看上去像: Radio Button 1 按键 1 Check Box 2 选择框 2 DEMO 演示 Check Box 1 选择框 1 Type here! 在此输入! Transparency Effects 透明效果 EFFECTS 效果 Set the appearance of buttons, text boxes and other interface elements 设置按键的外观, 输入栏 和 其他界面元素 WIDGETS 小部件 Base Colour 基础色 Accent Colour 点缀色 ================================================ FILE: plugins/TimeDatePlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(libcontemporary) set(SOURCES onboarding/onboardingtimezone.cpp plugin.cpp popovers/settimedatepopover.cpp popovers/settimezonepopover.cpp settings/datetimepane.cpp timezonesmodel.cpp onboarding/onboardingtimezone.ui popovers/settimedatepopover.ui popovers/settimezonepopover.ui settings/datetimepane.ui ) set(HEADERS onboarding/onboardingtimezone.h plugin.h popovers/settimedatepopover.h popovers/settimezonepopover.h settings/datetimepane.h timezonesmodel.h ) set(PLUGIN_NAME timedate) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-timedate.conf) target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets libcontemporary libthedesk) ================================================ FILE: plugins/TimeDatePlugin/Plugin.json ================================================ { "name": "Date and Time management", "icon": "preferences-system-time", "uuid": "e8e71dad-f372-4f96-a2c9-3462af834ada", "vi": { "name": "Quản lý ngày và giờ" } } ================================================ FILE: plugins/TimeDatePlugin/TimeDatePlugin.pro ================================================ QT += gui widgets TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ onboarding/onboardingtimezone.cpp \ plugin.cpp \ popovers/settimedatepopover.cpp \ popovers/settimezonepopover.cpp \ settings/datetimepane.cpp \ timezonesmodel.cpp HEADERS += \ onboarding/onboardingtimezone.h \ plugin.h \ popovers/settimedatepopover.h \ popovers/settimezonepopover.h \ settings/datetimepane.h \ timezonesmodel.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/TimeDatePlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/TimeDatePlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ onboarding/onboardingtimezone.ui \ popovers/settimedatepopover.ui \ popovers/settimezonepopover.ui \ settings/datetimepane.ui ================================================ FILE: plugins/TimeDatePlugin/onboarding/onboardingtimezone.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingtimezone.h" #include "ui_onboardingtimezone.h" #include "timezonesmodel.h" #include #include #include #include struct OnboardingTimeZonePrivate { TimezonesModel* model; }; OnboardingTimeZone::OnboardingTimeZone(QWidget* parent) : OnboardingPage(parent), ui(new Ui::OnboardingTimeZone) { ui->setupUi(this); d = new OnboardingTimeZonePrivate(); d->model = new TimezonesModel(); ui->titleLabel->setBackButtonShown(true); ui->listView->setModel(d->model); ui->listView->setItemDelegate(new TimezonesModelDelegate()); ui->nextButton->setEnabled(false); } OnboardingTimeZone::~OnboardingTimeZone() { delete ui; } QString OnboardingTimeZone::name() { return QStringLiteral("OnboardingTimeZone"); } QString OnboardingTimeZone::displayName() { return tr("Time Zone"); } void OnboardingTimeZone::on_titleLabel_backButtonClicked() { StateManager::onboardingManager()->previousStep(); } void OnboardingTimeZone::on_nextButton_clicked() { StateManager::onboardingManager()->nextStep(); } void OnboardingTimeZone::on_searchBox_textChanged(const QString& arg1) { d->model->search(arg1); } void OnboardingTimeZone::on_listView_activated(const QModelIndex& index) { QDBusMessage setTimezoneMessage = QDBusMessage::createMethodCall("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetTimezone"); setTimezoneMessage.setArguments({index.data(Qt::UserRole).toString(), true}); QDBusConnection::systemBus().call(setTimezoneMessage, QDBus::NoBlock); StateManager::onboardingManager()->setDateVisible(true); ui->nextButton->setEnabled(true); } void OnboardingTimeZone::on_ntpCheckbox_toggled(bool checked) { QDBusMessage setNtpMessage = QDBusMessage::createMethodCall("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetNTP"); setNtpMessage.setArguments({checked, true}); QDBusConnection::systemBus().call(setNtpMessage); } ================================================ FILE: plugins/TimeDatePlugin/onboarding/onboardingtimezone.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGTIMEZONE_H #define ONBOARDINGTIMEZONE_H #include #include namespace Ui { class OnboardingTimeZone; } struct OnboardingTimeZonePrivate; class OnboardingTimeZone : public OnboardingPage { Q_OBJECT public: explicit OnboardingTimeZone(QWidget* parent = nullptr); ~OnboardingTimeZone(); private: Ui::OnboardingTimeZone* ui; OnboardingTimeZonePrivate* d; // OnboardingPage interface public: QString name(); QString displayName(); private slots: void on_titleLabel_backButtonClicked(); void on_nextButton_clicked(); void on_searchBox_textChanged(const QString& arg1); void on_listView_activated(const QModelIndex& index); void on_ntpCheckbox_toggled(bool checked); }; #endif // ONBOARDINGTIMEZONE_H ================================================ FILE: plugins/TimeDatePlugin/onboarding/onboardingtimezone.ui ================================================ OnboardingTimeZone 0 0 617 420 Form 0 0 0 0 0 Time Zone Whereabouts are you located? We'll use this information to display the current time. true 9 16777215 1 Qt::Horizontal false Search 16777215 1 Qt::Horizontal QFrame::NoFrame 16777215 1 Qt::Horizontal 9 9 9 9 Use the Internet to synchronise the system clock (recommended) 16777215 1 Qt::Horizontal 6 9 9 9 9 Qt::Horizontal 40 20 Next ../../../thedesk/libthedesk/onboarding../../../thedesk/libthedesk/onboarding tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/TimeDatePlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "tsettings.h" #include #include #include #include #include #include #include #include #include "settings/datetimepane.h" #include "onboarding/onboardingtimezone.h" struct PluginPrivate { DateTimePane* dateTimePane; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/TimeDatePlugin/thedesk-timedate.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-timedate.conf"); d->dateTimePane = new DateTimePane(); StateManager::statusCenterManager()->addPane(d->dateTimePane, StatusCenterManager::SystemSettings); QObject::connect(StateManager::onboardingManager(), &OnboardingManager::onboardingRequired, [=] { StateManager::onboardingManager()->addOnboardingStep(new OnboardingTimeZone()); }); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->dateTimePane); d->dateTimePane->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/TimeDatePlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/TimeDatePlugin/popovers/settimedatepopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "settimedatepopover.h" #include "ui_settimedatepopover.h" #include #include #include #include struct SetTimeDatePopoverPrivate { tDateTimePicker* datePicker; tDateTimePicker* timePicker; }; SetTimeDatePopover::SetTimeDatePopover(QWidget* parent) : QWidget(parent), ui(new Ui::SetTimeDatePopover) { ui->setupUi(this); d = new SetTimeDatePopoverPrivate(); ui->titleLabel->setBackButtonShown(true); d->datePicker = new tDateTimePicker(this); d->timePicker = new tDateTimePicker(this); ui->pickerLayout->addWidget(d->datePicker); ui->pickerLayout->addWidget(d->timePicker); QFont fnt = d->datePicker->font(); fnt.setPointSize(30); d->datePicker->setFont(fnt); d->timePicker->setFont(fnt); d->datePicker->setDateTime(QDateTime::currentDateTime()); d->datePicker->setPickOptions(tDateTimePicker::PickDate); d->timePicker->setDateTime(QDateTime::currentDateTime()); d->timePicker->setPickOptions(tDateTimePicker::PickTime); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->spinner->setFixedSize(SC_DPI_T(QSize(32, 32), QSize)); } SetTimeDatePopover::~SetTimeDatePopover() { delete ui; delete d; } void SetTimeDatePopover::on_titleLabel_backButtonClicked() { emit done(); } void SetTimeDatePopover::on_applyButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->spinnerPage); QDateTime selectedDateTime(d->datePicker->currentDateTime().date(), d->timePicker->currentDateTime().time()); qint64 milliSinceEpoch = selectedDateTime.toMSecsSinceEpoch() * 1000; QDBusMessage setTimeMessage = QDBusMessage::createMethodCall("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetTime"); setTimeMessage.setArguments({milliSinceEpoch, false, true}); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(QDBusConnection::systemBus().asyncCall(setTimeMessage)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { ui->stackedWidget->setCurrentWidget(ui->dateTimePage); } else { emit done(); } watcher->deleteLater(); }); } ================================================ FILE: plugins/TimeDatePlugin/popovers/settimedatepopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2022 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SETTIMEDATEPOPOVER_H #define SETTIMEDATEPOPOVER_H #include namespace Ui { class SetTimeDatePopover; } struct SetTimeDatePopoverPrivate; class SetTimeDatePopover : public QWidget { Q_OBJECT public: explicit SetTimeDatePopover(QWidget* parent = nullptr); ~SetTimeDatePopover(); signals: void done(); private slots: void on_titleLabel_backButtonClicked(); void on_applyButton_clicked(); private: Ui::SetTimeDatePopover* ui; SetTimeDatePopoverPrivate* d; }; #endif // SETTIMEDATEPOPOVER_H ================================================ FILE: plugins/TimeDatePlugin/popovers/settimedatepopover.ui ================================================ SetTimeDatePopover 0 0 400 300 Form 0 0 0 0 0 0 0 0 0 0 0 Set Date and Time What's the current date and time? 9 Apply Date and Time Qt::Vertical 20 107 Qt::Vertical 20 121 Qt::Horizontal 171 20 Qt::Horizontal 170 20 Qt::Vertical 20 120 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/TimeDatePlugin/popovers/settimezonepopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "settimezonepopover.h" #include "ui_settimezonepopover.h" #include "timezonesmodel.h" #include #include #include struct SetTimezonePopoverPrivate { TimezonesModel* model; }; SetTimezonePopover::SetTimezonePopover(QWidget* parent) : QWidget(parent), ui(new Ui::SetTimezonePopover) { ui->setupUi(this); d = new SetTimezonePopoverPrivate(); d->model = new TimezonesModel(); ui->titleLabel->setBackButtonShown(true); ui->listView->setModel(d->model); ui->listView->setItemDelegate(new TimezonesModelDelegate()); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->spinner->setFixedSize(SC_DPI_T(QSize(32, 32), QSize)); } SetTimezonePopover::~SetTimezonePopover() { delete ui; delete d; } void SetTimezonePopover::on_titleLabel_backButtonClicked() { emit done(); } void SetTimezonePopover::on_listView_activated(const QModelIndex& index) { ui->stackedWidget->setCurrentWidget(ui->spinnerPage); QDBusMessage setTimezoneMessage = QDBusMessage::createMethodCall("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetTimezone"); setTimezoneMessage.setArguments({index.data(Qt::UserRole).toString(), true}); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(QDBusConnection::systemBus().asyncCall(setTimezoneMessage)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { ui->stackedWidget->setCurrentWidget(ui->timezonesPage); } else { emit done(); } watcher->deleteLater(); }); } void SetTimezonePopover::on_searchBox_textChanged(const QString& arg1) { d->model->search(arg1); } ================================================ FILE: plugins/TimeDatePlugin/popovers/settimezonepopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SETTIMEZONEPOPOVER_H #define SETTIMEZONEPOPOVER_H #include namespace Ui { class SetTimezonePopover; } struct SetTimezonePopoverPrivate; class SetTimezonePopover : public QWidget { Q_OBJECT public: explicit SetTimezonePopover(QWidget* parent = nullptr); ~SetTimezonePopover(); signals: void done(); private slots: void on_titleLabel_backButtonClicked(); void on_listView_activated(const QModelIndex& index); void on_searchBox_textChanged(const QString& arg1); private: Ui::SetTimezonePopover* ui; SetTimezonePopoverPrivate* d; }; #endif // SETTIMEZONEPOPOVER_H ================================================ FILE: plugins/TimeDatePlugin/popovers/settimezonepopover.ui ================================================ SetTimezonePopover 0 0 400 300 Form 0 0 0 0 0 0 0 0 0 0 0 Set Timezone Where are you now? 9 16777215 1 Qt::Horizontal false Search 16777215 1 Qt::Horizontal QFrame::NoFrame Qt::Vertical 20 121 Qt::Horizontal 171 20 Qt::Horizontal 170 20 Qt::Vertical 20 120 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/TimeDatePlugin/settings/datetimepane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "datetimepane.h" #include "ui_datetimepane.h" #include #include #include #include #include #include "popovers/settimezonepopover.h" #include "popovers/settimedatepopover.h" struct DateTimePanePrivate { bool updating = false; }; DateTimePane::DateTimePane() : StatusCenterPane(), ui(new Ui::DateTimePane) { ui->setupUi(this); d = new DateTimePanePrivate(); ui->titleLabel->setBackButtonShown(true); ui->titleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->titleLabel, &tTitleLabel::setBackButtonShown); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->actionsWidget->setFixedWidth(contentWidth); ui->timeSyncWidget->setFixedWidth(contentWidth); QDBusConnection::systemBus().connect("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(propertiesChanged(QString, QVariantMap, QStringList))); forceUpdate(); } DateTimePane::~DateTimePane() { delete d; delete ui; } void DateTimePane::forceUpdate() { QDBusInterface timedateInterface("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", QDBusConnection::systemBus()); QVariantMap changedProperties; changedProperties.insert("NTP", timedateInterface.property("NTP")); changedProperties.insert("Timezone", timedateInterface.property("Timezone")); this->propertiesChanged("org.freedesktop.timedate1", changedProperties, changedProperties.keys()); } QString DateTimePane::name() { return QStringLiteral("DateTimeSettings"); } QString DateTimePane::displayName() { return tr("Date and Time"); } QIcon DateTimePane::icon() { return QIcon::fromTheme("preferences-system-time"); } QWidget* DateTimePane::leftPane() { return nullptr; } void DateTimePane::on_titleLabel_backButtonClicked() { StateManager::instance()->statusCenterManager()->showStatusCenterHamburgerMenu(); } void DateTimePane::on_ntpSwitch_toggled(bool checked) { if (d->updating) return; QDBusMessage setNtpMessage = QDBusMessage::createMethodCall("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetNTP"); setNtpMessage.setArguments({checked, true}); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(QDBusConnection::systemBus().asyncCall(setNtpMessage)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [ = ] { forceUpdate(); watcher->deleteLater(); }); } void DateTimePane::propertiesChanged(QString interfaceName, QVariantMap changedProperties, QStringList invalidatedProperties) { Q_UNUSED(interfaceName) d->updating = true; if (invalidatedProperties.contains("NTP")) { ui->ntpSwitch->setChecked(changedProperties.value("NTP").toBool()); ui->changeDateTimeButton->setEnabled(!changedProperties.value("NTP").toBool()); } d->updating = false; } void DateTimePane::on_changeTimezoneButton_clicked() { SetTimezonePopover* setTimezone = new SetTimezonePopover(); tPopover* popover = new tPopover(setTimezone); popover->setPopoverWidth(SC_DPI(600)); connect(setTimezone, &SetTimezonePopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, setTimezone, &SetTimezonePopover::deleteLater); popover->show(this->window()); } void DateTimePane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } void DateTimePane::on_changeDateTimeButton_clicked() { SetTimeDatePopover* setTimeDate = new SetTimeDatePopover(); tPopover* popover = new tPopover(setTimeDate); popover->setPopoverWidth(SC_DPI(600)); connect(setTimeDate, &SetTimeDatePopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, setTimeDate, &SetTimezonePopover::deleteLater); popover->show(this->window()); } ================================================ FILE: plugins/TimeDatePlugin/settings/datetimepane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef DATETIMEPANE_H #define DATETIMEPANE_H #include #include namespace Ui { class DateTimePane; } struct DateTimePanePrivate; class DateTimePane : public StatusCenterPane { Q_OBJECT public: explicit DateTimePane(); ~DateTimePane(); private: Ui::DateTimePane* ui; DateTimePanePrivate* d; void forceUpdate(); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); private slots: void on_titleLabel_backButtonClicked(); void on_ntpSwitch_toggled(bool checked); void propertiesChanged(QString interfaceName, QVariantMap changedProperties, QStringList invalidatedProperties); void on_changeTimezoneButton_clicked(); // QWidget interface void on_changeDateTimeButton_clicked(); protected: void changeEvent(QEvent* event); }; #endif // DATETIMEPANE_H ================================================ FILE: plugins/TimeDatePlugin/settings/datetimepane.ui ================================================ DateTimePane 0 0 710 466 Form 0 0 0 0 0 Date and Time QFrame::NoFrame true 0 0 710 449 0 0 0 0 0 true ACTIONS 0 0 0 0 0 Change Date and Time Change Timezone 16777215 1 Qt::Horizontal Synchronise clock with the Internet NtpSwitch true TIME SYNCHRONISATION Qt::Vertical 20 40 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tSwitch QPushButton
tswitch.h
================================================ FILE: plugins/TimeDatePlugin/thedesk-timedate.conf ================================================ ================================================ FILE: plugins/TimeDatePlugin/timezonesmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "timezonesmodel.h" #include #include struct TimezonesModelPrivate { QList timezones; QList shownTimezones; }; TimezonesModel::TimezonesModel(QObject* parent) : QAbstractListModel(parent) { d = new TimezonesModelPrivate(); QDateTime now = QDateTime::currentDateTimeUtc(); for (QByteArray timezone : QTimeZone::availableTimeZoneIds()) { QTimeZone tz(timezone); if (timezone == tz.displayName(now, QTimeZone::OffsetName)) continue; // Ignore d->timezones.append(tz); } // Sort timezones std::sort(d->timezones.begin(), d->timezones.end(), [=](const QTimeZone& first, const QTimeZone& second) { if (first.offsetFromUtc(now) < second.offsetFromUtc(now)) { return true; } else if (first.offsetFromUtc(now) > second.offsetFromUtc(now)) { return false; } else { return QString(first.id()).split("/").last().localeAwareCompare(QString(second.id()).split("/").last()) < 0; } }); // Initialize the shown items search(""); } TimezonesModel::~TimezonesModel() { delete d; } int TimezonesModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return d->shownTimezones.count(); } QVariant TimezonesModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); QDateTime now = QDateTime::currentDateTimeUtc(); QTimeZone tz = d->shownTimezones.at(index.row()); switch (role) { case Qt::DisplayRole: { return QString(tz.id()).split("/").last().replace("_", " "); } case Qt::UserRole: return tz.id(); case Qt::UserRole + 1: return tz.displayName(now, QTimeZone::OffsetName); case Qt::UserRole + 2: return tz.displayName(now, QTimeZone::LongName); case Qt::UserRole + 3: if (index.row() == 0 || d->shownTimezones.at(index.row() - 1).offsetFromUtc(now) != tz.offsetFromUtc(now)) { return true; } else { return false; } } return QVariant(); } QModelIndex TimezonesModel::timezone(QTimeZone timezone) { for (int i = 0; i < d->timezones.count(); i++) { if (d->timezones.at(i) == timezone) return index(i); } return QModelIndex(); } void TimezonesModel::search(QString query) { d->shownTimezones.clear(); if (query == "") { d->shownTimezones = d->timezones; } else { QDateTime now = QDateTime::currentDateTime(); for (QTimeZone tz : d->timezones) { bool match = false; if (QString(tz.id()).contains(query, Qt::CaseInsensitive)) match = true; if (QString(tz.id()).replace("_", " ").contains(query, Qt::CaseInsensitive)) match = true; if (tz.displayName(now, QTimeZone::OffsetName).contains(query, Qt::CaseInsensitive)) match = true; if (tz.displayName(now, QTimeZone::LongName).contains(query, Qt::CaseInsensitive)) match = true; if (match) d->shownTimezones.append(tz); } } emit dataChanged(index(0), index(rowCount())); } TimezonesModelDelegate::TimezonesModelDelegate(QObject* parent) : QStyledItemDelegate(parent) { } TimezonesModelDelegate::~TimezonesModelDelegate() { } void TimezonesModelDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { QPen textPen, offsetPen; if (option.state & QStyle::State_Selected) { painter->setBrush(option.palette.brush(QPalette::Highlight)); textPen = option.palette.color(QPalette::HighlightedText); offsetPen = option.palette.color(QPalette::HighlightedText); } else if (option.state & QStyle::State_MouseOver) { QColor col = option.palette.color(QPalette::Highlight); col.setAlpha(127); painter->setBrush(col); textPen = option.palette.color(QPalette::HighlightedText); offsetPen = option.palette.color(QPalette::HighlightedText); } else { textPen = option.palette.color(QPalette::WindowText); offsetPen = option.palette.color(QPalette::Disabled, QPalette::WindowText); } painter->setPen(Qt::transparent); painter->drawRect(option.rect); painter->setBrush(Qt::transparent); QRect offsetRect = option.rect; offsetRect.setLeft(option.rect.left() + 6); offsetRect.setWidth(option.fontMetrics.horizontalAdvance(QStringLiteral("UTC+12:00"))); painter->setPen(offsetPen); painter->setFont(option.font); if (index.data(Qt::UserRole + 3).toBool()) painter->drawText(offsetRect, Qt::AlignRight | Qt::AlignVCenter, index.data(Qt::UserRole + 1).toString()); QString mainText = index.data(Qt::DisplayRole).toString(); QRect textRect = option.rect; textRect.setLeft(offsetRect.right() + 6); textRect.setWidth(option.fontMetrics.horizontalAdvance(mainText) + 1); painter->setPen(textPen); painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, mainText); QRect zoneName = option.rect; zoneName.setLeft(textRect.right() + 6); painter->setPen(offsetPen); painter->drawText(zoneName, Qt::AlignLeft | Qt::AlignVCenter, index.data(Qt::UserRole + 2).toString()); } ================================================ FILE: plugins/TimeDatePlugin/timezonesmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef TIMEZONESMODEL_H #define TIMEZONESMODEL_H #include #include struct TimezonesModelPrivate; class QTimeZone; class TimezonesModel : public QAbstractListModel { Q_OBJECT public: explicit TimezonesModel(QObject* parent = nullptr); ~TimezonesModel(); // Basic functionality: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QModelIndex timezone(QTimeZone timezone); void search(QString query); private: TimezonesModelPrivate* d; }; class TimezonesModelDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit TimezonesModelDelegate(QObject* parent = nullptr); ~TimezonesModelDelegate(); void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; #endif // TIMEZONESMODEL_H ================================================ FILE: plugins/TimeDatePlugin/translations/ar_SA.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/au_AU.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/cy.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/da.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/de.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/en_US.qm ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/es.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Dónde estás ahora? Search ================================================ FILE: plugins/TimeDatePlugin/translations/es_VE.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/id.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/nl.ts ================================================ DateTimePane Date and Time Datum en Tijd ACTIONS ACTIES Change Date and Time Datum en Tijd Wijzigen Change Timezone Tijdzone Wijzigen Synchronise clock with the Internet Klok met het Internet synchroniseren TIME SYNCHRONISATION TIJDSYNCHRONISATIE OnboardingTimeZone Time Zone Tijdzone Whereabouts are you located? We'll use this information to display the current time. Wat is je verblijfplaats? Deze informatie gebruiken we om de huidige tijd weer te geven. Search Zoeken Use the Internet to synchronise the system clock (recommended) Het Internet gebruiken om de systeemklok te synchroniseren (aangeraden) Next Volgende SetTimeDatePopover Set Date and Time Datum en Tijd Instellen What's the current date and time? Wat is de huidige datum en tijd? Apply Date and Time Datum en Tijd Toepassen SetTimezonePopover Set Timezone Tijdzone Instellen Where are you now? Waar ben je nu? Search Zoeken ================================================ FILE: plugins/TimeDatePlugin/translations/pt_BR.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/ro.ts ================================================ DateTimePane Date and Time Ora și data ACTIONS ACȚIUNI Change Date and Time Schimbați ora și data Change Timezone Schimbați fusul orar Synchronise clock with the Internet Sincronizați ceasul cu internetul TIME SYNCHRONISATION SINCRONIZAREA CEASULUI OnboardingTimeZone Time Zone Fus orar Whereabouts are you located? We'll use this information to display the current time. Unde vă aflați? Vom folosi informația aceasta pentru a vă arăta ora curentă. Search Căutare Use the Internet to synchronise the system clock (recommended) Folosiți internetul pentru a sincroniza ceasul sistemului (recomandat) Next Următorul SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Configurați fusul orar Where are you now? Unde vă situați acum? Search Căutare ================================================ FILE: plugins/TimeDatePlugin/translations/sv.ts ================================================ DateTimePane Date and Time ACTIONS Change Date and Time Change Timezone Synchronise clock with the Internet TIME SYNCHRONISATION OnboardingTimeZone Time Zone Whereabouts are you located? We'll use this information to display the current time. Search Use the Internet to synchronise the system clock (recommended) Next SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Where are you now? Search ================================================ FILE: plugins/TimeDatePlugin/translations/tr.ts ================================================ DateTimePane Date and Time Tarih ve Saat ACTIONS HAREKETLER Change Date and Time Tarih ve saati değiştir Change Timezone Saat Dilimini Değiştir Synchronise clock with the Internet Saati İnternet ile senkronize etmeye başlayın TIME SYNCHRONISATION ZAMAN SENKRONİZASYONU OnboardingTimeZone Time Zone Saat Dilimi Whereabouts are you located? We'll use this information to display the current time. Nerede bulunuyorsun? Bu bilgileri geçerli saati görüntülemek için kullanacağız. Search Ara Use the Internet to synchronise the system clock (recommended) Sistem saatini senkronize etmek için interneti kullanın (her zaman önerilir) Next Sonraki SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Saat Dilimini Ayarla Where are you now? Şu anda neredesin? Search Ara ================================================ FILE: plugins/TimeDatePlugin/translations/vi.ts ================================================ DateTimePane Date and Time Ngày và giờ ACTIONS HOẠT ĐỘNG Change Date and Time Thay đổi ngày và giờ Change Timezone Thay đổi múi giờ Synchronise clock with the Internet Đồng bộ đồng hồ với Internet TIME SYNCHRONISATION ĐỒNG BỘ ĐỒNG HỒ OnboardingTimeZone Time Zone Múi giờ Whereabouts are you located? We'll use this information to display the current time. Bạn đang ở đâu? Chúng tôi sẽ sử dụng thông tin này để đặt ngày và giờ. Search Tìm kiếm Use the Internet to synchronise the system clock (recommended) Sử dụng Internet để đồng bộ ngày và giờ (Đề xuất) Next Tiếp SetTimeDatePopover Set Date and Time What's the current date and time? Apply Date and Time SetTimezonePopover Set Timezone Đặt Múi Giờ Where are you now? Bạn đang ở đâu bây giờ? Search Tìm kiếm ================================================ FILE: plugins/TimeDatePlugin/translations/vi_VN.ts ================================================ DateTimePane Date and Time Ngày và giờ ACTIONS HOẠT ĐỘNG Change Date and Time Đổi ngày và giờ Change Timezone Đổi múi giờ Synchronise clock with the Internet Đồng bộ đồng hồ với Internet TIME SYNCHRONISATION ĐỒNG BỘ ĐỒNG HỒ OnboardingTimeZone Time Zone Múi giờ Whereabouts are you located? We'll use this information to display the current time. Bạn đang ở đâu? Chúng tôi sẽ sử dụng thông tin này để hiển thị thời gian hiện tại. Search Tìm kiếm Use the Internet to synchronise the system clock (recommended) Sử dụng Internet để đồng bộ đồng hồ hệ thống (khuyến khích) Next Tiếp SetTimeDatePopover Set Date and Time Đặt ngày và giờ What's the current date and time? Ngày và giờ hiện tại là gì? Apply Date and Time Áp dụng ngày và giờ SetTimezonePopover Set Timezone Đặt múi giờ Where are you now? Bạn đang ở đâu bây giờ? Search Tìm kiếm ================================================ FILE: plugins/UsersPlugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets DBus) find_package(libcontemporary) find_package(PolkitQt${QT_VERSION_MAJOR}-1) set(SOURCES onboarding/onboardingusers.cpp plugin.cpp settings/adduserdialog.cpp settings/changepassworddialog.cpp settings/changerealnamedialog.cpp settings/deleteuserdialog.cpp settings/lockuserdialog.cpp settings/user.cpp settings/usersmodel.cpp settings/userspane.cpp settings/usertypedialog.cpp onboarding/onboardingusers.ui settings/adduserdialog.ui settings/changepassworddialog.ui settings/changerealnamedialog.ui settings/deleteuserdialog.ui settings/lockuserdialog.ui settings/userspane.ui settings/usertypedialog.ui ) set(HEADERS onboarding/onboardingusers.h plugin.h settings/adduserdialog.h settings/changepassworddialog.h settings/changerealnamedialog.h settings/deleteuserdialog.h settings/lockuserdialog.h settings/user.h settings/usersmodel.h settings/userspane.h settings/usertypedialog.h ) set(PLUGIN_NAME users) add_plugin_td(${PLUGIN_NAME}) target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS}) cntp_defaults_file(${PLUGIN_NAME} DEFAULTS_FILE thedesk-users.conf) IF(${PolkitQt${QT_VERSION_MAJOR}-1_FOUND}) target_link_libraries(plugin-${PLUGIN_NAME} PolkitQt${QT_VERSION_MAJOR}-1::Core) target_compile_definitions(plugin-${PLUGIN_NAME} PRIVATE HAVE_POLKITQT) ENDIF() target_link_libraries(plugin-${PLUGIN_NAME} Qt::Widgets Qt::DBus libcontemporary libthedesk crypt) ================================================ FILE: plugins/UsersPlugin/Plugin.json ================================================ { "name": "User Management", "icon": "preferences-desktop-user", "uuid": "86b9b918-b77a-496d-aa1d-10819a3732a8", "vi": { "name": "Quản lý người dùng" } } ================================================ FILE: plugins/UsersPlugin/UsersPlugin.pro ================================================ QT += gui widgets dbus PKGCONFIG += polkit-qt5-1 CONFIG += link_pkgconfig LIBS += -lcrypt TEMPLATE = lib CONFIG += plugin CONFIG += c++11 # Include the-libs build tools include(/usr/share/the-libs/pri/gentranslations.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ onboarding/onboardingusers.cpp \ plugin.cpp \ settings/adduserdialog.cpp \ settings/changepassworddialog.cpp \ settings/changerealnamedialog.cpp \ settings/deleteuserdialog.cpp \ settings/lockuserdialog.cpp \ settings/user.cpp \ settings/usersmodel.cpp \ settings/userspane.cpp \ settings/usertypedialog.cpp HEADERS += \ onboarding/onboardingusers.h \ plugin.h \ settings/adduserdialog.h \ settings/changepassworddialog.h \ settings/changerealnamedialog.h \ settings/deleteuserdialog.h \ settings/lockuserdialog.h \ settings/user.h \ settings/usersmodel.h \ settings/userspane.h \ settings/usertypedialog.h DISTFILES += \ Plugin.json \ defaults.conf unix { translations.files = translations/*.qm translations.path = /usr/share/thedesk/UsersPlugin/translations defaults.files = defaults.conf defaults.path = /etc/theSuite/theDesk/UsersPlugin/ INSTALLS += translations defaults } include(../plugins.pri) FORMS += \ onboarding/onboardingusers.ui \ settings/adduserdialog.ui \ settings/changepassworddialog.ui \ settings/changerealnamedialog.ui \ settings/deleteuserdialog.ui \ settings/lockuserdialog.ui \ settings/userspane.ui \ settings/usertypedialog.ui ================================================ FILE: plugins/UsersPlugin/onboarding/onboardingusers.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "onboardingusers.h" #include "ui_onboardingusers.h" #include "settings/user.h" #include "settings/usersmodel.h" #include #include #include #include #include #include #include #include struct OnboardingUsersPrivate { bool userAdded = false; QString firstUser; }; OnboardingUsers::OnboardingUsers(QWidget* parent) : OnboardingPage(parent), ui(new Ui::OnboardingUsers) { ui->setupUi(this); d = new OnboardingUsersPrivate(); ui->addUserTitleLabel->setBackButtonShown(true); ui->titleLabel->setBackButtonShown(true); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->addUserDescriptionLabel->setText(tr("It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in.")); ui->accountTypeWidget->setVisible(false); ui->userList->setModel(new UsersModel(this)); } OnboardingUsers::~OnboardingUsers() { delete d; delete ui; } void OnboardingUsers::on_addUserTitleLabel_backButtonClicked() { if (d->userAdded) { ui->stackedWidget->setCurrentWidget(ui->allUsersPage); } else { StateManager::onboardingManager()->previousStep(); } } QCoro::Task<> OnboardingUsers::on_addUserCompleteButton_clicked() { if (ui->fullNameBox->text().isEmpty()) { tErrorFlash::flashError(ui->fullNameBox); co_return; } if (ui->usernameBox->text().isEmpty()) { tErrorFlash::flashError(ui->usernameBox); co_return; } if (ui->passwordBox->text().isEmpty()) { tErrorFlash::flashError(ui->passwordBox); co_return; } if (ui->passwordBox->text() != ui->confirmPasswordBox->text()) { tErrorFlash::flashError(ui->confirmPasswordBox); co_return; } ui->stackedWidget->setCurrentWidget(ui->spinnerPage); // Add the user account int accountType = d->userAdded ? (ui->administratorButton->isChecked() ? 1 : 0) : 1; QDBusMessage createMessage = QDBusMessage::createMethodCall("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", "CreateUser"); createMessage.setArguments({ui->usernameBox->text(), ui->fullNameBox->text(), accountType}); auto message = co_await QDBusConnection::systemBus().asyncCall(createMessage); QString error; if (message.type() == QDBusMessage::ErrorMessage) { error = message.errorMessage(); } else { UserPtr u(new User(message.arguments().constFirst().value())); // Set the user's password try { co_await u->setPassword(ui->passwordBox->text(), ui->passwordHintBox->text()); } catch (UserManipulationException& ex) { error = ex.reason(); } } if (error.isEmpty()) { if (d->userAdded) { ui->userListDescriptionLabel->setText(tr("You've added these users to your system")); } else { ui->userListDescriptionLabel->setText(tr("Thanks, %1. If other people will be using this device, you can add them now, or you can add them later.").arg(ui->fullNameBox->text())); } ui->stackedWidget->setCurrentWidget(ui->allUsersPage); d->userAdded = true; ui->accountTypeWidget->setVisible(true); ui->addUserDescriptionLabel->setText(tr("Enter the details of the next user to be added")); } else { // Bail out QTimer::singleShot(1000, [=] { ui->stackedWidget->setCurrentWidget(ui->addUserPage); tToast* toast = new tToast(); toast->setTitle(tr("Couldn't create user")); toast->setText(error); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); } } void OnboardingUsers::on_addUserButton_clicked() { resetAddUserForm(); ui->stackedWidget->setCurrentWidget(ui->addUserPage); } void OnboardingUsers::on_nextButton_clicked() { StateManager::onboardingManager()->nextStep(); } void OnboardingUsers::on_titleLabel_backButtonClicked() { StateManager::onboardingManager()->previousStep(); } QString OnboardingUsers::name() { return QStringLiteral("OnboardingUsers"); } QString OnboardingUsers::displayName() { return tr("Users"); } void OnboardingUsers::on_fullNameBox_textChanged(const QString& arg1) { ui->usernameBox->setText(arg1.split(" ").first().toLower()); } void OnboardingUsers::resetAddUserForm() { ui->fullNameBox->clear(); ui->usernameBox->clear(); ui->passwordBox->clear(); ui->confirmPasswordBox->clear(); ui->passwordHintBox->clear(); ui->administratorButton->setChecked(false); ui->standardUserButton->setChecked(true); } void OnboardingUsers::on_administratorButton_clicked() { ui->administratorButton->setChecked(true); ui->standardUserButton->setChecked(false); } void OnboardingUsers::on_standardUserButton_clicked() { ui->administratorButton->setChecked(false); ui->standardUserButton->setChecked(true); } ================================================ FILE: plugins/UsersPlugin/onboarding/onboardingusers.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ONBOARDINGUSERS_H #define ONBOARDINGUSERS_H #include #include namespace Ui { class OnboardingUsers; } struct OnboardingUsersPrivate; class OnboardingUsers : public OnboardingPage { Q_OBJECT public: explicit OnboardingUsers(QWidget* parent = nullptr); ~OnboardingUsers(); private slots: void on_addUserTitleLabel_backButtonClicked(); QCoro::Task<> on_addUserCompleteButton_clicked(); void on_addUserButton_clicked(); void on_nextButton_clicked(); void on_titleLabel_backButtonClicked(); void on_fullNameBox_textChanged(const QString& arg1); void on_administratorButton_clicked(); void on_standardUserButton_clicked(); private: Ui::OnboardingUsers* ui; OnboardingUsersPrivate* d; void resetAddUserForm(); // OnboardingPage interface public: QString name(); QString displayName(); }; #endif // ONBOARDINGUSERS_H ================================================ FILE: plugins/UsersPlugin/onboarding/onboardingusers.ui ================================================ OnboardingUsers 0 0 621 526 Form 0 0 0 0 0 0 0 0 0 0 0 Users QFrame::NoFrame true 0 -46 607 511 0 0 0 0 0 9 9 9 9 6 Add a user to this system true Full Name Username 75 true ABOUT YOU The username is generated based on the given full name. We recommend not changing it. true 16777215 1 Qt::Horizontal 9 9 9 9 6 Password Password Hint 75 true YOUR PASSWORD QLineEdit::Password Confirm Password Protect this account with a password to prevent anyone else logging into it. QLineEdit::Password If you forget your password, this will appear to help you remember. 0 0 0 0 0 16777215 1 Qt::Horizontal 9 9 9 9 6 QFrame::StyledPanel QFrame::Raised 75 true ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. true Administrator true true QFrame::StyledPanel QFrame::Raised 75 true STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. true Standard User true true true 75 true USER TYPE Qt::Vertical 20 0 16777215 1 Qt::Horizontal 6 9 9 9 9 Qt::Horizontal 40 20 Next ../../../thedesk/libthedesk/onboarding../../../thedesk/libthedesk/onboarding Qt::Vertical 20 201 Qt::Horizontal 281 20 Qt::Horizontal 281 20 Qt::Vertical 20 201 0 0 0 0 0 Users You've added these users to your system 9 16777215 1 Qt::Horizontal QFrame::NoFrame 16777215 1 Qt::Horizontal 6 9 9 9 9 Qt::Horizontal 40 20 Add Another User .. Next ../../../thedesk/libthedesk/onboarding../../../thedesk/libthedesk/onboarding tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tCircularSpinner QWidget
tcircularspinner.h
1
scrollArea fullNameBox usernameBox passwordBox confirmPasswordBox passwordHintBox administratorButton standardUserButton addUserCompleteButton userList addUserButton nextButton
================================================ FILE: plugins/UsersPlugin/plugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "plugin.h" #include "tsettings.h" #include #include #include #include #include #include #include #include #include "settings/userspane.h" #include "onboarding/onboardingusers.h" struct PluginPrivate { UsersPane* userPane; }; Plugin::Plugin() { d = new PluginPrivate(); } Plugin::~Plugin() { delete d; } void Plugin::activate() { tApplication::addPluginTranslator(CNTP_TARGET_NAME); tSettings::registerDefaults(QDir::cleanPath(qApp->applicationDirPath() + "/../plugins/UsersPlugin/thedesk-users.conf")); tSettings::registerDefaults("/usr/share/defaults/thedesk-users.conf"); d->userPane = new UsersPane(); StateManager::statusCenterManager()->addPane(d->userPane, StatusCenterManager::SystemSettings); QObject::connect(StateManager::onboardingManager(), &OnboardingManager::onboardingRequired, [=] { StateManager::onboardingManager()->addOnboardingStep(new OnboardingUsers()); }); } void Plugin::deactivate() { StateManager::statusCenterManager()->removePane(d->userPane); d->userPane->deleteLater(); tApplication::removePluginTranslator(CNTP_TARGET_NAME); } ================================================ FILE: plugins/UsersPlugin/plugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef PLUGIN_H #define PLUGIN_H #include "plugins/plugininterface.h" struct PluginPrivate; class Plugin : public QObject, public PluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "Plugin.json") Q_INTERFACES(PluginInterface) public: Plugin(); ~Plugin(); private: PluginPrivate* d; // PluginInterface interface public: void activate(); void deactivate(); }; #endif // PLUGIN_H ================================================ FILE: plugins/UsersPlugin/settings/adduserdialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "adduserdialog.h" #include "ui_adduserdialog.h" #include "user.h" #include #include #include #include #include #include struct AddUserDialogPrivate { User::PasswordMode passwordMode; }; AddUserDialog::AddUserDialog(QWidget* parent) : QWidget(parent), ui(new Ui::AddUserDialog) { ui->setupUi(this); d = new AddUserDialogPrivate(); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); ui->standardUserButton->click(); } AddUserDialog::~AddUserDialog() { delete d; delete ui; } void AddUserDialog::on_backButton_clicked() { emit done(); } void AddUserDialog::on_backButton_2_clicked() { ui->stackedWidget->setCurrentWidget(ui->detailsPage); } void AddUserDialog::on_nextButton_clicked() { if (ui->fullNameLineEdit->text().isEmpty()) { tErrorFlash::flashError(ui->fullNameLineEdit); return; } if (ui->usernameLineEdit->text().isEmpty()) { tErrorFlash::flashError(ui->fullNameLineEdit); return; } ui->stackedWidget->setCurrentWidget(ui->securityPage); } void AddUserDialog::on_fullNameLineEdit_textChanged(const QString& arg1) { ui->usernameLineEdit->setText(arg1.split(" ").first().toLower()); ui->realNameConfirmLabel->setText(arg1); } void AddUserDialog::on_usernameLineEdit_textChanged(const QString& arg1) { ui->usernameLineEdit->setText(arg1.toLower()); ui->userNameConfirmLabel->setText(arg1); } void AddUserDialog::on_backButton_3_clicked() { ui->stackedWidget->setCurrentWidget(ui->securityPage); } void AddUserDialog::on_usePasswordButton_clicked() { if (ui->passwordLineEdit->text().isEmpty()) { tErrorFlash::flashError(ui->passwordLineEdit); return; } if (ui->passwordLineEdit->text() != ui->confirmPasswordLineEdit->text()) { tErrorFlash::flashError(ui->confirmPasswordLineEdit); return; } d->passwordMode = User::SetPassword; ui->passwordConfirmLabel->setText(tr("Set Password")); ui->stackedWidget->setCurrentWidget(ui->confirmPage); } void AddUserDialog::on_askForPasswordButton_clicked() { d->passwordMode = User::SetAtLogin; ui->passwordConfirmLabel->setText(tr("Ask when logging in")); ui->stackedWidget->setCurrentWidget(ui->confirmPage); } void AddUserDialog::on_noPasswordButton_clicked() { d->passwordMode = User::NoPassword; ui->passwordConfirmLabel->setText(tr("Not Set")); ui->stackedWidget->setCurrentWidget(ui->confirmPage); } QCoro::Task<> AddUserDialog::on_performAddUserButton_clicked() { ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->stackedWidget->setCurrentWidget(ui->processingPage); // Add the user account int accountType = ui->administratorButton->isChecked() ? 1 : 0; QDBusMessage createMessage = QDBusMessage::createMethodCall("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", "CreateUser"); createMessage.setArguments({ui->usernameLineEdit->text(), ui->fullNameLineEdit->text(), accountType}); auto message = co_await QDBusConnection::systemBus().asyncCall(createMessage); QString error; if (message.type() == QDBusMessage::ErrorMessage) { error = message.errorMessage(); } else { UserPtr u(new User(message.arguments().first().value())); // Set the user's password try { if (d->passwordMode == User::SetPassword) { co_await u->setPassword(ui->passwordLineEdit->text(), ui->passwordHintLineEdit->text()); } else { co_await u->setPasswordMode(d->passwordMode); } } catch (UserManipulationException& ex) { error = ex.reason(); } } if (error.isEmpty()) { emit done(); } else { // Bail out QTimer::singleShot(1000, [=] { ui->stackedWidget->setCurrentWidget(ui->confirmPage); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); tToast* toast = new tToast(); toast->setTitle(tr("Couldn't create user")); toast->setText(error); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); } } void AddUserDialog::on_administratorButton_clicked() { ui->administratorButton->setChecked(true); ui->standardUserButton->setChecked(false); ui->userTypeConfirmLabel->setText(tr("Administrator")); } void AddUserDialog::on_standardUserButton_clicked() { ui->administratorButton->setChecked(false); ui->standardUserButton->setChecked(true); ui->userTypeConfirmLabel->setText(tr("Standard")); } ================================================ FILE: plugins/UsersPlugin/settings/adduserdialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef ADDUSERDIALOG_H #define ADDUSERDIALOG_H #include #include namespace Ui { class AddUserDialog; } struct AddUserDialogPrivate; class AddUserDialog : public QWidget { Q_OBJECT public: explicit AddUserDialog(QWidget* parent = nullptr); ~AddUserDialog(); private slots: void on_backButton_clicked(); void on_backButton_2_clicked(); void on_nextButton_clicked(); void on_fullNameLineEdit_textChanged(const QString& arg1); void on_usernameLineEdit_textChanged(const QString& arg1); void on_backButton_3_clicked(); void on_usePasswordButton_clicked(); void on_askForPasswordButton_clicked(); void on_noPasswordButton_clicked(); QCoro::Task<> on_performAddUserButton_clicked(); void on_administratorButton_clicked(); void on_standardUserButton_clicked(); signals: void done(); private: Ui::AddUserDialog* ui; AddUserDialogPrivate* d; }; #endif // ADDUSERDIALOG_H ================================================ FILE: plugins/UsersPlugin/settings/adduserdialog.ui ================================================ AddUserDialog 0 0 568 593 Form 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ../PulseaudioPane../PulseaudioPane true 0 0 15 Add User 9 0 0 ../PulseaudioPane../PulseaudioPane true 16777215 1 Qt::Horizontal 9 9 9 9 6 75 true PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. true 16777215 1 Qt::Horizontal 9 9 9 9 6 QFrame::StyledPanel QFrame::Raised 75 true ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. true Administrator true true QFrame::StyledPanel QFrame::Raised 75 true STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. true Standard User true true 75 true USER TYPE Qt::Vertical 20 262 0 0 0 0 0 0 0 0 ../PulseaudioPane../PulseaudioPane true 0 0 15 Account Security 9 16777215 1 Qt::Horizontal Protect this account with a password to prevent anyone else logging into it. 9 16777215 1 Qt::Horizontal 9 9 9 9 6 Password QLineEdit::Password Confirm Password QLineEdit::Password Password Hint If you forget your password, this will appear to help you remember. true Use this password Alternatively, choose one of the following options: 9 Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Qt::Vertical 20 40 0 0 0 0 0 0 0 0 ../PulseaudioPane../PulseaudioPane true 0 0 15 Add User 9 16777215 1 Qt::Horizontal Add this user to your system? 9 9 9 9 9 6 TextLabel Username Real Name User Type TextLabel 0 0 TextLabel Password TextLabel Add User Qt::Vertical 20 356 Qt::Vertical 20 267 Qt::Horizontal 255 20 Qt::Horizontal 254 20 Qt::Vertical 20 267 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tCircularSpinner QWidget
tcircularspinner.h
1
fullNameLineEdit usernameLineEdit administratorButton standardUserButton passwordLineEdit confirmPasswordLineEdit passwordHintLineEdit usePasswordButton askForPasswordButton noPasswordButton performAddUserButton nextButton backButton_3 backButton backButton_2
================================================ FILE: plugins/UsersPlugin/settings/changepassworddialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "changepassworddialog.h" #include "ui_changepassworddialog.h" #include #include struct ChangePasswordDialogPrivate { UserPtr user; }; ChangePasswordDialog::ChangePasswordDialog(UserPtr user, QWidget* parent) : QWidget(parent), ui(new Ui::ChangePasswordDialog) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); d = new ChangePasswordDialogPrivate(); d->user = user; ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->lockedAccountWarning->setVisible(user->isLocked()); } ChangePasswordDialog::~ChangePasswordDialog() { delete d; delete ui; } QCoro::Task<> ChangePasswordDialog::on_setPasswordButton_clicked() { if (ui->passwordLineEdit->text().isEmpty()) { tErrorFlash::flashError(ui->passwordLineEdit); co_return; } if (ui->passwordLineEdit->text() != ui->confirmPasswordLineEdit->text()) { tErrorFlash::flashError(ui->confirmPasswordLineEdit); co_return; } // Set the user's password ui->stackedWidget->setCurrentWidget(ui->processingPage); try { co_await d->user->setPassword(ui->passwordLineEdit->text(), ui->passwordHintLineEdit->text()); emit done(); } catch (UserManipulationException& ex) { // Bail out QTimer::singleShot(1000, [=] { ui->stackedWidget->setCurrentWidget(ui->setPasswordPage); tToast* toast = new tToast(); toast->setTitle(tr("Couldn't set password")); toast->setText(ex.reason()); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); } } QCoro::Task<> ChangePasswordDialog::on_askForPasswordButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->processingPage); try { co_await d->user->setPasswordMode(User::SetAtLogin); emit done(); } catch (UserManipulationException& ex) { // Bail out QTimer::singleShot(1000, [this, ex] { ui->stackedWidget->setCurrentWidget(ui->setPasswordPage); tToast* toast = new tToast(); toast->setTitle(tr("Couldn't set password policy")); toast->setText(ex.reason()); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); } } QCoro::Task<> ChangePasswordDialog::on_noPasswordButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->processingPage); try { co_await d->user->setPasswordMode(User::NoPassword); emit done(); } catch (UserManipulationException& ex) { // Bail out QTimer::singleShot(1000, [this, ex] { ui->stackedWidget->setCurrentWidget(ui->setPasswordPage); tToast* toast = new tToast(); toast->setTitle(tr("Couldn't set password policy")); toast->setText(ex.reason()); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); } } void ChangePasswordDialog::on_titleLabel_backButtonClicked() { emit done(); } ================================================ FILE: plugins/UsersPlugin/settings/changepassworddialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CHANGEPASSWORDDIALOG_H #define CHANGEPASSWORDDIALOG_H #include "user.h" #include namespace Ui { class ChangePasswordDialog; } struct ChangePasswordDialogPrivate; class ChangePasswordDialog : public QWidget { Q_OBJECT public: explicit ChangePasswordDialog(UserPtr user, QWidget* parent = nullptr); ~ChangePasswordDialog(); private slots: QCoro::Task<> on_setPasswordButton_clicked(); QCoro::Task<> on_askForPasswordButton_clicked(); QCoro::Task<> on_noPasswordButton_clicked(); void on_titleLabel_backButtonClicked(); signals: void done(); private: Ui::ChangePasswordDialog* ui; ChangePasswordDialogPrivate* d; }; #endif // CHANGEPASSWORDDIALOG_H ================================================ FILE: plugins/UsersPlugin/settings/changepassworddialog.ui ================================================ ChangePasswordDialog 0 0 400 466 Form 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Change Password 6 9 9 9 9 Set a password to protect this account. 255 255 255 255 100 0 255 100 0 255 255 255 255 255 255 255 100 0 255 100 0 255 255 255 255 255 255 255 100 0 255 100 0 231 231 231 true QFrame::StyledPanel QFrame::Raised 75 true WARNING This account is locked. Changing the password will unlock it. true 16777215 1 Qt::Horizontal 9 9 9 9 6 Password QLineEdit::Password Confirm Password QLineEdit::Password Password Hint If you forget your password, this will appear to help you remember. true Use this password Alternatively, choose one of the following options: 9 Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Qt::Vertical 20 40 Qt::Vertical 20 204 Qt::Horizontal 171 20 Qt::Horizontal 170 20 Qt::Vertical 20 203 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tCircularSpinner QWidget
tcircularspinner.h
1
passwordLineEdit confirmPasswordLineEdit passwordHintLineEdit setPasswordButton askForPasswordButton noPasswordButton
================================================ FILE: plugins/UsersPlugin/settings/changerealnamedialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "changerealnamedialog.h" #include "ui_changerealnamedialog.h" #include #include struct ChangeRealNameDialogPrivate { UserPtr user; }; ChangeRealNameDialog::ChangeRealNameDialog(UserPtr user, QWidget* parent) : QWidget(parent), ui(new Ui::ChangeRealNameDialog) { ui->setupUi(this); d = new ChangeRealNameDialogPrivate(); ui->titleLabel->setBackButtonShown(true); d->user = user; ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); } ChangeRealNameDialog::~ChangeRealNameDialog() { delete d; delete ui; } void ChangeRealNameDialog::on_setPasswordButton_clicked() { if (ui->realNameLineEdit->text().isEmpty()) { tErrorFlash::flashError(ui->realNameLineEdit); return; } //Set the user's real name ui->stackedWidget->setCurrentWidget(ui->processingPage); d->user->setRealName(ui->realNameLineEdit->text())->then([ = ] { emit done(); })->error([ = ](QString err) { //Bail out QTimer::singleShot(1000, [ = ] { ui->stackedWidget->setCurrentWidget(ui->setRealNamePage); tToast* toast = new tToast(); toast->setTitle(tr("Couldn't set real name")); toast->setText(err); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); }); } void ChangeRealNameDialog::on_titleLabel_backButtonClicked() { emit done(); } ================================================ FILE: plugins/UsersPlugin/settings/changerealnamedialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CHANGEREALNAMEDIALOG_H #define CHANGEREALNAMEDIALOG_H #include #include "user.h" namespace Ui { class ChangeRealNameDialog; } struct ChangeRealNameDialogPrivate; class ChangeRealNameDialog : public QWidget { Q_OBJECT public: explicit ChangeRealNameDialog(UserPtr user, QWidget* parent = nullptr); ~ChangeRealNameDialog(); private slots: void on_setPasswordButton_clicked(); void on_titleLabel_backButtonClicked(); signals: void done(); private: Ui::ChangeRealNameDialog* ui; ChangeRealNameDialogPrivate* d; }; #endif // CHANGEREALNAMEDIALOG_H ================================================ FILE: plugins/UsersPlugin/settings/changerealnamedialog.ui ================================================ ChangeRealNameDialog 0 0 400 474 Form 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. true 9 16777215 1 Qt::Horizontal 9 9 9 9 6 Real Name Set Real Name Qt::Vertical 20 40 Qt::Vertical 20 204 Qt::Horizontal 171 20 Qt::Horizontal 170 20 Qt::Vertical 20 203 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/UsersPlugin/settings/deleteuserdialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "deleteuserdialog.h" #include "ui_deleteuserdialog.h" #include struct DeleteUserDialogPrivate { UserPtr user; bool shouldDeleteFiles; }; DeleteUserDialog::DeleteUserDialog(UserPtr user, QWidget* parent) : QWidget(parent), ui(new Ui::DeleteUserDialog) { ui->setupUi(this); d = new DeleteUserDialogPrivate(); ui->titleLabel->setBackButtonShown(true); ui->doDeleteTitleLabel->setBackButtonShown(true); d->user = user; ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); ui->deleteButton->setProperty("type", "destructive"); } DeleteUserDialog::~DeleteUserDialog() { delete d; delete ui; } void DeleteUserDialog::on_deleteFilesButton_clicked() { d->shouldDeleteFiles = true; ui->stackedWidget->setCurrentWidget(ui->confirmPage); ui->deleteDataWarning->setVisible(true); } void DeleteUserDialog::on_keepFilesButton_clicked() { d->shouldDeleteFiles = false; ui->stackedWidget->setCurrentWidget(ui->confirmPage); ui->deleteDataWarning->setVisible(false); } void DeleteUserDialog::on_deleteButton_clicked() { ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); ui->stackedWidget->setCurrentWidget(ui->processingPage); d->user->deleteUser(d->shouldDeleteFiles)->then([ = ] { emit done(); })->error([ = ](QString err) { //Bail out QTimer::singleShot(1000, [ = ] { ui->stackedWidget->setCurrentWidget(ui->confirmPage); ui->stackedWidget->setCurrentAnimation(tStackedWidget::SlideHorizontal); tToast* toast = new tToast(); toast->setTitle(tr("Couldn't delete user")); toast->setText(err); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); }); } void DeleteUserDialog::on_titleLabel_backButtonClicked() { emit done(); } void DeleteUserDialog::on_doDeleteTitleLabel_backButtonClicked() { ui->stackedWidget->setCurrentWidget(ui->initialPage); } ================================================ FILE: plugins/UsersPlugin/settings/deleteuserdialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef DELETEUSERDIALOG_H #define DELETEUSERDIALOG_H #include #include "user.h" namespace Ui { class DeleteUserDialog; } struct DeleteUserDialogPrivate; class DeleteUserDialog : public QWidget { Q_OBJECT public: explicit DeleteUserDialog(UserPtr user, QWidget* parent = nullptr); ~DeleteUserDialog(); private slots: void on_deleteFilesButton_clicked(); void on_keepFilesButton_clicked(); void on_deleteButton_clicked(); void on_titleLabel_backButtonClicked(); void on_doDeleteTitleLabel_backButtonClicked(); signals: void done(); private: Ui::DeleteUserDialog* ui; DeleteUserDialogPrivate* d; }; #endif // DELETEUSERDIALOG_H ================================================ FILE: plugins/UsersPlugin/settings/deleteuserdialog.ui ================================================ DeleteUserDialog 0 0 400 448 Form 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Delete User What do you want to do with this user's files? true 9 Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Qt::Vertical 20 265 0 0 0 0 0 0 0 0 Delete User 6 9 9 9 9 Delete this user from this device? 0 Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files true 0 Delete User They'll be gone forever! Qt::Vertical 20 232 Qt::Vertical 20 195 Qt::Horizontal 171 20 Qt::Horizontal 170 20 Qt::Vertical 20 194 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/UsersPlugin/settings/lockuserdialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "lockuserdialog.h" #include "ui_lockuserdialog.h" #include struct LockUserDialogPrivate { UserPtr user; }; LockUserDialog::LockUserDialog(UserPtr user, QWidget* parent) : QWidget(parent), ui(new Ui::LockUserDialog) { ui->setupUi(this); d = new LockUserDialogPrivate(); d->user = user; ui->lockAccountTitleLabel->setBackButtonShown(true); ui->unlockAccountTitleLabel->setBackButtonShown(true); if (user->isLocked()) { ui->stackedWidget->setCurrentWidget(ui->unlockPage); } else { ui->stackedWidget->setCurrentWidget(ui->lockPage); } ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); } LockUserDialog::~LockUserDialog() { delete d; delete ui; } void LockUserDialog::toggleLock() { ui->stackedWidget->setCurrentWidget(ui->processingPage); d->user->setLocked(!d->user->isLocked())->then([ = ] { emit done(); })->error([ = ](QString err) { //Bail out QTimer::singleShot(1000, [ = ] { tToast* toast = new tToast(); if (d->user->isLocked()) { ui->stackedWidget->setCurrentWidget(ui->unlockPage); toast->setTitle(tr("Couldn't unlock user")); } else { ui->stackedWidget->setCurrentWidget(ui->lockPage); toast->setTitle(tr("Couldn't lock user")); } toast->setText(err); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); }); } void LockUserDialog::on_lockButton_clicked() { this->toggleLock(); } void LockUserDialog::on_unlockButton_clicked() { this->toggleLock(); } void LockUserDialog::on_lockAccountTitleLabel_backButtonClicked() { emit done(); } void LockUserDialog::on_unlockAccountTitleLabel_backButtonClicked() { emit done(); } ================================================ FILE: plugins/UsersPlugin/settings/lockuserdialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef LOCKUSERDIALOG_H #define LOCKUSERDIALOG_H #include #include "user.h" namespace Ui { class LockUserDialog; } struct LockUserDialogPrivate; class LockUserDialog : public QWidget { Q_OBJECT public: explicit LockUserDialog(UserPtr user, QWidget* parent = nullptr); ~LockUserDialog(); private slots: void on_lockButton_clicked(); void on_unlockButton_clicked(); void on_lockAccountTitleLabel_backButtonClicked(); void on_unlockAccountTitleLabel_backButtonClicked(); signals: void done(); private: Ui::LockUserDialog* ui; LockUserDialogPrivate* d; void toggleLock(); }; #endif // LOCKUSERDIALOG_H ================================================ FILE: plugins/UsersPlugin/settings/lockuserdialog.ui ================================================ LockUserDialog 0 0 400 530 Form 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Lock Account After locking this account, you won't be able to log in as this account. true 9 Lock Account Qt::Vertical 20 40 0 0 0 0 0 0 0 0 Unlock Account After unlocking this account, you'll be able to log in as this account. true 9 Unlock Account Qt::Vertical 20 382 Qt::Vertical 20 204 Qt::Horizontal 171 20 Qt::Horizontal 170 20 Qt::Vertical 20 203 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/UsersPlugin/settings/user.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "user.h" #include #include #include T_EXCEPTION_IMPL(UserManipulationException) struct UserPrivate { QDBusInterface* interface; qulonglong uid; QString realName; QString userName; QString displayName; User::UserType userType; bool locked; }; User::User(QDBusObjectPath path, QObject* parent) : QObject(parent) { d = new UserPrivate(); d->interface = new QDBusInterface("org.freedesktop.Accounts", path.path(), "org.freedesktop.Accounts.User", QDBusConnection::systemBus()); QDBusConnection::systemBus().connect("org.freedesktop.Accounts", path.path(), "org.freedesktop.Accounts.User", "Changed", this, SLOT(changed())); this->update(); } User::~User() { delete d; } QDBusObjectPath User::path() { return QDBusObjectPath(d->interface->path()); } bool User::isCurrentUser() { return d->uid == geteuid(); } bool User::isLocked() { return d->locked; } QString User::displayName() { return d->displayName; } QString User::userName() { return d->userName; } User::UserType User::userType() { return d->userType; } QCoro::Task<> User::setPassword(QString password, QString hint) { // Crypt password QRandomGenerator* rand = QRandomGenerator::global(); QByteArray characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz./"; QByteArray salt = "$6$"; for (int i = 0; i < 16; i++) { salt.append(characters.at(rand->bounded(characters.length()))); } auto cryptedBytes = crypt(password.toUtf8().constData(), salt.constData()); QString crypted = QString::fromLatin1(cryptedBytes); auto result = co_await d->interface->asyncCall("SetPassword", crypted, hint); if (result.type() == QDBusMessage::ErrorMessage) { throw UserManipulationException(result.errorMessage()); } } QCoro::Task<> User::setPasswordMode(User::PasswordMode mode) { auto result = co_await d->interface->asyncCall("SetPasswordMode", static_cast(mode)); if (result.type() == QDBusMessage::ErrorMessage) { throw UserManipulationException(result.errorMessage()); } } tPromise* User::setUserType(User::UserType type) { return new tPromise([=](std::function res, std::function rej) { QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(d->interface->asyncCall("SetAccountType", static_cast(type))); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { rej(watcher->error().message()); } else { res(); } }); }); } tPromise* User::setRealName(QString realName) { return new tPromise([=](std::function res, std::function rej) { QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(d->interface->asyncCall("SetRealName", realName)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { rej(watcher->error().message()); } else { res(); } }); }); } tPromise* User::setLocked(bool locked) { return new tPromise([=](std::function res, std::function rej) { QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(d->interface->asyncCall("SetLocked", locked)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { rej(watcher->error().message()); } else { res(); } }); }); } tPromise* User::deleteUser(bool removeFiles) { return new tPromise([=](std::function res, std::function rej) { QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", "DeleteUser"); message.setArguments({static_cast(d->uid), removeFiles}); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(QDBusConnection::systemBus().asyncCall(message)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { if (watcher->isError()) { rej(watcher->error().message()); } else { res(); } }); }); } void User::changed() { this->update(); emit dataUpdated(); } void User::update() { d->uid = d->interface->property("Uid").toULongLong(); d->realName = d->interface->property("RealName").toString(); d->userName = d->interface->property("UserName").toString(); d->locked = d->interface->property("Locked").toBool(); d->userType = static_cast(d->interface->property("AccountType").toInt()); QString displayName = d->realName; if (displayName.isEmpty()) displayName = d->userName; d->displayName = displayName; } ================================================ FILE: plugins/UsersPlugin/settings/user.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef USER_H #define USER_H #include #include #include #include #include #include struct UserPrivate; class User : public QObject { Q_OBJECT public: explicit User(QDBusObjectPath path, QObject* parent = nullptr); ~User(); enum PasswordMode { SetPassword = 0, SetAtLogin = 1, NoPassword = 2 }; enum UserType { StandardUser = 0, Administrator = 1 }; QDBusObjectPath path(); bool isCurrentUser(); bool isLocked(); QString displayName(); QString userName(); UserType userType(); signals: void dataUpdated(); public slots: QCoro::Task<> setPassword(QString password, QString hint); QCoro::Task<> setPasswordMode(PasswordMode mode); tPromise* setUserType(UserType type); tPromise* setRealName(QString realName); tPromise* setLocked(bool locked); tPromise* deleteUser(bool removeFiles); private slots: void changed(); private: UserPrivate* d; void update(); }; typedef QSharedPointer UserPtr; Q_DECLARE_METATYPE(UserPtr); class UserManipulationException : public tException { T_EXCEPTION(UserManipulationException) }; #endif // USER_H ================================================ FILE: plugins/UsersPlugin/settings/usersmodel.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "usersmodel.h" #include #include #include #include #include #include #include #include "user.h" struct UsersModelPrivate { QList users; }; UsersModel::UsersModel(QObject *parent) : QAbstractListModel(parent) { d = new UsersModelPrivate(); QDBusConnection::systemBus().connect("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", "UserAdded", this, SLOT(userAdded(QDBusObjectPath))); QDBusConnection::systemBus().connect("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", "UserDeleted", this, SLOT(userRemoved(QDBusObjectPath))); QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", "ListCachedUsers"); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(QDBusConnection::systemBus().asyncCall(msg)); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] { QDBusArgument arg = watcher->reply().arguments().first().value(); QList users; arg >> users; for (QDBusObjectPath user : users) { this->userAdded(user); } watcher->deleteLater(); emit dataChanged(index(0), index(rowCount())); }); } UsersModel::~UsersModel() { delete d; } int UsersModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return d->users.count(); } QVariant UsersModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); UserPtr u = d->users.at(index.row()); switch (role) { case Qt::DisplayRole: return u->displayName(); case Qt::UserRole: return QVariant::fromValue(u); } return QVariant(); } void UsersModel::userAdded(QDBusObjectPath path) { UserPtr u(new User(path)); connect(u.data(), &User::dataUpdated, this, [=] { int i = d->users.indexOf(u); emit dataChanged(index(i), index(i)); }); d->users.append(u); emit dataChanged(index(0), index(rowCount())); } void UsersModel::userRemoved(QDBusObjectPath path) { for (UserPtr u : d->users) { if (u->path() == path) { d->users.removeOne(u); emit dataChanged(index(0), index(rowCount())); return; } } } ================================================ FILE: plugins/UsersPlugin/settings/usersmodel.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef USERSMODEL_H #define USERSMODEL_H #include #include struct UsersModelPrivate; class UsersModel : public QAbstractListModel { Q_OBJECT public: explicit UsersModel(QObject *parent = nullptr); ~UsersModel() override; // Basic functionality: int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; private slots: void userAdded(QDBusObjectPath path); void userRemoved(QDBusObjectPath path); private: UsersModelPrivate* d; }; #endif // USERSMODEL_H ================================================ FILE: plugins/UsersPlugin/settings/userspane.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "userspane.h" #include "ui_userspane.h" #include "adduserdialog.h" #include "changepassworddialog.h" #include "changerealnamedialog.h" #include "deleteuserdialog.h" #include "lockuserdialog.h" #include "user.h" #include "usersmodel.h" #include "usertypedialog.h" #include #include #include #include #ifdef HAVE_POLKITQT #include #endif struct UsersPanePrivate { UserPtr currentUser; }; UsersPane::UsersPane() : StatusCenterPane(), ui(new Ui::UsersPane) { ui->setupUi(this); d = new UsersPanePrivate(); ui->leftPane->setParent(nullptr); ui->usernameTitleLabel->setBackButtonShown(true); ui->usernameTitleLabel->setBackButtonShown(StateManager::instance()->statusCenterManager()->isHamburgerMenuRequired()); connect(StateManager::instance()->statusCenterManager(), &StatusCenterManager::isHamburgerMenuRequiredChanged, ui->usernameTitleLabel, &tTitleLabel::setBackButtonShown); ui->usersList->setModel(new UsersModel()); connect(ui->usersList->selectionModel(), &QItemSelectionModel::currentChanged, this, [=](QModelIndex newIndex, QModelIndex oldIndex) { if (d->currentUser) { disconnect(d->currentUser.data(), &User::dataUpdated, this, &UsersPane::currentUserChanged); } if (newIndex.isValid()) { ui->stackedWidget->setCurrentWidget(ui->userPane); d->currentUser = newIndex.data(Qt::UserRole).value(); connect(d->currentUser.data(), &User::dataUpdated, this, &UsersPane::currentUserChanged); this->currentUserChanged(); } else { d->currentUser = nullptr; ui->stackedWidget->setCurrentWidget(ui->noUserPane); } }); const int contentWidth = StateManager::instance()->statusCenterManager()->preferredContentWidth(); ui->userActionsWidget->setFixedWidth(contentWidth); ui->userDangerActionsWidget->setFixedWidth(contentWidth); ui->usernameLabel->setFixedWidth(contentWidth); ui->deleteUserButton->setProperty("type", "destructive"); } UsersPane::~UsersPane() { delete d; delete ui; } void UsersPane::on_mainMenuButton_clicked() { StateManager::instance()->statusCenterManager()->returnToRootMenu(); } void UsersPane::currentUserChanged() { ui->usernameTitleLabel->setText(d->currentUser->displayName()); ui->usernameLabel->setText(tr("Username: %1").arg(d->currentUser->userName())); if (d->currentUser->isLocked()) { ui->lockUserButton->setText(tr("Unlock User")); } else { ui->lockUserButton->setText(tr("Lock User")); } } void UsersPane::on_addButton_clicked() { this->checkPolkit(false)->then([=] { AddUserDialog* d = new AddUserDialog(); tPopover* popover = new tPopover(d); popover->setPopoverWidth(SC_DPI(600)); popover->setDismissable(false); connect(d, &AddUserDialog::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, d, &AddUserDialog::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); }); } tPromise* UsersPane::checkPolkit(bool isOwnUser) { tPromise* promise = new tPromise([=](QString& error) { QString auth; if (isOwnUser) { auth = "org.freedesktop.accounts.change-own-user-data"; } else { auth = "org.freedesktop.accounts.user-administration"; } #ifdef HAVE_POLKITQT // Check Polkit authorization PolkitQt1::Authority::Result r = PolkitQt1::Authority::instance()->checkAuthorizationSync(auth, PolkitQt1::UnixProcessSubject(QApplication::applicationPid()), PolkitQt1::Authority::None); if (r == PolkitQt1::Authority::No) { error = "not-allowed"; return; } else if (r == PolkitQt1::Authority::Challenge) { PolkitQt1::Authority::Result r = PolkitQt1::Authority::instance()->checkAuthorizationSync(auth, PolkitQt1::UnixProcessSubject(QApplication::applicationPid()), PolkitQt1::Authority::AllowUserInteraction); if (r != PolkitQt1::Authority::Yes) { error = "challenge-failed"; return; } } #endif }); promise->error([=](QString err) { if (err == "not-allowed") { tToast* toast = new tToast(); toast->setTitle(tr("Unauthorized")); toast->setText(tr("Polkit does not allow you to manage users on the system.")); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); } }); return promise; } void UsersPane::on_deleteUserButton_clicked() { this->checkPolkit(false)->then([=] { DeleteUserDialog* d = new DeleteUserDialog(this->d->currentUser); tPopover* popover = new tPopover(d); popover->setPopoverWidth(SC_DPI(600)); popover->setDismissable(false); connect(d, &DeleteUserDialog::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, d, &DeleteUserDialog::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); }); } void UsersPane::on_changePasswordButton_clicked() { this->checkPolkit(d->currentUser->isCurrentUser())->then([=] { ChangePasswordDialog* d = new ChangePasswordDialog(this->d->currentUser); tPopover* popover = new tPopover(d); popover->setPopoverWidth(SC_DPI(600)); popover->setDismissable(false); connect(d, &ChangePasswordDialog::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, d, &ChangePasswordDialog::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); }); } void UsersPane::on_changeUserTypeButton_clicked() { this->checkPolkit(d->currentUser->isCurrentUser())->then([=] { UserTypeDialog* d = new UserTypeDialog(this->d->currentUser); tPopover* popover = new tPopover(d); popover->setPopoverWidth(SC_DPI(600)); popover->setDismissable(false); connect(d, &UserTypeDialog::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, d, &UserTypeDialog::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); }); } void UsersPane::on_changeRealNameButton_clicked() { this->checkPolkit(d->currentUser->isCurrentUser())->then([=] { ChangeRealNameDialog* d = new ChangeRealNameDialog(this->d->currentUser); tPopover* popover = new tPopover(d); popover->setPopoverWidth(SC_DPI(600)); popover->setDismissable(false); connect(d, &ChangeRealNameDialog::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, d, &ChangeRealNameDialog::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); }); } void UsersPane::on_lockUserButton_clicked() { this->checkPolkit(false)->then([=] { LockUserDialog* d = new LockUserDialog(this->d->currentUser); tPopover* popover = new tPopover(d); popover->setPopoverWidth(SC_DPI(600)); popover->setDismissable(false); connect(d, &LockUserDialog::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, d, &LockUserDialog::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this->window()); }); } QString UsersPane::name() { return "UsersSettings"; } QString UsersPane::displayName() { return tr("Users"); } QIcon UsersPane::icon() { return QIcon::fromTheme("preferences-desktop-user"); } QWidget* UsersPane::leftPane() { return ui->leftPane; } void UsersPane::on_usernameTitleLabel_backButtonClicked() { StateManager::instance()->statusCenterManager()->showStatusCenterHamburgerMenu(); } void UsersPane::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); emit displayNameChanged(); } } ================================================ FILE: plugins/UsersPlugin/settings/userspane.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef USERSPANE_H #define USERSPANE_H #include #include #include namespace Ui { class UsersPane; } struct UsersPanePrivate; class UsersPane : public StatusCenterPane { Q_OBJECT public: explicit UsersPane(); ~UsersPane(); private slots: void on_mainMenuButton_clicked(); void on_addButton_clicked(); void on_deleteUserButton_clicked(); void on_changePasswordButton_clicked(); void on_changeUserTypeButton_clicked(); void on_changeRealNameButton_clicked(); void on_lockUserButton_clicked(); void on_usernameTitleLabel_backButtonClicked(); private: Ui::UsersPane* ui; UsersPanePrivate* d; void changeEvent(QEvent* event); tPromise* checkPolkit(bool isOwnUser); void currentUserChanged(); // StatusCenterPane interface public: QString name(); QString displayName(); QIcon icon(); QWidget* leftPane(); }; #endif // USERSPANE_H ================================================ FILE: plugins/UsersPlugin/settings/userspane.ui ================================================ UsersPane 0 0 708 418 Form 0 0 0 0 0 0 0 0 0 0 0 0 0 ../PulseaudioPane../PulseaudioPane true 0 0 15 Users 9 0 0 New User ../PulseaudioPane../PulseaudioPane true 16777215 1 Qt::Horizontal QFrame::NoFrame 0 Qt::Vertical 20 163 20 No User Selected Qt::AlignCenter Select a user to get started Qt::AlignCenter Qt::Vertical 20 163 0 0 0 0 0 Title QFrame::NoFrame true 0 0 354 401 0 0 0 0 0 0 0 0 0 0 75 true ACTIONS 9 Change Real Name Change Password Change User Type 16777215 1 Qt::Horizontal 0 0 0 0 0 75 true DANGER 9 Lock User Delete User Username: title 9 Qt::Vertical 20 0 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: plugins/UsersPlugin/settings/usertypedialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "usertypedialog.h" #include "ui_usertypedialog.h" #include struct UserTypeDialogPrivate { UserPtr user; }; UserTypeDialog::UserTypeDialog(UserPtr user, QWidget *parent) : QWidget(parent), ui(new Ui::UserTypeDialog) { ui->setupUi(this); d = new UserTypeDialogPrivate(); d->user = user; ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); if (user->userType() == User::Administrator) { ui->administratorButton->setChecked(true); } else { ui->standardUserButton->setChecked(true); } } UserTypeDialog::~UserTypeDialog() { delete d; delete ui; } void UserTypeDialog::on_backButton_clicked() { emit done(); } void UserTypeDialog::on_standardUserButton_clicked() { //Set the user type this->setUserType(User::StandardUser); } void UserTypeDialog::on_administratorButton_clicked() { //Set the user type this->setUserType(User::Administrator); } void UserTypeDialog::setUserType(User::UserType type) { if (d->user->userType() == type) { emit done(); return; } //Set the user's account type ui->stackedWidget->setCurrentWidget(ui->processingPage); d->user->setUserType(type)->then([=] { emit done(); })->error([=](QString err) { //Bail out QTimer::singleShot(1000, [=] { ui->stackedWidget->setCurrentWidget(ui->setAccountTypePage); tToast* toast = new tToast(); toast->setTitle(tr("Couldn't set user type")); toast->setText(err); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); }); } ================================================ FILE: plugins/UsersPlugin/settings/usertypedialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2019 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef USERTYPEDIALOG_H #define USERTYPEDIALOG_H #include #include "user.h" namespace Ui { class UserTypeDialog; } struct UserTypeDialogPrivate; class UserTypeDialog : public QWidget { Q_OBJECT public: explicit UserTypeDialog(UserPtr user, QWidget *parent = nullptr); ~UserTypeDialog(); private slots: void on_backButton_clicked(); void on_standardUserButton_clicked(); void on_administratorButton_clicked(); signals: void done(); private: Ui::UserTypeDialog *ui; UserTypeDialogPrivate* d; void setUserType(User::UserType type); }; #endif // USERTYPEDIALOG_H ================================================ FILE: plugins/UsersPlugin/settings/usertypedialog.ui ================================================ UserTypeDialog 0 0 535 480 Form 6 0 0 0 0 0 0 0 0 0 0 0 0 0 ../PulseaudioPane../PulseaudioPane true 0 0 15 Change User Type 9 16777215 1 Qt::Horizontal 6 9 9 9 9 QFrame::StyledPanel QFrame::Raised 75 true ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. true Administrator true true QFrame::StyledPanel QFrame::Raised 75 true STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. true Standard User true true Qt::Vertical 20 40 Qt::Vertical 20 204 Qt::Horizontal 171 20 Qt::Horizontal 170 20 Qt::Vertical 20 203 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: plugins/UsersPlugin/thedesk-users.conf ================================================ ================================================ FILE: plugins/UsersPlugin/translations/ar_SA.ts ================================================ AddUserDialog Add User أضف مستخدم PERSONAL DETAILS تفاصيل شخصية Username اسم المستخدم Full Name الاسم الكامل The username is generated based on the given full name. We recommend not changing it. يتم إنشاء اسم المستخدم بناءً على الاسم الكامل المحدد. نوصي ا بعدم تغييره. ADMINISTRATOR مدير Administrator مدير STANDARD USER مستخدم عادي An administrator has full control over this device. They'll be able to configure systemwide settings and install software. يمتلك مدير التحكم الكامل على هذا الجهاز. يستطيعون على تغيير إعدادات النظام و تحميل وتثبيت البرامج. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. لا يمكن للمستخدم عادي تنفيذ إجراءات على مستوى المدير. لن يتمكنوا إلا من تنفيذ الإجراءات الإدارية التي تؤثر فقط على حساباهم. Standard User مستخدم عادي USER TYPE نوع المستخدم Account Security أمن حساب المستخدم Protect this account with a password to prevent anyone else logging into it. قم بحماية هذا الحساب بكلمة مرور لمنع أي شخص آخر من تسجيل الدخول إلي هذا الحساب. Password كلمة مرور Confirm Password التأكيد من كلمة المرور Password Hint ملحوظة كلمة مرور If you forget your password, this will appear to help you remember. إذا نسيت كلمة المرور الخاصة بك، فسيظهر هذه الملحوظة لكلمة مرور لمساعدتك على التذكر. Use this password استخدم كلمة المرور هذه Alternatively, choose one of the following options: غير من ذلك، تستطيع اختر أحد الخيارات التالية: Ask for a password on the next login اطلب كلمة مرور عند تسجيل الدخول التالي The first time the user logs in, we'll ask them for a password. في المرة الأولى التي يسجل فيها الحساب المستخدم الدخول، سنقوم بطلب منه كلمة مرور. Don't set a password لا تضف كلمة مرور Anyone will be able to log into this account. سيتمكن أي حساب آخر من تسجيل الدخول إلى هذا الحساب. Add this user to your system? أضف هذا المستخدم إلى نظام التشغيل؟ Real Name الاسم الحقيقي User Type نوع المستخدم Set Password ضبط كلمة مرور Ask when logging in اسأل عند تسجيل الدخول Not Set لم يتم الوضع Couldn't create user غير قادر على إنشاء حساب المستخدم Standard اساسي ChangePasswordDialog Change Password تغيير كلمة المرور Set a password to protect this account. قم بتعيين كلمة مرور لحماية هذا الحساب. WARNING تحذير This account is locked. Changing the password will unlock it. هذا الحساب مغلق. تغيير كلمة المرور إلى هذا الحساب يلغاء قفلها. Password كلمة مرور Confirm Password التأكيد من كلمة المرور Password Hint ملحوظة كلمة مرور If you forget your password, this will appear to help you remember. إذا نسيت كلمة المرور الخاصة بك، فسيظهر هذه الملحوظة لكلمة مرور لمساعدتك على التذكر. Use this password استخدم كلمة المرور هذه Alternatively, choose one of the following options: غير من ذلك، تستطيع اختر أحد الخيارات التالية: Ask for a password on the next login اطلب كلمة مرور عند تسجيل الدخول التالي The first time the user logs in, we'll ask them for a password. في المرة الأولى التي يسجل فيها الحساب المستخدم الدخول، سنقوم بطلب منه كلمة مرور. Don't set a password لا تضف كلمة مرور Anyone will be able to log into this account. سيتمكن أي حساب آخر من تسجيل الدخول إلى هذا الحساب. Couldn't set password غير قادر على تعيين كلمة المرور Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name الاسم الحقيقي Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name الاسم الكامل Username اسم المستخدم ABOUT YOU The username is generated based on the given full name. We recommend not changing it. يتم إنشاء اسم المستخدم بناءً على الاسم الكامل المحدد. نوصي ا بعدم تغييره. Password كلمة مرور Password Hint ملحوظة كلمة مرور YOUR PASSWORD Confirm Password التأكيد من كلمة المرور Protect this account with a password to prevent anyone else logging into it. قم بحماية هذا الحساب بكلمة مرور لمنع أي شخص آخر من تسجيل الدخول إلي هذا الحساب. If you forget your password, this will appear to help you remember. إذا نسيت كلمة المرور الخاصة بك، فسيظهر هذه الملحوظة لكلمة مرور لمساعدتك على التذكر. ADMINISTRATOR مدير An administrator has full control over this device. They'll be able to configure systemwide settings and install software. يمتلك مدير التحكم الكامل على هذا الجهاز. يستطيعون على تغيير إعدادات النظام و تحميل وتثبيت البرامج. Administrator مدير STANDARD USER مستخدم عادي A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. لا يمكن للمستخدم عادي تنفيذ إجراءات على مستوى المدير. لن يتمكنوا إلا من تنفيذ الإجراءات الإدارية التي تؤثر فقط على حساباهم. Standard User مستخدم عادي USER TYPE نوع المستخدم Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user غير قادر على إنشاء حساب المستخدم UserTypeDialog Change User Type ADMINISTRATOR مدير An administrator has full control over this device. They'll be able to configure systemwide settings and install software. يمتلك مدير التحكم الكامل على هذا الجهاز. يستطيعون على تغيير إعدادات النظام و تحميل وتثبيت البرامج. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. لا يمكن للمستخدم عادي تنفيذ إجراءات على مستوى المدير. لن يتمكنوا إلا من تنفيذ الإجراءات الإدارية التي تؤثر فقط على حساباهم. Administrator مدير STANDARD USER مستخدم عادي Standard User مستخدم عادي Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password تغيير كلمة المرور Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/au_AU.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/cy.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/da.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/de.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/en_GB.ts ================================================ AddUserDialog Add User Add User PERSONAL DETAILS PERSONAL DETAILS Username Username Full Name Full Name The username is generated based on the given full name. We recommend not changing it. The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR ADMINISTRATOR Administrator Administrator STANDARD USER STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User Standard User USER TYPE USER TYPE Account Security Account Security Protect this account with a password to prevent anyone else logging into it. Protect this account with a password to prevent anyone else logging into it. Password Password Confirm Password Confirm Password Password Hint Password Hint If you forget your password, this will appear to help you remember. If you forget your password, this will appear to help you remember. Use this password Use this password Alternatively, choose one of the following options: Alternatively, choose one of the following options: Ask for a password on the next login Ask for a password on the next login The first time the user logs in, we'll ask them for a password. The first time the user logs in, we'll ask them for a password. Don't set a password Don't set a password Anyone will be able to log into this account. Anyone will be able to log into this account. Add this user to your system? Add this user to your system? Real Name Real Name User Type User Type Set Password Set Password Ask when logging in Ask when logging in Not Set Not Set Couldn't create user Couldn't create user Standard Standard ChangePasswordDialog Change Password Change Password Set a password to protect this account. Set a password to protect this account. WARNING WARNING This account is locked. Changing the password will unlock it. This account is locked. Changing the password will unlock it. Password Password Confirm Password Confirm Password Password Hint Password Hint If you forget your password, this will appear to help you remember. If you forget your password, this will appear to help you remember. Use this password Use this password Alternatively, choose one of the following options: Alternatively, choose one of the following options: Ask for a password on the next login Ask for a password on the next login The first time the user logs in, we'll ask them for a password. The first time the user logs in, we'll ask them for a password. Don't set a password Don't set a password Anyone will be able to log into this account. Anyone will be able to log into this account. Couldn't set password Couldn't set password Couldn't set password policy Couldn't set password policy ChangeRealNameDialog Change Real Name Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Real Name Set Real Name Set Real Name Couldn't set real name Couldn't set real name DeleteUserDialog Delete User Delete User What do you want to do with this user's files? What do you want to do with this user's files? Delete Files Delete Files Files for this user will be removed from this device. Files for this user will be removed from this device. Keep Files Keep Files Files for this user will be kept in the same location. Files for this user will be kept in the same location. Delete this user from this device? Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! They'll be gone forever! Couldn't delete user Couldn't delete user LockUserDialog Lock Account Lock Account After locking this account, you won't be able to log in as this account. After locking this account, you won't be able to log in as this account. Unlock Account Unlock Account After unlocking this account, you'll be able to log in as this account. After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't unlock user Couldn't lock user Couldn't lock user OnboardingUsers Users Users Full Name Full Name Username Username ABOUT YOU ABOUT YOU The username is generated based on the given full name. We recommend not changing it. The username is generated based on the given full name. We recommend not changing it. Password Password Password Hint Password Hint YOUR PASSWORD YOUR PASSWORD Confirm Password Confirm Password Protect this account with a password to prevent anyone else logging into it. Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. If you forget your password, this will appear to help you remember. ADMINISTRATOR ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator Administrator STANDARD USER STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User Standard User USER TYPE USER TYPE Next Next Add Another User Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system You've added these users to your system Enter the details of the next user to be added Enter the details of the next user to be added Couldn't create user Couldn't create user UserTypeDialog Change User Type Change User Type ADMINISTRATOR ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator Administrator STANDARD USER STANDARD USER Standard User Standard User Couldn't set user type Couldn't set user type UsersPane Users Users New User New User No User Selected No User Selected Select a user to get started Select a user to get started ACTIONS ACTIONS Change Real Name Change Real Name Change Password Change Password Change User Type Change User Type DANGER DANGER Delete User Delete User Username: %1 Username: %1 Unlock User Unlock User Lock User Lock User Unauthorized Unauthorized Polkit does not allow you to manage users on the system. Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/en_US.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. The username is based on your full name. It's recommended not to change it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. An administrator has full control over this device. They can configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. A standard user can't perform systemwide actions. They can only make changes to their own account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. If you forget your password, this will help you remember it. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. If you forget your password, this will help you remember it. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Your real name appears on the login screen, on the Gateway, and anywhere else we need to differentiate users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Files for this user will be permanently deleted. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files This user's data will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. After locking this account, you won't be able to log into it again. Unlock Account After unlocking this account, you'll be able to log in as this account. After unlocking this account, you'll be able to log into it again. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. The username is based on your full name. It's recommended not to change it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. If you forget your password, this will help you remember it. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. An administrator has full control over this device. They can configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. A standard user can't perform systemwide actions. They can only make changes to their own account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. An administrator has full control over this device. They can configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. A standard user can't perform systemwide actions. They can only make changes to their own account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/es.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/es_VE.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/id_ID.ts ================================================ AddUserDialog Add User Tambahkan User PERSONAL DETAILS DATA PRIBADI Username Nama user Full Name Nama lengkap The username is generated based on the given full name. We recommend not changing it. Nama user dibuat berdasarkan nama lengkap yang Anda tulis, sebaiknya tidak perlu diganti. ADMINISTRATOR ADMINISTRATOR Administrator Administrator STANDARD USER USER BIASA An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator punya kendali penuh atas sistem. Mereka dapat mengubah konfigurasi sistem dan menginstal software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. User biasa tak dapat mengubah konfigurasi sistem. Mereka hanya dapat melakukan hal-hal administratif pada akunnya sendiri. Standard User User Biasa USER TYPE TIPE USER Account Security Keamanan Akun Protect this account with a password to prevent anyone else logging into it. Amankan akun dengan menggunakan password agar orang lain tak bisa login ke akun Anda. Password Password Confirm Password Ulangi Password Password Hint Petunjuk Password If you forget your password, this will appear to help you remember. Jika suatu saat Anda lupa password akun, ini dapat membantu Anda mengingatnya. Use this password Gunakan password ini Alternatively, choose one of the following options: Kalau tidak, pilihlah salah satu dari berikut: Ask for a password on the next login Tanyakan password saat login berikutnya The first time the user logs in, we'll ask them for a password. Saat pertama kali user login, user akan diminta mengetik password. Don't set a password Jangan gunakan password Anyone will be able to log into this account. Siapa saja dapat login ke akun ini. Add this user to your system? Tambahkan user ke sistem? Real Name Nama Lengkap User Type Tipe User Set Password Pilih Password Ask when logging in Minta saat login Not Set Tidak Diatur Couldn't create user Tidak dapat membuat user Standard Standar ChangePasswordDialog Change Password Ganti Password Set a password to protect this account. Atur password untuk mengamankan akun ini. WARNING PERINGATAN This account is locked. Changing the password will unlock it. Akun ini terkunci. Mengganti password akan membuka akun. Password Password Confirm Password Ulangi Password Password Hint Petunjuk Password If you forget your password, this will appear to help you remember. Jika suatu saat Anda lupa password akun, ini dapat membantu Anda mengingatnya. Use this password Gunakan password ini Alternatively, choose one of the following options: Kalau tidak, pilihlah salah satu dari berikut: Ask for a password on the next login Tanyakan password saat login berikutnya The first time the user logs in, we'll ask them for a password. Saat pertama kali user login, user akan diminta mengetik password. Don't set a password Jangan gunakan password Anyone will be able to log into this account. Siapa saja dapat login ke akun ini. Couldn't set password Tidak dapat mengatur password Couldn't set password policy Tidak dapat mengatur kebijakan password ChangeRealNameDialog Change Real Name Ganti Nama Lengkap Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Nama Lengkap Anda akan muncul pada login screen, pada Gerbang Aplikasi serta tempat-tempat lain dimana user dibedakan dengan jelas. Real Name Nama Lengkap Set Real Name Atur Nama Lengkap Couldn't set real name Tidak dapat mengatur nama lengkap DeleteUserDialog Delete User Hapus User What do you want to do with this user's files? Apa yang ingin Anda lakukan dengan file-file user ini? Delete Files Hapus Files for this user will be removed from this device. Semua file dari user ini akan dihapus dari sistem. Keep Files Simpan Files for this user will be kept in the same location. Semua file dari user ini akan disimpan di lokasi yang sama. Delete this user from this device? Hapus user ini dari sistem? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files Semua data terkait user ini akan hilang selamanya. Ini termasuk - Direktori Home - Pesan (mail spool) - File Sementara They'll be gone forever! User ini akan hilang selamanya! Couldn't delete user Tidak dapat menghapus user LockUserDialog Lock Account Kunci Akun After locking this account, you won't be able to log in as this account. Setelah mengunci akun ini, Anda tidak dapat login ke akun tersebut. Unlock Account Buka Akun After unlocking this account, you'll be able to log in as this account. Setelah membuka akun ini, Anda dapat kembali login ke akun tersebut. Couldn't unlock user Tidak dapat membuka user Couldn't lock user Tidak dapat mengunci user OnboardingUsers Users Full Name Nama lengkap Username Nama user ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Nama user dibuat berdasarkan nama lengkap yang Anda tulis, sebaiknya tidak perlu diganti. Password Password Password Hint Petunjuk Password YOUR PASSWORD Confirm Password Ulangi Password Protect this account with a password to prevent anyone else logging into it. Amankan akun dengan menggunakan password agar orang lain tak bisa login ke akun Anda. If you forget your password, this will appear to help you remember. Jika suatu saat Anda lupa password akun, ini dapat membantu Anda mengingatnya. ADMINISTRATOR ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator punya kendali penuh atas sistem. Mereka dapat mengubah konfigurasi sistem dan menginstal software. Administrator Administrator STANDARD USER USER BIASA A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. User biasa tak dapat mengubah konfigurasi sistem. Mereka hanya dapat melakukan hal-hal administratif pada akunnya sendiri. Standard User User Biasa USER TYPE TIPE USER Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user Tidak dapat membuat user UserTypeDialog Change User Type Ganti Tipe User ADMINISTRATOR ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator punya kendali penuh atas sistem. Mereka dapat mengubah konfigurasi sistem dan menginstal software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. User biasa tak dapat mengubah konfigurasi sistem. Mereka hanya dapat melakukan hal-hal administratif pada akunnya sendiri. Administrator Administrator STANDARD USER USER BIASA Standard User User Biasa Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Ganti Nama Lengkap Change Password Ganti Password Change User Type Ganti Tipe User DANGER Delete User Hapus User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/nl.ts ================================================  AddUserDialog Gebruiker Toevoegen Add User PERSOONSGEGEVENS PERSONAL DETAILS Gebruikersnaam Username Volledige Naam Full Name De gebruikersnaam wordt gegenereerd op basis van de gegeven volledige naam. We raden aan om hem niet te wijzigen. The username is generated based on the given full name. We recommend not changing it. BEHEERDER ADMINISTRATOR Beheerder Administrator STANDAARDGEBRUIKER STANDARD USER Beheerders hebben volledige controle over dit apparaat. Ze kunnen systeembrede instellingen aanpassen en software installeren. An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Standaardgebruikers kunnen geen systeembrede acties uitvoeren. Ze kunnen alleen administratieve acties uitvoeren die alleen van toepassing zijn op hun eigen account. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standaardgebruiker Standard User GEBRUIKERSTYPE USER TYPE Accountbeveiliging Account Security Bescherm dit account met een wachtwoord om te voorkomen dat iemand anders ermee inlogt. Protect this account with a password to prevent anyone else logging into it. Wachtwoord Password Wachtwoord Bevestigen Confirm Password Wachtwoordhint Password Hint Als je je wachtwoord vergeet, verschijnt dit om je te helpen herinneren. If you forget your password, this will appear to help you remember. Dit wachtwoord gebruiken Use this password Of kies een van de volgende opties: Alternatively, choose one of the following options: Om een wachtwoord vragen bij de volgende login Ask for a password on the next login De eerste keer dat de gebruiker inlogt, zullen we om een wachtwoord vragen. The first time the user logs in, we'll ask them for a password. Geen wachtwoord instellen Don't set a password Iedereen kan met dit account inloggen. Anyone will be able to log into this account. Deze gebruiker aan je systeem toevoegen? Add this user to your system? Echte Naam Real Name Gebruikerstype User Type Wachtwoord Instellen Set Password Vragen bij het inloggen Ask when logging in Niet Ingesteld Not Set Kon gebruiker niet aanmaken Couldn't create user Standaard Standard ChangePasswordDialog Wachtwoord Wijzigen Change Password Stel een wachtwoord in om dit account te beschermen. Set a password to protect this account. WAARSCHUWING WARNING Dit account is vergrendeld. Door het wachtwoord aan te passen wordt het ontgrendeld. This account is locked. Changing the password will unlock it. Wachtwoord Password Wachtwoord Bevestigen Confirm Password Wachtwoordhint Password Hint Als je je wachtwoord vergeet, verschijnt dit om je te helpen herinneren. If you forget your password, this will appear to help you remember. Dit wachtwoord gebruiken Use this password Of kies een van de volgende opties: Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Echte Naam Wijzigen Change Real Name Je Echte Naam veschijnt op het loginscherm, in de Gateway en op andere plekken waar we onderscheid moeten maken tussen gebruikers. Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Echte Naam Real Name Echte Naam Instellen Set Real Name Kon echte naam niet instellen Couldn't set real name DeleteUserDialog Gebruiker Verwijderen Delete User Wat wil je doen met de bestanden van deze gebruiker? What do you want to do with this user's files? Bestanden Verwijderen Delete Files De bestanden van deze gebruiker worden van dit apparaat verwijderd. Files for this user will be removed from this device. Bestanden Houden Keep Files Bestanden van deze gebruiker blijven op dezelfde locatie staan. Files for this user will be kept in the same location. Deze gebruiker van dit apparaat verwijderen? Delete this user from this device? Alle gegevens verbonden aan deze gebruiker zullen voor altijd weg zijn, bijvoorbeeld: - Home Directory - Mail Spool - Tijdelijke Bestanden Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files Ze gaan voor altijd weg! They'll be gone forever! Kon gebruiker niet verwijderen Couldn't delete user LockUserDialog Account Vergrendelen Lock Account Door dit account te vergrendelen, kun je niet inloggen met dit account. After locking this account, you won't be able to log in as this account. Account Ontgrendelen Unlock Account Door dit account te ontgrendelen, kun je weer inloggen met dit account. After unlocking this account, you'll be able to log in as this account. Kon gebruiker niet ontgrendelen Couldn't unlock user Kon gebruiker niet vergrendelen Couldn't lock user OnboardingUsers Gebruikers Users Volledige Naam Full Name Gebruikersnaam Username OVER JOU ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Volgende Next Nog een Gebruiker Toevoegen Add Another User Tijd om je te leren kennen! Apps gebruiken deze informatie om je ervaring te personaliseren en je zult dit wachtwoord gebruiken om in te loggen. It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Dankjewel, %1. Als anderen dit apparaat ook gaan gebruiken, kun je ze nu toevoegen, of later. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. Je hebt deze gebruikers aan je systeem toegevoegd You've added these users to your system Vul de gegevens in van de volgende toe te voegen gebruiker Enter the details of the next user to be added Kon gebruiker niet aanmaken Couldn't create user UserTypeDialog Gebruikerstype Wijzigen Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Kon gebruikerstype niet instellen Couldn't set user type UsersPane Gebruiker Users Nieuwe Gebruiker New User Geen Gebruiker Geselecteerd No User Selected Kies een gebruiker om te beginnen Select a user to get started ACTIES ACTIONS Echte Naam Wijzigen Change Real Name Wachtwoord Wijzigen Change Password Gebruikerstype Wijzigen Change User Type GEVAAR DANGER Gebruiker Verwijderen Delete User Gebruikersnaam: %1 Username: %1 Gebruiker Ontgrendelen Unlock User Gebruiker Vergrendelen Lock User Ongeauthoriseerd Unauthorized Polkit laat je geen gebruikers beheren op het systeem. Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/pt_BR.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/ro.ts ================================================ AddUserDialog Add User Adaugă un utilizator PERSONAL DETAILS INFORMAȚII PERSONALE Username Nume de utilizator Full Name Nume complet The username is generated based on the given full name. We recommend not changing it. Numele complet determină numele de utilizator. Nu recomandăm schimbarea acestuia. ADMINISTRATOR ADMINISTRATOR Administrator Administrator STANDARD USER Utilizator normal An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Un administrator are control complet asupra dispozitivului. Acesta va putea să schimbe setări pe întregul sistem și să instaleze software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Un utilizator normal nu poate executa acțiuni la întregul sistem. Acesta va putea să execute acțiuni administrative doar pe contul său. Standard User Utilizator normal USER TYPE TIP DE UTILIZATOR Account Security Securitatea contului Protect this account with a password to prevent anyone else logging into it. Protejați acest cont cu o parolă pentru a împiedica accesul neautorizat. Password Parola Confirm Password Confirmați parola Password Hint Indiciu de parolă If you forget your password, this will appear to help you remember. Dacă vă uitați parola, acest indiciu va apărea ca să vă ajute să vă reamintiți. Use this password Folosiți parola Alternatively, choose one of the following options: Sau, alegeți una dintre următoarele opțiuni: Ask for a password on the next login Solicită parola la următoarea autentificare The first time the user logs in, we'll ask them for a password. Prima dată când utilizatorul se autentifică, îi vom cere o parolă. Don't set a password Nu seta o parolă Anyone will be able to log into this account. Oricine va putea intra pe acest cont. Add this user to your system? Adăugați acest utilizator la sistemul dvs.? Real Name Numele real User Type Tipul utilizatorului Set Password Setează o parolă Ask when logging in Solicită la autentificare Not Set Nesetat Couldn't create user Nu s-a putut crea utilizatorul Standard Normal ChangePasswordDialog Change Password Schimbă parola Set a password to protect this account. Setați o parolă pentru a proteja acest cont. WARNING ATENȚIE This account is locked. Changing the password will unlock it. Acest cont este blocat. Schimbarea parolei îl va debloca. Password Parolă Confirm Password Confirmați parola Password Hint Indiciu de parolă If you forget your password, this will appear to help you remember. Dacă vă uitați parola, acest indiciu va apărea ca să vă ajute să vă reamintiți. Use this password Folosiți parola Alternatively, choose one of the following options: Sau, alegeți una dintre următoarele opțiuni: Ask for a password on the next login Solicită parola la următoarea autentificare The first time the user logs in, we'll ask them for a password. Prima dată când utilizatorul se autentifică, îi vom cere o parolă. Don't set a password Nu seta o parolă Anyone will be able to log into this account. Oricine va putea intra pe acest cont. Couldn't set password Nu s-a putut seta o parolă Couldn't set password policy Nu s-a putut seta o politică de parolă ChangeRealNameDialog Change Real Name Schimbă numele real Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Numele real va apărea pe ecranul de autentificare, pe portal și în orice altă locație unde trebuie să diferențiem utilizatorii. Real Name Numele real Set Real Name Setează numele real Couldn't set real name Nu s-a putut seta numele real DeleteUserDialog Delete User Șterge utilizatorul What do you want to do with this user's files? Ce doriți să faceți cu fișierele acestui utilizator? Delete Files Șterge fișierele Files for this user will be removed from this device. Fișierele utilizatorului vor fi șterse de pe dispozitiv. Keep Files Păstrează fișierele Files for this user will be kept in the same location. Fișierele utilizatorului vor fi păstrate acolo unde sunt. Delete this user from this device? Ștergeți utilizatorul de pe acest dispozitiv? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files Orice date asociate cu acest utilizator vor fi șterse permanent. Acestea cuprind: -Folderul Home -Mailurile -Fișierele temporare They'll be gone forever! Vor fi șterse permanent! Couldn't delete user Nu s-a putut șterge utilizatorul LockUserDialog Lock Account Blochează contul After locking this account, you won't be able to log in as this account. După blocarea contului, acesta nu va mai putea fi folosit pentru autentificare. Unlock Account Deblochează contul After unlocking this account, you'll be able to log in as this account. După deblocarea contului, acesta va putea fi folosit pentru autentificare. Couldn't unlock user Nu s-a putut debloca contul Couldn't lock user Nu s-a putut bloca contul OnboardingUsers Users Utilizatori Full Name Nume complet Username Nume de utilizator ABOUT YOU DESPRE DUMNEAVOASTRĂ The username is generated based on the given full name. We recommend not changing it. Numele complet determină numele de utilizator. Nu recomandăm schimbarea acestuia. Password Parolă Password Hint Indiciu de parolă YOUR PASSWORD PAROLA DUMNEAVOASTRĂ Confirm Password Confirmați parola Protect this account with a password to prevent anyone else logging into it. Protejați acest cont cu o parolă pentru a împiedica accesul neautorizat. If you forget your password, this will appear to help you remember. Dacă vă uitați parola, acest indiciu va apărea ca să vă ajute să vă reamintiți. ADMINISTRATOR ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Un administrator are control complet asupra dispozitivului. Acesta va putea să schimbe setări pe întregul sistem și să instaleze software. Administrator Administrator STANDARD USER UTILIZATOR NORMAL A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Un utilizator normal nu poate executa acțiuni la întregul sistem. Acesta va putea să execute acțiuni administrative doar pe contul său. Standard User Utilizator normal USER TYPE TIP DE UTILIZATOR Next Următorul Add Another User Adăugați un alt utilizatăr It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Haideți să ne cunoaștem. Aplicațiile vor folosi aceste informații pentru a vă personaliza experiența, iar dumneavoastră veți putea folosi parola pentru a vă autentifica. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. Mulțumim, %1. Dacă mai folosesc și alte persoane acest dispozitiv, le puteți adăuga acum sau mai târziu. You've added these users to your system Ați adăugat acești utilizatori la sistemul dumneavoastă Enter the details of the next user to be added Introduceți detaliile următorului utilizator de adăugat Couldn't create user Nu s-a putut crea utilizatorul UserTypeDialog Change User Type Schimbați tipul utilizatorului ADMINISTRATOR ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Un administrator are control complet asupra dispozitivului. Acesta va putea să schimbe setări pe întregul sistem și să instaleze software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Un utilizator normal nu poate executa acțiuni la întregul sistem. Acesta va putea să execute acțiuni administrative doar pe contul său. Administrator Administrator STANDARD USER UTILIZATOR NORMAL Standard User Utilizator normal Couldn't set user type Nu s-a putut seta tipul utilizatorului UsersPane Users Utilizatori New User Utilizator nou No User Selected Niciun utilizator selectat Select a user to get started Selectați un utilizator pentru a începe ACTIONS ACȚIUNI Change Real Name Schimbă numele real Change Password Schimbă parola Change User Type Schimbați tipul utilizatorului DANGER PERICOL Delete User Șterge utilizatorul Username: %1 Nume utilizator: %1 Unlock User Deblochează utilizatorul Lock User Blochează utilizatorul Unauthorized Neautorizat Polkit does not allow you to manage users on the system. Polkit nu vă permite să gestionați utilizatorii pe acest sistem. ================================================ FILE: plugins/UsersPlugin/translations/sv.ts ================================================ AddUserDialog Add User PERSONAL DETAILS Username Full Name The username is generated based on the given full name. We recommend not changing it. ADMINISTRATOR Administrator STANDARD USER An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Account Security Protect this account with a password to prevent anyone else logging into it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Add this user to your system? Real Name User Type Set Password Ask when logging in Not Set Couldn't create user Standard ChangePasswordDialog Change Password Set a password to protect this account. WARNING This account is locked. Changing the password will unlock it. Password Confirm Password Password Hint If you forget your password, this will appear to help you remember. Use this password Alternatively, choose one of the following options: Ask for a password on the next login The first time the user logs in, we'll ask them for a password. Don't set a password Anyone will be able to log into this account. Couldn't set password Couldn't set password policy ChangeRealNameDialog Change Real Name Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Real Name Set Real Name Couldn't set real name DeleteUserDialog Delete User What do you want to do with this user's files? Delete Files Files for this user will be removed from this device. Keep Files Files for this user will be kept in the same location. Delete this user from this device? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files They'll be gone forever! Couldn't delete user LockUserDialog Lock Account After locking this account, you won't be able to log in as this account. Unlock Account After unlocking this account, you'll be able to log in as this account. Couldn't unlock user Couldn't lock user OnboardingUsers Users Full Name Username ABOUT YOU The username is generated based on the given full name. We recommend not changing it. Password Password Hint YOUR PASSWORD Confirm Password Protect this account with a password to prevent anyone else logging into it. If you forget your password, this will appear to help you remember. ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Administrator STANDARD USER A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standard User USER TYPE Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user UserTypeDialog Change User Type ADMINISTRATOR An administrator has full control over this device. They'll be able to configure systemwide settings and install software. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Administrator STANDARD USER Standard User Couldn't set user type UsersPane Users New User No User Selected Select a user to get started ACTIONS Change Real Name Change Password Change User Type DANGER Delete User Username: %1 Unlock User Lock User Unauthorized Polkit does not allow you to manage users on the system. ================================================ FILE: plugins/UsersPlugin/translations/tr_TR.ts ================================================ AddUserDialog Add User Kullanıcı Ekle PERSONAL DETAILS KİŞİSEL DETAYLAR Username Kullanıcı adı Full Name Ad ve Soyad The username is generated based on the given full name. We recommend not changing it. Kullanıcı adı, verilen tam ada göre oluşturulur. Değiştirmemenizi öneririz. ADMINISTRATOR YÖNETİCİ Administrator Yönetici STANDARD USER STANDART KULLANICI An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Bir yönetici, bu cihaz üzerinde tam denetime sahiptir. Sistem genelindeki ayarları yapılandırabilecek ve yazılım yükleyebilecekler. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standart bir kullanıcı, sistem genelinde eylemler gerçekleştiremez. Yalnızca kendi hesaplarını etkileyen idari işlemleri gerçekleştirebilecekler. Standard User Standart kullanıcı USER TYPE KULLANICI TİPİ Account Security Hesap Güvenliği Protect this account with a password to prevent anyone else logging into it. Başkalarının oturum açmasını önlemek için bu hesabı bir parola ile koruyun. Password Şifre Confirm Password Şifreyi Onayla Password Hint Şifre ipucu If you forget your password, this will appear to help you remember. Şifrenizi unutursanız, bu hatırlamanıza yardımcı olacak şekilde görünecektir. Use this password Bu şifreyi kullanın Alternatively, choose one of the following options: Alternatif olarak, aşağıdaki seçeneklerden birini seçin: Ask for a password on the next login Bir sonraki girişte şifre isteyin The first time the user logs in, we'll ask them for a password. Kullanıcı ilk kez oturum açtığında, ondan bir parola isteyeceğiz. Don't set a password Bir şifre belirlemeyin Anyone will be able to log into this account. Bu hesaba herkes giriş yapabilecek. Add this user to your system? Bu kullanıcı sisteminize eklensin mi? Real Name Gerçek ad User Type Kullanıcı tipi Set Password Şifreyi belirle Ask when logging in Giriş yaparken sor Not Set Ayarlanmadı Couldn't create user Kullanıcı oluşturulamadı Standard Standart ChangePasswordDialog Change Password Şifre değiştir Set a password to protect this account. Bu hesabı korumak için bir şifre belirleyin. WARNING UYARI This account is locked. Changing the password will unlock it. Bu hesap kilitlendi. Şifreyi değiştirmek kilidini açacaktır. Password Şifre Confirm Password Şifreyi Onayla Password Hint Şifre ipucu If you forget your password, this will appear to help you remember. Şifrenizi unutursanız, bu hatırlamanıza yardımcı olacak şekilde görünecektir. Use this password Bu şifreyi kullanın Alternatively, choose one of the following options: Alternatif olarak, aşağıdaki seçeneklerden birini seçin: Ask for a password on the next login Bir sonraki girişte şifre isteyin The first time the user logs in, we'll ask them for a password. Kullanıcı ilk kez oturum açtığında, ondan bir parola isteyeceğiz. Don't set a password Parola belirleme Anyone will be able to log into this account. Bu hesaba herkes giriş yapabilecek. Couldn't set password Şifre ayarlanamadı Couldn't set password policy Şifre ilkesi ayarlanamadı ChangeRealNameDialog Change Real Name Gerçek ve Adı Değiştir Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Gerçek ve Adınız oturum açma ekranında, Ağ Geçidinde ve kullanıcılar arasında ayrım yapmamız gereken diğer herhangi bir yerde görünür. Real Name Gerçek ve ad Set Real Name Gerçek ve Adı Ayarla Couldn't set real name Gerçek ad belirlenemedi DeleteUserDialog Delete User Kullanıcıyı sil What do you want to do with this user's files? Bu kullanıcının dosyalarıyla ne yapmak istiyorsunuz? Delete Files Dosyaları sil Files for this user will be removed from this device. Bu kullanıcının dosyaları bu cihazdan kaldırılacaktır. Keep Files Dosyaları sakla Files for this user will be kept in the same location. Bu kullanıcının dosyaları aynı yerde tutulacak. Delete this user from this device? Bu kullanıcı bu cihazdan silinsin mi? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files Bu kullanıcıyla ilişkili tüm veriler sonsuza kadar silinecek. Bu içerir - Ana Dizin - Posta Biriktirme - Geçici dosyalar They'll be gone forever! Sonsuza dek gitmiş olacaklar! Couldn't delete user Kullanıcı silinemedi LockUserDialog Lock Account Kilitli hesap After locking this account, you won't be able to log in as this account. Bu hesabı kilitledikten sonra, bu hesapla giriş yapamayacaksınız. Unlock Account Hesabın Kilidini Aç After unlocking this account, you'll be able to log in as this account. Bu hesabın kilidini açtıktan sonra, bu hesapla giriş yapabileceksiniz. Couldn't unlock user Kullanıcının kilidi açılamadı Couldn't lock user Kullanıcı kilitlenemedi OnboardingUsers Users Kullanıcılar Full Name Ad ve Soyad Username Kullanıcı adı ABOUT YOU SENİN HAKKINDA The username is generated based on the given full name. We recommend not changing it. Kullanıcı adı, verilen tam ada göre oluşturulur. Değiştirmemenizi öneririz. Password Şifre Password Hint Şifre ipucu YOUR PASSWORD SENİN ŞİFRE Confirm Password Şifreyi Onayla Protect this account with a password to prevent anyone else logging into it. Başkalarının oturum açmasını önlemek için bu hesabı bir parola ile koruyun. If you forget your password, this will appear to help you remember. Şifrenizi unutursanız, bu hatırlamanıza yardımcı olacak şekilde görünecektir. ADMINISTRATOR YÖNETİCİ An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Bir yönetici, bu cihaz üzerinde tam denetime sahiptir. Sistem genelindeki ayarları yapılandırabilecek ve yazılım yükleyebilecekler. Administrator Yönetici STANDARD USER STANDART KULLANICI A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standart bir kullanıcı, sistem genelinde eylemler gerçekleştiremez. Yalnızca kendi hesaplarını etkileyen idari işlemleri gerçekleştirebilecekler. Standard User Standart Kullanıcı USER TYPE KULLANICI TİPİ Next Ertesi Add Another User Başka Kullanıcı Ekle It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Seni tanımanın zamanı geldi. Uygulamalar, deneyiminizi kişiselleştirmek için bu bilgileri kullanır ve oturum açmak için parolayı kullanırsınız. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. Teşekkür ederim, %1. Bu cihazı başka kişiler kullanacaksa, şimdi ekleyebilir veya daha sonra ekleyebilirsiniz. You've added these users to your system Bu kullanıcıları sisteminize eklediniz Enter the details of the next user to be added Eklenecek sonraki kullanıcının ayrıntılarını girin Couldn't create user Kullanıcı oluşturulamadı UserTypeDialog Change User Type Kullanıcı Türünü Değiştirin ADMINISTRATOR YÖNETİCİ An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Bir yönetici, bu cihaz üzerinde tam denetime sahiptir. Sistem genelindeki ayarları yapılandırabilecek ve yazılım yükleyebilecekler. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Standart bir kullanıcı, sistem genelinde eylemler gerçekleştiremez. Yalnızca kendi hesaplarını etkileyen idari işlemleri gerçekleştirebilecekler. Administrator Yönetici STANDARD USER STANDART KULLANICI Standard User Standart Kullanıcı Couldn't set user type Kullanıcı türü ayarlanamadı UsersPane Users Kullanıcılar New User Yeni kullanıcı No User Selected Kullanıcı Seçilmedi Select a user to get started Başlamak için bir kullanıcı seçin ACTIONS HAREKETLER Change Real Name Gerçek Adı Değiştir Change Password Şifre değiştir Change User Type Kullanıcı Türünü Değiştirin DANGER TEHLİKE Delete User Kullanıcıyı sil Username: %1 Kullanıcı adı: %1 Unlock User Kullanıcının Kilidini Aç Lock User Kullanıcıyı Kilitle Unauthorized Yetkisiz Polkit does not allow you to manage users on the system. Polkit, sistemdeki kullanıcıları yönetmenize izin vermez. ================================================ FILE: plugins/UsersPlugin/translations/vi_VN.ts ================================================ AddUserDialog Add User Thêm người dùng PERSONAL DETAILS CHI TIẾT CÁ NHÂN Username Tên người dùng Full Name Họ và tên The username is generated based on the given full name. We recommend not changing it. Tên người dùng bị tạo dựa trên họ và tên bạn nhập vào. Chúng tôi nên bạn không thay đổi nó. ADMINISTRATOR QUẢN TRỊ Administrator Quản trị STANDARD USER CHUẨN An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Người dùng quản trị có quyền kiểm soát toàn thiết bị này. Họ có thể đổi cài đặt cho toàn bộ hệ thống và cài đặt phần mềm. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Người dùng chuẩn không thể thực hiện hành động trên toàn hệ thống. Họ chỉ được thực hiện hành động sẽ ảnh hưởng đến tài khoản đó. Standard User Chuẩn USER TYPE KIỂU NGƯỜI DÙNG Account Security Bảo mật tài khoản Protect this account with a password to prevent anyone else logging into it. Bảo vệ tài khoản này với một mật khẩu để ngăn chặn bất cứ ai khác đăng nhập vào nó. Password Mật khẩu Confirm Password Xác nhận mật khẩu Password Hint Gợi ý mật khẩu If you forget your password, this will appear to help you remember. Nếu bạn quên mật khẩu, gợi ý này sẽ hiện lên để giúp bạn nhớ. Use this password Sử dụng mật khẩu này Alternatively, choose one of the following options: Cách khắc, chọn một tùy chọn bên dưới: Ask for a password on the next login Yêu cầu mật khẩu mới khi đăng nhập lần tiếp The first time the user logs in, we'll ask them for a password. Lần sau người dùng này đăng nhập, chúng tôi sẽ yêu cầu một mật khẩu. Don't set a password Đừng đặt mật khẩu Anyone will be able to log into this account. Bất cứ ai hết có thể đăng nhập vào tài khoản này. Add this user to your system? Thêm người dùng này vào hệ thống của bạn? Real Name Họ và tên User Type Kiểu người dùng Set Password Đặt Ask when logging in Yêu cầu lần tiếp Not Set Không đặt Couldn't create user Không thể tạo người dùng Standard Chuẩn ChangePasswordDialog Change Password Đổi mật khẩu Set a password to protect this account. Đặt một mật khẩu để bảo vệ tài khoản này. WARNING CẢNH BÁO This account is locked. Changing the password will unlock it. Tài khoản này đã bị vô hiệu. Nếu bạn đổi mật khẩu, nó sẽ bị kích hoạt. Password Mật khẩu Confirm Password Xác nhận mật khẩu Password Hint Gợi ý mật khẩu If you forget your password, this will appear to help you remember. Nếu bạn quên mật khẩu, gợi ý này sẽ hiện lên để giúp bạn nhớ. Use this password Sử dụng mật khẩu này Alternatively, choose one of the following options: Cách khắc, chọn một tùy chọn bên dưới: Ask for a password on the next login Yêu cầu mật khẩu mới khi đăng nhập lần tiếp The first time the user logs in, we'll ask them for a password. Lần sau người dùng này đăng nhập, chúng tôi sẽ yêu cầu một mật khẩu. Don't set a password Đừng đặt mật khẩu Anyone will be able to log into this account. Bất cứ ai hết có thể đăng nhập vào tài khoản này. Couldn't set password Không thể đặt mật khẩu Couldn't set password policy Không thể đặt chính sách mật khẩu ChangeRealNameDialog Change Real Name Đổi họ và tên Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. Họ và tên của bạn sẽ hiện lên trên màn hình đăng nhập, trên cửa, và bất kỳ vị trí nào khác khi chúng tôi cần phân biệt người dùng khác nhau. Real Name Họ và tên Set Real Name Đặt họ và tên Couldn't set real name Không thể đặt họ và tên DeleteUserDialog Delete User Xóa người dùng What do you want to do with this user's files? Bạn muốn làm điều gì với các tệp của người dùng này? Delete Files Xóa các tệp Files for this user will be removed from this device. Tệp của người dùng này sẽ bị xóa khỏi thiết bị này. Keep Files Giữ các tệp Files for this user will be kept in the same location. Tệp của người dùng này sẽ bị giữ lại nguyên chỗ. Delete this user from this device? Xóa người dùng khỏi thiết bị này? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files Bất kỳ dữ liệu liên quan với người dùng này sẽ bị mất mãi mãi. Dữ liệu này bao gồm - Thư mục chính - Ống thư - Tệp tạm thời They'll be gone forever! Nó sẽ bị mất mãi mãi! Couldn't delete user Không thể xóa người dùng LockUserDialog Lock Account Vô hiệu tài khoản After locking this account, you won't be able to log in as this account. Sau khi bạn vô hiệu tài khoản này, bạn không thể đăng nhập vào nó. Unlock Account Kích hoạt tài khoản After unlocking this account, you'll be able to log in as this account. Sau khi bạn kích hoạt tài khoản này, bạn có thể đăng nhập vào nó. Couldn't unlock user Không thể kích hoạt tài khoản Couldn't lock user Không thể vô hiệu tài khoản OnboardingUsers Users Người dùng Full Name Họ và tên Username Tên người dùng ABOUT YOU VỀ BẠN The username is generated based on the given full name. We recommend not changing it. Tên người dùng bị tạo dựa trên họ và tên bạn nhập vào. Chúng tôi nên bạn không thay đổi nó. Password Mật khẩu Password Hint Gợi ý mật khẩu YOUR PASSWORD MẬT KHẨU CỦA BẠN Confirm Password Xác nhận mật khẩu Protect this account with a password to prevent anyone else logging into it. Bảo vệ tài khoản này với một mật khẩu để ngăn chặn bất cứ ai khác đăng nhập vào nó. If you forget your password, this will appear to help you remember. Nếu bạn quên mật khẩu, gợi ý này sẽ hiện lên để giúp bạn nhớ. ADMINISTRATOR QUẢN TRỊ An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Người dùng quản trị có quyền kiểm soát toàn thiết bị này. Họ có thể đổi cài đặt cho toàn bộ hệ thống và cài đặt phần mềm. Administrator Quản trị STANDARD USER CHUẨN A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Người dùng chuẩn không thể thực hiện hành động trên toàn hệ thống. Họ chỉ được thực hiện hành động sẽ ảnh hưởng đến tài khoản đó. Standard User Chuẩn USER TYPE KIỂU NGƯỜI DÙNG Next Tiếp Add Another User Thêm người dùng nữa It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Đến giờ làm quen với bạn. Ứng dụng sẽ sử dụng thông tin này để cá nhân hóa trải nghiệm của bạn và bạn sẽ sử dụng mật khẩu này để đăng nhập. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. Cảm ơn %1. Nếu người khác sử dụng thiết bị này, bạn có thể thêm họ vào ngay bây giờ, hoặc bạn có thể thêm vào sau. You've added these users to your system Bạn đã thêm người dùng này vào thiết bị này Enter the details of the next user to be added Điền vào chi tiết cho người dùng tiếp theo để thêm vào Couldn't create user Không thể tạo người dùng UserTypeDialog Change User Type Đổi kiểu tài khoản ADMINISTRATOR QUẢN TRỊ An administrator has full control over this device. They'll be able to configure systemwide settings and install software. Người dùng quản trị có quyền kiểm soát toàn thiết bị này. Họ có thể đổi cài đặt cho toàn bộ hệ thống và cài đặt phần mềm. A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. Người dùng chuẩn không thể thực hiện hành động trên toàn hệ thống. Họ chỉ được thực hiện hành động sẽ ảnh hưởng đến tài khoản đó. Administrator Quản trị STANDARD USER CHUẨN Standard User Chuẩn Couldn't set user type Không thể đặt kiểu người dùng UsersPane Users Người dùng New User Người dùng mới No User Selected Chúa chọn người dùng Select a user to get started Chọn một người dùng để bắt đầu ACTIONS HOẠT ĐỘNG Change Real Name Đổi họ và tên Change Password Đổi mật khẩu Change User Type Đổi kiểu tài khoản DANGER NGUY HIỂM Delete User Xóa người dùng Username: %1 Tên người dùng: %1 Unlock User Kích hoạt người dùng Lock User Vô hiệu người dùng Unauthorized Không được phép Polkit does not allow you to manage users on the system. Polkit không có cho bạn phép quản lý người dùng trên hệ thống này. ================================================ FILE: plugins/UsersPlugin/translations/zh_CN.ts ================================================ AddUserDialog Add User 添加用户 PERSONAL DETAILS 个人信息 Username 用户名 Full Name 全面 The username is generated based on the given full name. We recommend not changing it. 用户名是根据给定的全名生成的。 我们建议不要更改它。 ADMINISTRATOR 管理员 Administrator 管理员 STANDARD USER 普通用户 An administrator has full control over this device. They'll be able to configure systemwide settings and install software. 管理员可以完全控制此设备。 他们将能够配置系统范围的设置并安装软件。 A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. 标准用户无法执行系统范围的操作。 他们将只能执行只会影响其帐户的管理操作。 Standard User 普通用户 USER TYPE 用户类型 Account Security 帐号安全 Protect this account with a password to prevent anyone else logging into it. 使用密码保护该帐户,以防止其他人登录。 Password 密码 Confirm Password 确定密码 Password Hint 密码提示 If you forget your password, this will appear to help you remember. 如果您忘记密码,这将有助于您记忆。 Use this password 使用此密码 Alternatively, choose one of the following options: 或者,选择以下选项之一: Ask for a password on the next login 在下次登录时要求输入密码 The first time the user logs in, we'll ask them for a password. 用户首次登录时,我们会要求他们输入密码。 Don't set a password 不要设置密码 Anyone will be able to log into this account. 任何人都可以登录此帐户。 Add this user to your system? 将此用户添加到您的系统? Real Name 真实名字 User Type 用户类型 Set Password 设置密码 Ask when logging in 登录时询问 Not Set 未设置 Couldn't create user 无法创建用户 Standard 标准 ChangePasswordDialog Change Password 更改密码 Set a password to protect this account. 设置密码以保护该帐户。 WARNING 警告 This account is locked. Changing the password will unlock it. 此帐户已被锁定。 更改密码将其解锁。 Password 密码 Confirm Password 确定密码 Password Hint 密码提示 If you forget your password, this will appear to help you remember. 如果您忘记密码,这将有助于您记忆。 Use this password 使用此密码 Alternatively, choose one of the following options: 或者,选择以下选项之一: Ask for a password on the next login 在下次登录时要求输入密码 The first time the user logs in, we'll ask them for a password. 用户首次登录时,我们会要求他们输入密码。 Don't set a password 不要设置密码 Anyone will be able to log into this account. 任何人都可以登录此帐户。 Couldn't set password 无法设置密码 Couldn't set password policy 无法设置密码 ChangeRealNameDialog Change Real Name 更改真实姓名 Your Real Name appears on the login screen, on the Gateway and in any other location where we need to differentiate between users. 您的真实姓名会出现在登录屏幕,网关以及我们需要区分用户的任何其他位置。 Real Name 真实名字 Set Real Name 设置真实姓名 Couldn't set real name 无法设置姓名 DeleteUserDialog Delete User 删除用户 What do you want to do with this user's files? 您要如何处理此用户的文件? Delete Files 删除文件 Files for this user will be removed from this device. 该用户的文件将从此设备中删除。 Keep Files 保留档案 Files for this user will be kept in the same location. 该用户的文件将保存在同一位置。 Delete this user from this device? 从此设备删除该用户? Any data associated with this user will be gone forever. This includes - Home Directory - Mail Spool - Temporary Files 与该用户关联的所有数据将永远消失。 这包括 -主目录 -邮件线轴 -临时文件 They'll be gone forever! 他们将永远消失! Couldn't delete user 无法删除用户 LockUserDialog Lock Account 锁定账户 After locking this account, you won't be able to log in as this account. 锁定此帐户后,您将无法使用该帐户登录。 Unlock Account 解锁账号 After unlocking this account, you'll be able to log in as this account. 锁定此帐户后,您将无法使用该帐户登录。 Couldn't unlock user 无法解锁此用户 Couldn't lock user 无法锁定此用户 OnboardingUsers Users 用户 Full Name 全面 Username 用户名 ABOUT YOU The username is generated based on the given full name. We recommend not changing it. 用户名是根据给定的全名生成的。 我们建议不要更改它。 Password 密码 Password Hint 密码提示 YOUR PASSWORD Confirm Password 确定密码 Protect this account with a password to prevent anyone else logging into it. 使用密码保护该帐户,以防止其他人登录。 If you forget your password, this will appear to help you remember. 如果您忘记密码,这将有助于您记忆。 ADMINISTRATOR 管理员 An administrator has full control over this device. They'll be able to configure systemwide settings and install software. 管理员可以完全控制此设备。 他们将能够配置系统范围的设置并安装软件。 Administrator 管理员 STANDARD USER 普通用户 A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. 标准用户无法执行系统范围的操作。 他们将只能执行只会影响其帐户的管理操作。 Standard User 普通用户 USER TYPE 用户类型 Next Add Another User It's time to get to know you. Apps will use this information to personalise your experience, and you'll use the password to log in. Thanks, %1. If other people will be using this device, you can add them now, or you can add them later. You've added these users to your system Enter the details of the next user to be added Couldn't create user 无法创建用户 UserTypeDialog Change User Type 变更使用者类型 ADMINISTRATOR 管理员 An administrator has full control over this device. They'll be able to configure systemwide settings and install software. 管理员可以完全控制此设备。 他们将能够配置系统范围的设置并安装软件。 A standard user can't perform systemwide actions. They'll only be able to perform administrative actions that only affect their account. 标准用户无法执行系统范围的操作。 他们将只能执行只会影响其帐户的管理操作。 Administrator 管理员 STANDARD USER 普通用户 Standard User 普通用户 Couldn't set user type 无法设置用户类型 UsersPane Users 用户 New User 新用户 No User Selected 未选择用户 Select a user to get started 选择一个用户开始 ACTIONS 行动 Change Real Name 更改真实姓名 Change Password 更改密码 Change User Type 变更使用者类型 DANGER 危险 Delete User 删除用户 Username: %1 用户名: %1 Unlock User 解锁用户 Lock User 锁定用户 Unauthorized 未授权 Polkit does not allow you to manage users on the system. Polkit不允许您管理系统上的用户。 ================================================ FILE: plugins/plugins.pri ================================================ QT += tdesktopenvironment CONFIG += plugin unix:!macx: { LIBS += -L$$OUT_PWD/../../libthedesk/ -lthedesk INCLUDEPATH += $$PWD/../libthedesk ../../libthedesk/plugins DEPENDPATH += $$PWD/../libthedesk target.path = $$[QT_INSTALL_LIBS]/thedesk/plugins INSTALLS += target } QMAKE_POST_LINK += $$QMAKE_COPY_DIR $$quote($$_PRO_FILE_PWD_/translations) $$shell_quote($$OUT_PWD) && \ $$QMAKE_COPY $$quote($$_PRO_FILE_PWD_/defaults.conf) $$shell_quote($$OUT_PWD) ================================================ FILE: plugins/plugins.pro ================================================ TEMPLATE = subdirs SUBDIRS += \ AccessibilityPlugin \ AudioPlugin \ BluetoothPlugin \ BrightnessPlugin \ DefaultsPlugin \ DisplayPlugin \ InputPlugin \ LocalePlugin \ NetworkPlugin \ NotificationsPlugin \ OverviewPlugin \ PowerPlugin \ ScreenshotPlugin \ ThemePlugin \ TimeDatePlugin \ UsersPlugin DISTFILES += plugins.pri ================================================ FILE: polkitagent/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) project(polkitagent VERSION 1.0.0 LANGUAGES CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network DBus) find_package(libcontemporary REQUIRED) find_package(libtdesktopenvironment REQUIRED) find_package(PolkitQt${QT_VERSION_MAJOR}-1 REQUIRED) set(SOURCES authwindow.cpp common.cpp identitypopover.cpp main.cpp polkitinterface.cpp authwindow.ui identitypopover.ui ) set(HEADERS authwindow.h common.h identitypopover.h polkitinterface.h ) add_executable(polkitagent ${SOURCES} ${HEADERS}) set_target_properties(polkitagent PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_GUI_IDENTIFIER com.vicr123.thedesk.polkitagent WIN32_EXECUTABLE TRUE CNTP_DATA_SUBDIR thedesk/td-polkitagent OUTPUT_NAME "td-polkitagent" ) cntp_init(polkitagent 20) cntp_translate(polkitagent) cntp_target_name(polkitagent "td-polkitagent") #cntp_defaults_file(polkitagent # DEFAULTS_FILE polkitagent.conf) target_link_libraries(polkitagent Qt::Widgets Qt::Network Qt::DBus PolkitQt${QT_VERSION_MAJOR}-1::Core PolkitQt${QT_VERSION_MAJOR}-1::Agent libcontemporary libtdesktopenvironment) install(TARGETS polkitagent RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} BUNDLE DESTINATION /Applications) ================================================ FILE: polkitagent/authwindow.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "authwindow.h" #include "ui_authwindow.h" #include "common.h" #include "identitypopover.h" #include #include #include #include #include struct AuthWindowPrivate { PolkitQt1::Identity::List identities; PolkitQt1::Agent::AsyncResult* callback = nullptr; PolkitQt1::Agent::Session* session = nullptr; QString cookie; }; AuthWindow::AuthWindow(QWidget* parent) : QWidget(parent), ui(new Ui::AuthWindow) { ui->setupUi(this); d = new AuthWindowPrivate(); ui->titleLabel->setBackButtonShown(true); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); QShortcut* escShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this); connect(escShortcut, &QShortcut::activated, this, [=] { ui->titleLabel->backButtonClicked(); }); } AuthWindow::~AuthWindow() { delete d; delete ui; } void AuthWindow::setMessage(QString message) { ui->messageLabel->setText(message); ui->customMessageLabel->setText(message); } void AuthWindow::setIdentities(PolkitQt1::Identity::List identities) { d->identities = identities; ui->changeIdentity->setVisible(!identities.isEmpty()); ui->customChangeIdentity->setVisible(!identities.isEmpty()); } void AuthWindow::setCallback(PolkitQt1::Agent::AsyncResult* result) { d->callback = result; } void AuthWindow::setCookie(QString cookie) { d->cookie = cookie; } void AuthWindow::showAuthWindow() { initiateSession(d->identities.first()); QTimer::singleShot(0, [=] { auto* popover = new SystemPopover(this); popover->setPopoverWidth(600); popover->setPopoverSide(tPopover::Bottom); connect(ui->titleLabel, &tTitleLabel::backButtonClicked, popover, &tPopover::dismiss); connect(this, &AuthWindow::dismiss, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, this, [=] { if (d->session) { d->session->setProperty("cancelled", true); d->session->cancel(); d->session->deleteLater(); } if (d->callback) { d->callback->setError("org.freedesktop.PolicyKit1.Error.Cancelled"); d->callback->setCompleted(); } popover->deleteLater(); }); popover->show(); }); } void AuthWindow::cancel() { ui->titleLabel->backButtonClicked(); } void AuthWindow::initiateSession(PolkitQt1::Identity identity) { if (d->session) { d->session->setProperty("cancelled", true); d->session->cancel(); d->session->deleteLater(); } ui->stackedWidget->setCurrentWidget(ui->loadingPage, false); ui->usernameLabel->setText(Common::stringForIdentity(identity)); ui->customUsernameLabel->setText(Common::stringForIdentity(identity)); d->session = new PolkitQt1::Agent::Session(d->identities.first(), d->cookie); d->session->setProperty("cancelled", false); connect(d->session, &PolkitQt1::Agent::Session::request, this, [=](QString request, bool echo) { if (request.startsWith("password:", Qt::CaseInsensitive)) { // Use the password pane ui->passwordBox->setText(""); ui->passwordBox->setEchoMode(echo ? QLineEdit::Normal : QLineEdit::Password); ui->stackedWidget->setCurrentWidget(ui->passwordPage); ui->passwordBox->setFocus(); } else { // Use the request pane ui->responseBox->setText(""); ui->responseBox->setPlaceholderText(request); ui->responseBox->setEchoMode(echo ? QLineEdit::Normal : QLineEdit::Password); ui->stackedWidget->setCurrentWidget(ui->customResponsePage); ui->responseBox->setFocus(); } }); connect(d->session, &PolkitQt1::Agent::Session::completed, this, [=](bool gainedAuthorisation) { if (!d->session->property("cancelled").toBool()) { if (gainedAuthorisation) { d->session->deleteLater(); d->session = nullptr; d->callback->setCompleted(); emit dismiss(); } else { initiateSession(identity); } } }); connect(d->session, &PolkitQt1::Agent::Session::showError, this, [=](QString error) { tToast* toast = new tToast(this); toast->setTitle(tr("Error")); toast->setText(error); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); connect(d->session, &PolkitQt1::Agent::Session::showInfo, this, [=](QString info) { tToast* toast = new tToast(this); toast->setTitle(tr("Message")); toast->setText(info); connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); toast->show(this); }); d->session->initiate(); } void AuthWindow::on_okPasswordButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->loadingPage); d->session->setResponse(ui->passwordBox->text()); } void AuthWindow::on_changeIdentity_clicked() { IdentityPopover* id = new IdentityPopover(d->identities, this); tPopover* popover = new tPopover(id); popover->setPopoverWidth(SC_DPI(400)); popover->setPopoverSide(tPopover::Bottom); connect(id, &IdentityPopover::selectIdentity, this, [=](PolkitQt1::Identity identity) { this->initiateSession(identity); }); connect(id, &IdentityPopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); connect(popover, &tPopover::dismissed, id, &IdentityPopover::deleteLater); popover->show(this); } void AuthWindow::on_customChangeIdentity_clicked() { ui->changeIdentity->click(); } void AuthWindow::on_okResponseButton_clicked() { ui->stackedWidget->setCurrentWidget(ui->loadingPage); d->session->setResponse(ui->responseBox->text()); } ================================================ FILE: polkitagent/authwindow.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef AUTHWINDOW_H #define AUTHWINDOW_H #include #include #include namespace Ui { class AuthWindow; } struct AuthWindowPrivate; class AuthWindow : public QWidget { Q_OBJECT public: explicit AuthWindow(QWidget* parent = nullptr); ~AuthWindow(); void setMessage(QString message); void setIdentities(PolkitQt1::Identity::List identities); void setCallback(PolkitQt1::Agent::AsyncResult* result); void setCookie(QString cookie); void showAuthWindow(); void cancel(); signals: void dismiss(); private slots: void on_okPasswordButton_clicked(); void on_changeIdentity_clicked(); void on_customChangeIdentity_clicked(); void on_okResponseButton_clicked(); private: Ui::AuthWindow* ui; AuthWindowPrivate* d; void initiateSession(PolkitQt1::Identity identity); }; #endif // AUTHWINDOW_H ================================================ FILE: polkitagent/authwindow.ui ================================================ AuthWindow 0 0 618 357 Form 0 0 0 0 0 PolicyKit Authentication 2 Qt::Vertical 20 141 Qt::Horizontal 280 20 Qt::Horizontal 279 20 Qt::Vertical 20 140 Qt::Vertical 20 38 Qt::Horizontal 23 20 500 0 false QFrame::NoFrame QFrame::Plain 0 0 0 15 Username .. true 20 Enter your password to confirm this action false TextLabel Qt::Vertical QSizePolicy::Fixed 20 40 0 true 0 0 0 0 30 false QLineEdit::Password Qt::AlignCenter false 0 0 ../plugins/NetworkPlugin/statusCenter/popovers../plugins/NetworkPlugin/statusCenter/popovers false true Qt::Horizontal 23 20 Qt::Vertical 20 52 Qt::Vertical 20 50 Qt::Vertical 20 49 500 0 false QFrame::NoFrame QFrame::Plain 0 0 0 15 Username Qt::NoFocus .. true false TextLabel 15 Pass the authentication challenge to confirm this action Qt::Vertical QSizePolicy::Fixed 20 40 0 true 0 0 0 0 30 false QLineEdit::Password false 0 0 Qt::NoFocus ../plugins/NetworkPlugin/statusCenter/popovers../plugins/NetworkPlugin/statusCenter/popovers false true Qt::Horizontal 29 20 Qt::Horizontal 40 20 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked() backButtonClicked()
tCircularSpinner QWidget
tcircularspinner.h
1
tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
passwordBox returnPressed() okPasswordButton click() 499 251 554 246 responseBox returnPressed() okResponseButton click() 465 254 536 256
================================================ FILE: polkitagent/common.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "common.h" #include QString Common::stringForIdentity(PolkitQt1::Identity identity) { if (identity.toUnixUserIdentity().isValid()) { return DesktopWm::displayName(identity.toUnixUserIdentity().uid()); } else { return identity.toString(); } } ================================================ FILE: polkitagent/common.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef COMMON_H #define COMMON_H #include namespace Common { QString stringForIdentity(PolkitQt1::Identity identity); } #endif // COMMON_H ================================================ FILE: polkitagent/identitypopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "identitypopover.h" #include "ui_identitypopover.h" #include "common.h" IdentityPopover::IdentityPopover(PolkitQt1::Identity::List identities, QWidget* parent) : QWidget(parent), ui(new Ui::IdentityPopover) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); for (PolkitQt1::Identity identity : identities) { QListWidgetItem* item = new QListWidgetItem(); item->setText(Common::stringForIdentity(identity)); item->setData(Qt::UserRole, identity.toString()); ui->identityList->addItem(item); } ui->identityList->setFixedWidth(SC_DPI(600)); } IdentityPopover::~IdentityPopover() { delete ui; } void IdentityPopover::on_identityList_itemActivated(QListWidgetItem* item) { emit selectIdentity(PolkitQt1::Identity::fromString(item->data(Qt::UserRole).toString())); emit done(); } void IdentityPopover::on_titleLabel_backButtonClicked() { emit done(); } ================================================ FILE: polkitagent/identitypopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef IDENTITYPOPOVER_H #define IDENTITYPOPOVER_H #include #include namespace Ui { class IdentityPopover; } class QListWidgetItem; class IdentityPopover : public QWidget { Q_OBJECT public: explicit IdentityPopover(PolkitQt1::Identity::List identities, QWidget* parent = nullptr); ~IdentityPopover(); signals: void selectIdentity(PolkitQt1::Identity identity); void done(); private slots: void on_identityList_itemActivated(QListWidgetItem* item); void on_titleLabel_backButtonClicked(); private: Ui::IdentityPopover* ui; }; #endif // IDENTITYPOPOVER_H ================================================ FILE: polkitagent/identitypopover.ui ================================================ IdentityPopover 0 0 400 300 Form 0 0 0 0 0 Identity Who do you want to authenticate as? 9 0 0 QFrame::NoFrame tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
================================================ FILE: polkitagent/main.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "polkitinterface.h" #include #include #include int main(int argc, char* argv[]) { tApplication a(argc, argv); a.setQuitOnLastWindowClosed(false); a.setApplicationShareDir("thedesk/td-polkitagent"); a.installTranslators(); PolkitInterface* interface = new PolkitInterface(); PolkitQt1::UnixSessionSubject subject(QApplication::applicationPid()); if (!interface->registerListener(subject, "/com/vicr123/PolkitAuthAgent")) { qDebug() << "Can't register authentication agent"; return 1; } return a.exec(); } ================================================ FILE: polkitagent/polkitagent.pro ================================================ QT += core gui thelib tdesktopenvironment SHARE_APP_NAME=thedesk/td-polkitagent greaterThan(QT_MAJOR_VERSION, 4): QT += widgets unix { CONFIG += link_pkgconfig PKGCONFIG += polkit-qt5-1 polkit-qt5-agent-1 } CONFIG += c++11 TARGET = td-polkitagent # Include the-libs build tools include(/usr/share/the-libs/pri/buildmaster.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ authwindow.cpp \ common.cpp \ identitypopover.cpp \ main.cpp \ overlaywindow.cpp \ polkitinterface.cpp HEADERS += \ authwindow.h \ common.h \ identitypopover.h \ overlaywindow.h \ polkitinterface.h FORMS += \ authwindow.ui \ identitypopover.ui \ overlaywindow.ui unix { target.path = $$THELIBS_INSTALL_LIB INSTALLS += target } ================================================ FILE: polkitagent/polkitinterface.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "polkitinterface.h" #include #include #include struct PolkitInterfacePrivate { QPointer authWin; }; PolkitInterface::PolkitInterface() : PolkitQt1::Agent::Listener() { d = new PolkitInterfacePrivate(); } PolkitInterface::~PolkitInterface() { delete d; } void PolkitInterface::initiateAuthentication(const QString& actionId, const QString& message, const QString& iconName, const PolkitQt1::Details& details, const QString& cookie, const PolkitQt1::Identity::List& identities, PolkitQt1::Agent::AsyncResult* result) { d->authWin = new AuthWindow(); d->authWin->setMessage(message); d->authWin->setIdentities(identities); d->authWin->setCookie(cookie); d->authWin->setCallback(result); d->authWin->showAuthWindow(); } bool PolkitInterface::initiateAuthenticationFinish() { return true; } void PolkitInterface::cancelAuthentication() { if (d->authWin) { d->authWin->cancel(); } } ================================================ FILE: polkitagent/polkitinterface.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef POLKITINTERFACE_H #define POLKITINTERFACE_H #include #include #include #include struct PolkitInterfacePrivate; class PolkitInterface : public PolkitQt1::Agent::Listener { Q_OBJECT public: explicit PolkitInterface(); ~PolkitInterface(); signals: private: PolkitInterfacePrivate* d; // Listener interface public slots: void initiateAuthentication(const QString& actionId, const QString& message, const QString& iconName, const PolkitQt1::Details& details, const QString& cookie, const PolkitQt1::Identity::List& identities, PolkitQt1::Agent::AsyncResult* result); bool initiateAuthenticationFinish(); void cancelAuthentication(); }; #endif // POLKITINTERFACE_H ================================================ FILE: polkitagent/translations/ar_SA.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/au_AU.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/cy.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/da.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/de.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/en_GB.ts ================================================ AuthWindow PolicyKit Authentication PolicyKit Authentication Enter your password to confirm this action Enter your password to confirm this action Pass the authentication challenge to confirm this action Pass the authentication challenge to confirm this action Error Error Message Message IdentityPopover Identity Identity Who do you want to authenticate as? Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/en_US.qm ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/es.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/es_VE.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/id.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/nl.ts ================================================ AuthWindow PolicyKit Authentication PolicyKit-authenticatie Enter your password to confirm this action Voer je wachtwoord in om deze actie te bevestigen Pass the authentication challenge to confirm this action Haal de authenticatie-uitdaging om deze actie te bevestigen Error Fout Message Bericht IdentityPopover Identity Identiteit Who do you want to authenticate as? Als wie wil je je authentificeren? ================================================ FILE: polkitagent/translations/pt_BR.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/ro_RO.ts ================================================ AuthWindow PolicyKit Authentication Autentificare PolicyKit Enter your password to confirm this action Indroduceți parola pentru a confirma acțiunea Pass the authentication challenge to confirm this action Treceți de testul de autentificare pentru a confirma acțiunea Error Eroare Message Mesaj IdentityPopover Identity Identitate Who do you want to authenticate as? Sub ce identitate doriți să vă autentificați? ================================================ FILE: polkitagent/translations/sv.ts ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: polkitagent/translations/tr_TR.ts ================================================ AuthWindow PolicyKit Authentication PolicyKit Kimlik Doğrulaması Enter your password to confirm this action Bu eylemi onaylamak için şifrenizi girin Pass the authentication challenge to confirm this action Bu eylemi onaylamak için kimlik doğrulama sorgulamasını geçin Error Hata Message İleti IdentityPopover Identity Kimlik Who do you want to authenticate as? Kimin kimliğini doğrulamak istiyorsunuz? ================================================ FILE: polkitagent/translations/vi_VN.ts ================================================ AuthWindow PolicyKit Authentication Xác thực PolicyKit Enter your password to confirm this action Điền mật khẩu của bạn để xác nhận hoạt động này Pass the authentication challenge to confirm this action Trả lời thử thách xác thực để xác nhận hoạt động này Error Lỗi Message Thông tin IdentityPopover Identity Danh tính Who do you want to authenticate as? Bạn muốn xác thực bằng ai? ================================================ FILE: polkitagent/translations/zh_CN.ts ================================================ AuthWindow PolicyKit Authentication 策略配置验证 Enter your password to confirm this action 输入你的密码以确定 Pass the authentication challenge to confirm this action 通过此挑战来确定此行为 Error 错误 Message 信息 IdentityPopover Identity 身份 Who do you want to authenticate as? 你想作为谁来进行认证? ================================================ FILE: polkitagent/translations/zu_ZA.qm ================================================ AuthWindow PolicyKit Authentication Enter your password to confirm this action Pass the authentication challenge to confirm this action Error Message IdentityPopover Identity Who do you want to authenticate as? ================================================ FILE: startdesk/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) project(startdesk VERSION 1.0.0 LANGUAGES CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network DBus) find_package(libcontemporary REQUIRED) find_package(libtdesktopenvironment REQUIRED) set(SOURCES crash/backtracedialog.cpp crash/backtracepopover.cpp crash/backtracewidget.cpp crash/crashwidget.cpp main.cpp splash/splashcontroller.cpp splash/splashwidget.cpp splashwindow.cpp crash/backtracedialog.ui crash/backtracepopover.ui crash/backtracewidget.ui crash/crashwidget.ui splash/splashwidget.ui splashwindow.ui resources.qrc ) set(HEADERS crash/backtracedialog.h crash/backtracepopover.h crash/backtracewidget.h crash/crashwidget.h splash/splashcontroller.h splash/splashwidget.h splashwindow.h ) add_executable(startdesk ${SOURCES} ${HEADERS}) set_target_properties(startdesk PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_GUI_IDENTIFIER com.vicr123.thedesk.startdesk WIN32_EXECUTABLE TRUE CNTP_DATA_SUBDIR startdesk) cntp_init(startdesk 20) cntp_translate(startdesk) cntp_target_name(startdesk "startdesk") #cntp_defaults_file(startdesk # DEFAULTS_FILE startdesk.conf) target_link_libraries(startdesk Qt::Widgets Qt::Network Qt::DBus libcontemporary libtdesktopenvironment libthedesk) configure_file(thedesk.desktop.in ${CMAKE_BINARY_DIR}/thedesk.desktop) configure_file(thedesk-wayland.desktop.in ${CMAKE_BINARY_DIR}/thedesk-wayland.desktop) configure_file(start-thedesk-wayland.in ${CMAKE_BINARY_DIR}/start-thedesk-wayland) install(TARGETS startdesk RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} BUNDLE DESTINATION /Applications) install(FILES wayfire-thedesk-config.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/thedesk/startdesk) install(FILES ${CMAKE_BINARY_DIR}/thedesk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/xsessions) install(FILES ${CMAKE_BINARY_DIR}/thedesk-wayland.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/wayland-sessions) install(PROGRAMS ${CMAKE_BINARY_DIR}/start-thedesk-wayland DESTINATION ${CMAKE_INSTALL_BINDIR}) ================================================ FILE: startdesk/crash/backtracedialog.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "backtracedialog.h" #include "ui_backtracedialog.h" BacktraceDialog::BacktraceDialog(QWidget *parent) : QDialog(parent), ui(new Ui::BacktraceDialog) { ui->setupUi(this); } BacktraceDialog::~BacktraceDialog() { delete ui; } ================================================ FILE: startdesk/crash/backtracedialog.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BACKTRACEDIALOG_H #define BACKTRACEDIALOG_H #include namespace Ui { class BacktraceDialog; } class BacktraceDialog : public QDialog { Q_OBJECT public: explicit BacktraceDialog(QWidget *parent = nullptr); ~BacktraceDialog(); private: Ui::BacktraceDialog *ui; }; #endif // BACKTRACEDIALOG_H ================================================ FILE: startdesk/crash/backtracedialog.ui ================================================ BacktraceDialog 0 0 645 480 Error Details 0 0 0 0 0 Error Details 0 0 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
BacktraceWidget QWidget
crash/backtracewidget.h
1
================================================ FILE: startdesk/crash/backtracepopover.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "backtracepopover.h" #include "ui_backtracepopover.h" BacktracePopover::BacktracePopover(QWidget* parent) : QWidget(parent), ui(new Ui::BacktracePopover) { ui->setupUi(this); ui->titleLabel->setBackButtonShown(true); } BacktracePopover::~BacktracePopover() { delete ui; } void BacktracePopover::on_titleLabel_backButtonClicked() { emit done(); } ================================================ FILE: startdesk/crash/backtracepopover.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BACKTRACEPOPOVER_H #define BACKTRACEPOPOVER_H #include namespace Ui { class BacktracePopover; } class BacktracePopover : public QWidget { Q_OBJECT public: explicit BacktracePopover(QWidget* parent = nullptr); ~BacktracePopover(); signals: void done(); private slots: void on_titleLabel_backButtonClicked(); private: Ui::BacktracePopover* ui; }; #endif // BACKTRACEPOPOVER_H ================================================ FILE: startdesk/crash/backtracepopover.ui ================================================ BacktracePopover 0 0 908 586 Form 0 0 0 0 0 Error Details 0 0 tTitleLabel QLabel
ttitlelabel.h
backButtonClicked()
BacktraceWidget QWidget
crash/backtracewidget.h
1
================================================ FILE: startdesk/crash/backtracewidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "backtracewidget.h" #include "ui_backtracewidget.h" #include "splash/splashcontroller.h" #include #include #include BacktraceWidget::BacktraceWidget(QWidget* parent) : QWidget(parent), ui(new Ui::BacktraceWidget) { ui->setupUi(this); ui->textBrowser->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); ui->textBrowser->setText(SplashController::instance()->lastBacktrace().join("\n")); ui->topWidget->setFixedWidth(SC_DPI(600)); } BacktraceWidget::~BacktraceWidget() { delete ui; } void BacktraceWidget::on_saveButton_clicked() { QFileDialog* dialog = new QFileDialog(this); dialog->setAcceptMode(QFileDialog::AcceptSave); dialog->setFileMode(QFileDialog::AnyFile); connect(dialog, &QFileDialog::fileSelected, this, [=](QString file) { QFile fileOutput(file); fileOutput.open(QFile::WriteOnly); fileOutput.write(ui->textBrowser->toPlainText().toUtf8()); fileOutput.close(); }); connect(dialog, &QFileDialog::finished, dialog, &QFileDialog::deleteLater); dialog->open(); } ================================================ FILE: startdesk/crash/backtracewidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef BACKTRACEWIDGET_H #define BACKTRACEWIDGET_H #include namespace Ui { class BacktraceWidget; } class BacktraceWidget : public QWidget { Q_OBJECT public: explicit BacktraceWidget(QWidget* parent = nullptr); ~BacktraceWidget(); private slots: void on_saveButton_clicked(); private: Ui::BacktraceWidget* ui; }; #endif // BACKTRACEWIDGET_H ================================================ FILE: startdesk/crash/backtracewidget.ui ================================================ BacktraceWidget 0 0 731 424 Form 0 0 0 0 0 9 9 9 9 Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! true 75 true ACTIONS Save to file 16777215 1 Qt::Horizontal QFrame::NoFrame ================================================ FILE: startdesk/crash/crashwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "crashwidget.h" #include "ui_crashwidget.h" #include "backtracepopover.h" #include "splash/splashcontroller.h" #include #include CrashWidget::CrashWidget(QWidget* parent) : QWidget(parent), ui(new Ui::CrashWidget) { ui->setupUi(this); ui->iconLabel->setPixmap(QIcon(":/icons/crash.svg").pixmap(SC_DPI_T(QSize(128, 128), QSize))); connect(SplashController::instance(), &SplashController::crash, this, [=] { ui->descriptionLabel->setText(tr("theDesk had a problem and has stopped working.")); }); connect(SplashController::instance(), &SplashController::startFail, this, [=] { ui->descriptionLabel->setText(tr("theDesk couldn't start because of a problem.")); }); } CrashWidget::~CrashWidget() { delete ui; } void CrashWidget::on_logOutButton_clicked() { SplashController::instance()->logout(); } void CrashWidget::on_relaunchButton_clicked() { SplashController::instance()->startDE(); } void CrashWidget::on_detailsButton_clicked() { BacktracePopover* bt = new BacktracePopover(); tPopover* popover = new tPopover(bt); popover->setPopoverWidth(SC_DPI(600)); popover->setPopoverSide(tPopover::Bottom); connect(bt, &BacktracePopover::done, popover, &tPopover::dismiss); connect(popover, &tPopover::dismissed, bt, &BacktracePopover::deleteLater); connect(popover, &tPopover::dismissed, popover, &tPopover::deleteLater); popover->show(this); } ================================================ FILE: startdesk/crash/crashwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef CRASHWIDGET_H #define CRASHWIDGET_H #include namespace Ui { class CrashWidget; } class CrashWidget : public QWidget { Q_OBJECT public: explicit CrashWidget(QWidget* parent = nullptr); ~CrashWidget(); private slots: void on_logOutButton_clicked(); void on_relaunchButton_clicked(); void on_detailsButton_clicked(); private: Ui::CrashWidget* ui; }; #endif // CRASHWIDGET_H ================================================ FILE: startdesk/crash/crashwidget.ui ================================================ CrashWidget 0 0 596 435 Form Qt::Vertical 20 155 20 Oh, Bonkers! Qt::AlignCenter false Qt::AlignCenter theDesk had a problem and has stopped working. Qt::AlignCenter Qt::Horizontal 40 20 Relaunch theDesk .. Log Out .. Qt::Horizontal 40 20 Qt::Vertical 20 155 Qt::Horizontal 40 20 View Details ================================================ FILE: startdesk/main.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "splash/splashcontroller.h" #include #include #include #include #include #include #include int main(int argc, char* argv[]) { // Put environment variables qputenv("QT_QPA_PLATFORMTHEME", "thedesk-platform"); // Turn off flatpak forwarding for ourselves qputenv("TD_PLATFORM_NO_FLATPAK_FORWARD", "1"); QString oldPath = qgetenv("PATH"); qputenv("PATH", ("/usr/bin/thedesk-xdg-utils:" + oldPath).toUtf8()); tApplication a(argc, argv); a.setApplicationName("theDesk"); a.setOrganizationName("theSuite"); a.setApplicationDisplayName("theDesk"); a.setQuitOnLastWindowClosed(false); qunsetenv("TD_PLATFORM_NO_FLATPAK_FORWARD"); tSettings::registerDefaults(a.applicationDirPath() + "/defaults.conf"); tSettings::registerDefaults("/etc/theSuite/theDesk/defaults.conf"); tSettings* settings = new tSettings(); // Check for initialisation script if (settings->value("Session/UseInitializationScript").toBool()) { QProcess process; process.start(settings->value("Session/InitializationScript").toString(), QStringList()); process.waitForFinished(); } // Ask systemd to import environment variables QStringList systemdEnvironment = {QStringLiteral("XDG_CURRENT_DESKTOP=%1").arg(qEnvironmentVariable("XDG_CURRENT_DESKTOP")), QStringLiteral("QT_QPA_PLATFORMTHEME=%1").arg(qEnvironmentVariable("QT_QPA_PLATFORMTHEME")), QStringLiteral("PATH=%1").arg(qEnvironmentVariable("PATH"))}; if (qEnvironmentVariableIsSet("DISPLAY")) { systemdEnvironment.append(QStringLiteral("DISPLAY=%1").arg(qEnvironmentVariable("DISPLAY"))); } if (qEnvironmentVariableIsSet("WAYLAND_DISPLAY")) { systemdEnvironment.append(QStringLiteral("WAYLAND_DISPLAY=%1").arg(qEnvironmentVariable("WAYLAND_DISPLAY"))); } QDBusMessage setEnvironmentMessage = QDBusMessage::createMethodCall("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "SetEnvironment"); setEnvironmentMessage.setArguments({systemdEnvironment}); QDBusConnection::sessionBus().asyncCall(setEnvironmentMessage); // Restart the portal so it picks up our new environment variables QDBusMessage restartPortalMessage = QDBusMessage::createMethodCall("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "RestartUnit"); restartPortalMessage.setArguments({QStringLiteral("xdg-desktop-portal.service"), QStringLiteral("replace")}); QDBusConnection::sessionBus().asyncCall(restartPortalMessage); SplashController::instance()->startDE(); return a.exec(); } ================================================ FILE: startdesk/resources.qrc ================================================ icons/crash.svg ================================================ FILE: startdesk/splash/splashcontroller.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "splashcontroller.h" #include "crash/backtracedialog.h" #include "splashwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct SplashControllerPrivate { SplashController* instance = nullptr; SplashWindow* splash; QProcess* process = nullptr; QProcess* wm = nullptr; QLocalServer* server; QPointer socket; QString serverPath; QByteArray buffer; tSettings* settings; bool autostartDone = false; bool startedSuccessfully = false; bool performingAutoRecovery = false; QElapsedTimer timeSinceSuccessfulStart; QStringList currentBacktrace; QStringList lastBacktrace; }; SplashControllerPrivate* SplashController::d = new SplashControllerPrivate(); SplashController::SplashController(QObject* parent) : QObject(parent) { d->settings = new tSettings(); this->initSession(); } void SplashController::socketDataAvailable() { d->buffer.append(d->socket->readAll()); int bracket = 0; for (int i = 0; i < d->buffer.count(); i++) { if (d->buffer.at(i) == '{') { bracket++; } else if (d->buffer.at(i) == '}') { bracket--; } else if (bracket == 0) { // Error d->buffer = d->buffer.mid(i + 1); i = -1; } if (bracket == 0) { QByteArray data = d->buffer.left(i + 1); d->buffer = d->buffer.mid(i + 1); i = -1; QJsonDocument doc = QJsonDocument::fromJson(data); QJsonObject obj = doc.object(); if (obj.contains("type")) { QString type = obj.value("type").toString(); if (type == "hideSplash") { emit hideSplashes(); d->startedSuccessfully = true; d->timeSinceSuccessfulStart.restart(); if (d->performingAutoRecovery) { tNotification* notification = new tNotification(); notification->setAppIcon("com.vicr123.thedesk"); notification->setAppName("theDesk"); notification->setSummary(tr("Oh, Bonkers!")); notification->setText(tr("theDesk had a problem and was restarted.")); notification->setTransient(true); notification->insertAction("details", tr("View Details")); notification->post(); connect(notification, &tNotification::actionClicked, this, [=](QString key) { if (key == "details") { BacktraceDialog* dialog = new BacktraceDialog(); connect(dialog, &BacktraceDialog::finished, dialog, &BacktraceDialog::deleteLater); dialog->show(); } }); } } else if (type == "showSplash") { emit starting(); } else if (type == "autoStart") { // Run Autostart apps this->runAutostart(); } else if (type == "question") { emit question(obj.value("title").toString(), obj.value("question").toString()); } } } } } SplashController::~SplashController() { } SplashController* SplashController::instance() { if (!d->instance) { d->instance = new SplashController(); d->splash = new SplashWindow(); d->splash->showFullScreen(); } return d->instance; } void SplashController::initSession() { // Start the server d->serverPath = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation) + "/startdesk-" + QString::number(QRandomGenerator::system()->generate64()); QLocalServer::removeServer(d->serverPath); d->server = new QLocalServer(this); connect(d->server, &QLocalServer::newConnection, this, [=] { d->socket = d->server->nextPendingConnection(); connect(d->socket, &QLocalSocket::readyRead, this, &SplashController::socketDataAvailable); connect(d->socket, &QLocalSocket::disconnected, d->socket, &QLocalSocket::deleteLater); d->server->close(); }); // Start the window manager this->startWM(); } void SplashController::runAutostart() { if (d->autostartDone) return; if (qEnvironmentVariable("THEDESK_NO_AUTOSTART") == "true") return; // Autostart the Polkit agent QString pkPath = QStringLiteral(SYSTEM_LIBRARY_DIRECTORY).append("/td-polkitagent"); if (QFile::exists(pkPath)) { auto pkProc = new QProcess(this); pkProc->start(pkPath); } QStringList searchPaths = { qEnvironmentVariable("XDG_CONFIG_HOME", QDir::homePath() + "/.config") + "/autostart", qEnvironmentVariable("XDG_CONFIG_DIRS", "/etc/xdg") + "/autostart"}; for (QString desktopEntry : Application::allApplications(searchPaths)) { ApplicationPointer app(new Application(desktopEntry, searchPaths)); if (app->getProperty("Hidden", "false").toString() == "true") continue; // Ignore this autostart entry if (!app->getStringList("OnlyShowIn", {"thedesk"}).contains("thedesk")) continue; if (app->getStringList("NotShowIn").contains("thedesk")) continue; // Blacklist Touchegg if (desktopEntry == "touchegg") continue; if (app->hasProperty("TryExec")) { QString tryExecPath = app->getProperty("TryExec").toString(); if (tryExecPath.startsWith("/")) { // TryExec is an absolute path QFile testFile(tryExecPath); if (!testFile.exists() | testFile.permissions() & ~QFile::ExeUser) continue; } else { // TryExec should be searched for in the PATH if (libContemporaryCommon::searchInPath(tryExecPath).isEmpty()) continue; } } // Autostart this app app->launch(); } d->autostartDone = true; } void SplashController::startWM() { if (!d->wm && QApplication::platformName() != "wayland") { d->wm = new QProcess(this); QString wmgr = d->settings->value("Session/WindowManager").toString(); d->wm->start(d->settings->value("Session/WindowManager").toString(), d->settings->delimitedList("Session/WindowManagerArguments")); // TODO: make this a configurable setting } } void SplashController::startDE() { if (d->process) return; emit starting(); d->server->listen(d->serverPath); d->startedSuccessfully = false; // Set correct DPI tSettings settings; DesktopWm::instance()->registerAsPrimaryProvider(); ScreenDaemon::instance()->setDpi(settings.value("Display/dpi").toInt()); QString thedeskPath = qEnvironmentVariable("THEDESK_PATH", "/usr/bin/thedesk"); d->process = new QProcess(this); // d->process->setProcessChannelMode(QProcess::ForwardedChannels); d->process->setProgram(thedeskPath); d->process->setArguments({"--sessionserver", d->serverPath}); d->process->start(); connect(d->process, &QProcess::errorOccurred, this, [=](QProcess::ProcessError error) { if (error == QProcess::FailedToStart || !d->startedSuccessfully) { emit startFail(); } else if (error == QProcess::Crashed) { d->lastBacktrace = d->currentBacktrace; d->currentBacktrace.clear(); // Check to see if we should crash or not if (d->timeSinceSuccessfulStart.hasExpired(60000)) { // Attempt to recover QTimer::singleShot(1000, this, [=] { d->performingAutoRecovery = true; this->startDE(); }); } else { d->performingAutoRecovery = false; emit crash(); } } }); connect(d->process, QOverload::of(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus status) { if (status == QProcess::NormalExit) { if (exitCode == 0) { this->logout(); } } d->process->deleteLater(); d->process = nullptr; d->server->close(); if (d->socket) d->socket->close(); }); connect(d->process, &QProcess::readyReadStandardOutput, this, [=] { QString data = d->process->readAllStandardOutput(); QTextStream output(stdout); output << data; }); connect(d->process, &QProcess::readyReadStandardError, this, [=] { QString data = d->process->readAllStandardError(); for (QString line : data.split("\n")) { if (line.startsWith("THEDESK-TRAP:")) { d->currentBacktrace.append(line.mid(14)); } } QTextStream output(stderr); output << data; }); } void SplashController::logout() { if (d->wm) d->wm->kill(); QApplication::exit(); } void SplashController::respond(bool answer) { d->socket->write(QJsonDocument(QJsonObject({ {"type", "questionResponse"}, {"response", answer } })) .toJson()); d->socket->flush(); } QStringList SplashController::lastBacktrace() { return d->lastBacktrace; } ================================================ FILE: startdesk/splash/splashcontroller.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SPLASHCONTROLLER_H #define SPLASHCONTROLLER_H #include struct SplashControllerPrivate; class SplashController : public QObject { Q_OBJECT public: ~SplashController(); static SplashController* instance(); void initSession(); void runAutostart(); void startWM(); void startDE(); void logout(); void respond(bool answer); QStringList lastBacktrace(); signals: void starting(); void hideSplashes(); void crash(); void startFail(); void question(QString title, QString message); private: explicit SplashController(QObject* parent = nullptr); static SplashControllerPrivate* d; void socketDataAvailable(); }; #endif // SPLASHCONTROLLER_H ================================================ FILE: startdesk/splash/splashwidget.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "splashwidget.h" #include "ui_splashwidget.h" #include #include SplashWidget::SplashWidget(QWidget* parent) : QWidget(parent), ui(new Ui::SplashWidget) { ui->setupUi(this); // QProcess proc; // proc.start("fortune", QStringList()); // proc.waitForFinished(); // QProcess cs; // cs.start("cowsay", QStringList()); // cs.write(proc.readAll()); // cs.closeWriteChannel(); // cs.waitForFinished(); // ui->fortuneLabel->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); // ui->fortuneLabel->setText(cs.readAll().trimmed()); ui->fortuneLabel->setVisible(false); } SplashWidget::~SplashWidget() { delete ui; } ================================================ FILE: startdesk/splash/splashwidget.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SPLASHWIDGET_H #define SPLASHWIDGET_H #include namespace Ui { class SplashWidget; } class SplashWidget : public QWidget { Q_OBJECT public: explicit SplashWidget(QWidget *parent = nullptr); ~SplashWidget(); private: Ui::SplashWidget *ui; }; #endif // SPLASHWIDGET_H ================================================ FILE: startdesk/splash/splashwidget.ui ================================================ SplashWidget 0 0 400 300 Form 40 40 Qt::Vertical 20 121 Qt::Horizontal 171 20 Qt::Horizontal 170 20 Qt::Vertical 20 120 TextLabel tCircularSpinner QWidget
tcircularspinner.h
1
================================================ FILE: startdesk/splashwindow.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "splashwindow.h" #include "ui_splashwindow.h" #include "splash/splashcontroller.h" #include #include #include SplashWindow::SplashWindow(QWidget* parent) : QDialog(parent), ui(new Ui::SplashWindow) { ui->setupUi(this); this->setWindowFlag(Qt::WindowStaysOnTopHint); ui->stackedWidget->setCurrentAnimation(tStackedWidget::Fade); connect(SplashController::instance(), &SplashController::starting, this, [=] { ui->stackedWidget->setCurrentWidget(ui->splashPage, this->isVisible()); this->showFullScreen(); }); connect(SplashController::instance(), &SplashController::hideSplashes, this, [=] { this->hide(); }); connect(SplashController::instance(), &SplashController::crash, this, [=] { ui->stackedWidget->setCurrentWidget(ui->crashPage, this->isVisible()); this->showFullScreen(); }); connect(SplashController::instance(), &SplashController::startFail, this, [=] { ui->stackedWidget->setCurrentWidget(ui->crashPage, this->isVisible()); this->showFullScreen(); }); connect(SplashController::instance(), &SplashController::question, this, [=](QString title, QString message) { ui->questionTitle->setText(title); ui->questionText->setText(message); ui->stackedWidget->setCurrentWidget(ui->questionPage, this->isVisible()); this->showFullScreen(); }); this->setGeometry(tApplication::primaryScreen()->geometry()); } SplashWindow::~SplashWindow() { delete ui; } void SplashWindow::hide() { tVariantAnimation* anim = new tVariantAnimation(this); anim->setStartValue(1.0); anim->setEndValue(0.0); anim->setEasingCurve(QEasingCurve::OutCubic); anim->setDuration(500); connect(anim, &tVariantAnimation::valueChanged, this, [=](QVariant value) { this->setWindowOpacity(value.toDouble()); }); connect(anim, &tVariantAnimation::finished, this, [=] { anim->deleteLater(); QDialog::hide(); this->setWindowOpacity(1); }); anim->start(); } void SplashWindow::on_yesButton_clicked() { SplashController::instance()->respond(true); ui->stackedWidget->setCurrentWidget(ui->splashPage); } void SplashWindow::on_noButton_clicked() { SplashController::instance()->respond(false); ui->stackedWidget->setCurrentWidget(ui->splashPage); } ================================================ FILE: startdesk/splashwindow.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2020 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef SPLASHWINDOW_H #define SPLASHWINDOW_H #include namespace Ui { class SplashWindow; } class SplashWindow : public QDialog { Q_OBJECT public: explicit SplashWindow(QWidget* parent = nullptr); ~SplashWindow(); void hide(); private slots: void on_yesButton_clicked(); void on_noButton_clicked(); private: Ui::SplashWindow* ui; }; #endif // SPLASHWINDOW_H ================================================ FILE: startdesk/splashwindow.ui ================================================ SplashWindow 0 0 633 471 Dialog 0 0 0 0 0 Qt::Vertical 20 173 Qt::Horizontal 218 20 0 0 0 0 9 9 9 15 Title Question 0 Yes .. No .. Qt::Horizontal 217 20 Qt::Vertical 20 172 tStackedWidget QStackedWidget
tstackedwidget.h
1 switchingFrame(int)
SplashWidget QWidget
splash/splashwidget.h
1
CrashWidget QWidget
crash/crashwidget.h
1
================================================ FILE: startdesk/start-thedesk-wayland.in ================================================ #!/bin/sh sleep 2 # Mitigate lightdm bug that causes Wayfire not to start up correctly immediately exec wayfire --config ${CMAKE_INSTALL_FULL_DATADIR}/thedesk/startdesk/wayfire-thedesk-config.conf ================================================ FILE: startdesk/startdesk.pro ================================================ QT += core gui thelib network tdesktopenvironment greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 # Include the-libs build tools equals(THELIBS_BUILDTOOLS_PATH, "") { THELIBS_BUILDTOOLS_PATH = $$[QT_INSTALL_PREFIX]/share/the-libs/pri } include($$THELIBS_BUILDTOOLS_PATH/gentranslations.pri) include($$THELIBS_BUILDTOOLS_PATH/varset.pri) # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ crash/backtracedialog.cpp \ crash/backtracepopover.cpp \ crash/backtracewidget.cpp \ crash/crashwidget.cpp \ main.cpp \ splash/splashcontroller.cpp \ splash/splashwidget.cpp \ splashwindow.cpp HEADERS += \ crash/backtracedialog.h \ crash/backtracepopover.h \ crash/backtracewidget.h \ crash/crashwidget.h \ splash/splashcontroller.h \ splash/splashwidget.h \ splashwindow.h FORMS += \ crash/backtracedialog.ui \ crash/backtracepopover.ui \ crash/backtracewidget.ui \ crash/crashwidget.ui \ splash/splashwidget.ui \ splashwindow.ui DISTFILES += \ thedesk.desktop unix { target.path = /usr/bin/ translations.files = translations/*.qm translations.path = /usr/share/thedesk/startdesk/translations xsession.path = /usr/share/xsessions xsession.files = thedesk.desktop wayland-session.path = /usr/share/wayland-sessions wayland-session.files = thedesk-wayland.desktop wayfire-config.path = /usr/share/thedesk/startdesk wayfire-config.files = wayfire-thedesk-config.conf INSTALLS += target translations xsession wayland-session wayfire-config } DEFINES += SYSTEM_LIBRARY_DIRECTORY=\\\"$$THELIBS_INSTALL_LIB\\\" unix:!macx: LIBS += -L$$OUT_PWD/../libthedesk/ -lthedesk INCLUDEPATH += $$PWD/../libthedesk DEPENDPATH += $$PWD/../libthedesk RESOURCES += \ resources.qrc ================================================ FILE: startdesk/thedesk-wayland.desktop.in ================================================ [Desktop Entry] Encoding=UTF-8 Type=Application Exec=${CMAKE_INSTALL_FULL_BINDIR}/start-thedesk-wayland TryExec=${CMAKE_INSTALL_FULL_BINDIR}/wayfire DesktopNames=theDesk Name=theDesk on Wayland Comment=theDesk Desktop Environment ================================================ FILE: startdesk/thedesk.desktop.in ================================================ [Desktop Entry] Encoding=UTF-8 Type=XSession Exec=${CMAKE_INSTALL_FULL_BINDIR}/startdesk TryExec=${CMAKE_INSTALL_FULL_BINDIR}/startdesk DesktopNames=theDesk Name=theDesk Comment=theDesk Desktop Environment ================================================ FILE: startdesk/translations/ar_SA.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/au_AU.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/cy.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/da.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/de.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/en_GB.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! Oh, Bonkers! theDesk had a problem and has stopped working. theDesk had a problem and has stopped working. Relaunch theDesk Relaunch theDesk Log Out Log Out View Details theDesk couldn't start because of a problem. theDesk couldn't start because of a problem. SplashController Oh, Bonkers! Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Question Yes Yes No No ================================================ FILE: startdesk/translations/en_US.qm ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/es.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/es_VE.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/id.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/nl.ts ================================================ BacktraceDialog Error Details Foutdetails BacktracePopover Error Details Foutdetails BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! Bekijk de gegevens hieronder en zorg ervoor dat er geen persoonlijke gegevens in staan. Voeg deze informatie toe aan een bugrapport en dan komen we bij je terug! ACTIONS ACTIES Save to file Opslaan naar bestand CrashWidget Oh, Bonkers! Oh nee! theDesk had a problem and has stopped working. theDesk had een probleem en werkt niet meer. Relaunch theDesk theDesk Herstarten Log Out Uitloggen View Details Details Weergeven theDesk couldn't start because of a problem. theDesk kon niet opstarten door een probleem. SplashController Oh, Bonkers! Oh nee! theDesk had a problem and was restarted. theDesk had een probleem en is herstart. View Details Details Weergeven SplashWindow Question Vraag Yes Ja No Nee ================================================ FILE: startdesk/translations/pl_PL.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! O nie! theDesk had a problem and has stopped working. Aplikacja theDesk miała problem i przestała działać. Relaunch theDesk Uruchom ponownie theDesk Log Out Wyloguj Sie View Details theDesk couldn't start because of a problem. Aplikacja theDesk nie mogła zastartować bo jest problem. SplashController Oh, Bonkers! O nie! theDesk had a problem and was restarted. View Details SplashWindow Question Pytanie Yes Tak No Nie ================================================ FILE: startdesk/translations/pt_BR.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/ro_RO.ts ================================================ BacktraceDialog Error Details Detalii eroare BacktracePopover Error Details Detalii eroare BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! Revizuiți informațiile de mai jos și asigurați-vă că nu conțin date personale. Atașați aceste date la un raport de eroare și o să vă contactăm! ACTIONS ACȚIUNI Save to file Salvați în fișier CrashWidget Oh, Bonkers! O, vai! theDesk had a problem and has stopped working. theDesk a întâmpinat o problemă și s-a oprit. Relaunch theDesk Repornește theDesk Log Out Deconectare View Details Vedeți detaliile theDesk couldn't start because of a problem. theDesk nu a putut porni din cauza unei probleme. SplashController Oh, Bonkers! O, vai! theDesk had a problem and was restarted. theDesk a întâmpinat o problemă și a fost repornit. View Details Vedeți detaliile SplashWindow Question Întrebare Yes Da No Nu ================================================ FILE: startdesk/translations/sv.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/translations/tr_TR.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! Oh, Bir Kaçık! theDesk had a problem and has stopped working. theDesk'te bir sorun vardı ve çalışmayı durdurdu. Relaunch theDesk TheDesk'i yeniden başlatın Log Out Çıkış Yap View Details theDesk couldn't start because of a problem. theDesk bir sorun nedeniyle başlayamadı. SplashController Oh, Bonkers! Oh, Bir Kaçık! theDesk had a problem and was restarted. View Details SplashWindow Question Soru Yes Evet No Yok ================================================ FILE: startdesk/translations/vi_VN.ts ================================================ BacktraceDialog Error Details Chi tiết về lỗi BacktracePopover Error Details Chi tiết về lỗi BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! Vui lòng xem lại chi tiết dưới đây, và xác nhận nó không nhúng dữ liệu cá nhân. Đính kèm thông tin này vào một báo cáo lỗi, rồi chúng tôi hãy trả lời cho bạn! ACTIONS HOẠT ĐỘNG Save to file Lưu vào tệp CrashWidget Oh, Bonkers! Ủa? theDesk had a problem and has stopped working. Rất tiếc, theDesk gặp vấn đề và bị buộc dừng. Relaunch theDesk Khởi chạy theDesk lại Log Out Đăng xuất View Details Xem chi tiết theDesk couldn't start because of a problem. theDesk không thể khởi động vì một sự cố. SplashController Oh, Bonkers! Ủa? theDesk had a problem and was restarted. theDesk đã xảy ra một lỗi, và đã khởi chạy lại. View Details Xem chi tiết SplashWindow Question Câu hỏi Yes Có No Không ================================================ FILE: startdesk/translations/zh_CN.ts ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! 糟糕!! theDesk had a problem and has stopped working. theDesk遇到了错误并停止了运行。 Relaunch theDesk 重启theDesk Log Out 注销 View Details theDesk couldn't start because of a problem. theDesk 因为某种原因不能启动。 SplashController Oh, Bonkers! 糟糕!! theDesk had a problem and was restarted. View Details SplashWindow Question 问题 Yes No ================================================ FILE: startdesk/translations/zu_ZA.qm ================================================ BacktraceDialog Error Details BacktracePopover Error Details BacktraceWidget Review the information below and ensure it does not contain any personal data. Attach the information to a bug report and we'll get back to you! ACTIONS Save to file CrashWidget Oh, Bonkers! theDesk had a problem and has stopped working. Relaunch theDesk Log Out View Details theDesk couldn't start because of a problem. SplashController Oh, Bonkers! theDesk had a problem and was restarted. View Details SplashWindow Question Yes No ================================================ FILE: startdesk/wayfire-thedesk-config.conf ================================================ # Default config for Wayfire # # Copy this to ~/.config/wayfire.ini and edit it to your liking. # # Take the tutorial to get started. # https://github.com/WayfireWM/wayfire/wiki/Tutorial # # Read the Configuration document for a complete reference. # https://github.com/WayfireWM/wayfire/wiki/Configuration # Input configuration ────────────────────────────────────────────────────────── # Example configuration: # # [input] # xkb_layout = us,fr # xkb_variant = dvorak,bepo # # See Input options for a complete reference. # https://github.com/WayfireWM/wayfire/wiki/Configuration#input # Output configuration ───────────────────────────────────────────────────────── # Example configuration: # # [output:eDP-1] # mode = 1920x1080@60000 # layout = 0,0 # transform = normal # scale = 1.000000 # # You can get the names of your outputs with wlr-randr. # https://github.com/emersion/wlr-randr # # See also kanshi for configuring your outputs automatically. # https://wayland.emersion.fr/kanshi/ # # See Output options for a complete reference. # https://github.com/WayfireWM/wayfire/wiki/Configuration#output #[output:HDMI-A-1] #mode=3840x2160@30000 # Core options ───────────────────────────────────────────────────────────────── [core] # List of plugins to be enabled. # See the Configuration document for a complete list. plugins = \ alpha \ animate \ blur \ cube \ decoration \ fast-switcher \ fisheye \ grid \ idle \ invert \ move \ oswitch \ place \ resize \ switcher \ vswitch \ window-rules \ wobbly \ wrot \ zoom \ dbusqt \ thedesk-keygrab \ thedesk-startdesk \ thedesk-a11y # Note: [blur] is not enabled by default, because it can be resource-intensive. # Feel free to add it to the list if you want it. # You can find its documentation here: # https://github.com/WayfireWM/wayfire/wiki/Configuration#blur # Close focused window. close_top_view = KEY_Q | KEY_F4 # Workspaces arranged into a grid: 1 × 1. vwidth = 1 vheight = 1 # Prefer client-side decoration or server-side decoration preferred_decoration_mode = client # Mouse bindings ─────────────────────────────────────────────────────────────── # Drag windows by holding down Super and left mouse button. [move] activate = BTN_LEFT # Resize them with right mouse button + Super. [resize] activate = BTN_RIGHT # Zoom in the desktop by scrolling + Super. [zoom] modifier = # Change opacity by scrolling with Super + Alt. [alpha] modifier = # Rotate windows with the mouse. [wrot] activate = BTN_RIGHT # Fisheye effect. [fisheye] toggle = KEY_F # Startup commands ───────────────────────────────────────────────────────────── [autostart] # Automatically start background and panel. # Set to false if you want to override the default clients. autostart_wf_shell = false # Applications ───────────────────────────────────────────────────────────────── [command] # Windows ────────────────────────────────────────────────────────────────────── # Position the windows in certain regions of the output. [grid] # # ⇱ ↑ ⇲ │ 7 8 9 # ← f → │ 4 5 6 # ⇱ ↓ ⇲ d │ 1 2 3 0 # ‾ ‾ slot_bl = KEY_KP1 slot_b = KEY_KP2 slot_br = KEY_KP3 slot_l = KEY_LEFT | KEY_KP4 slot_c = KEY_UP | KEY_KP5 slot_r = KEY_RIGHT | KEY_KP6 slot_tl = KEY_KP7 slot_t = KEY_KP8 slot_tr = KEY_KP9 # Restore default. restore = KEY_DOWN | KEY_KP0 # Change active window with an animation. [switcher] next_view = KEY_TAB prev_view = KEY_TAB # Simple active window switcher. [fast-switcher] activate = KEY_ESC # Workspaces ─────────────────────────────────────────────────────────────────── # Switch to workspace. [vswitch] binding_left = KEY_LEFT binding_down = KEY_DOWN binding_up = KEY_UP binding_right = KEY_RIGHT # Move the focused window with the same key-bindings, but add Shift. binding_win_left = KEY_LEFT binding_win_down = KEY_DOWN binding_win_up = KEY_UP binding_win_right = KEY_RIGHT # Show the current workspace row as a cube. [cube] activate = BTN_LEFT # Switch to the next or previous workspace. #rotate_left = KEY_H #rotate_right = KEY_L # Show an overview of all workspaces. [expo] toggle = # Select a workspace. # Workspaces are arranged into a grid of 3 × 3. # The numbering is left to right, line by line. # # ⇱ k ⇲ # h ⏎ l # ⇱ j ⇲ # ‾ ‾ # See core.vwidth and core.vheight for configuring the grid. select_workspace_1 = KEY_1 select_workspace_2 = KEY_2 select_workspace_3 = KEY_3 select_workspace_4 = KEY_4 select_workspace_5 = KEY_5 select_workspace_6 = KEY_6 select_workspace_7 = KEY_7 select_workspace_8 = KEY_8 select_workspace_9 = KEY_9 # Outputs ────────────────────────────────────────────────────────────────────── # Change focused output. [oswitch] # Switch to the next output. next_output = KEY_O # Same with the window. next_output_with_win = KEY_O # Invert the colors of the whole output. [invert] toggle = KEY_I # Rules ──────────────────────────────────────────────────────────────────────── # Example configuration: # # [window-rules] # maximize_alacritty = on created if app_id is "Alacritty" then maximize # # You can get the properties of your applications with the following command: # $ WAYLAND_DEBUG=1 alacritty 2>&1 | kak # # See Window rules for a complete reference. # https://github.com/WayfireWM/wayfire/wiki/Configuration#window-rules [animate] duration=250 [blur] blur_by_default=all ================================================ FILE: theDesk.pro ================================================ TEMPLATE = subdirs libraryproj.subdir = libthedesk deskproj.subdir = desktop deskproj.depends = libraryproj pluginsproj.subdir = plugins pluginsproj.depends = libraryproj startdeskproj.subdir = startdesk startdeskproj.depends = libraryproj SUBDIRS = libraryproj \ deskproj \ desktop-portal \ platform \ pluginsproj \ polkitagent \ startdeskproj packagesExist(wayfire) { SUBDIRS += wayfire-plugins } ================================================ FILE: wayfire-plugins/CMakeLists.txt ================================================ find_program(WAYLAND_SCANNER wayland-scanner) if(NOT WAYLAND_SCANNER) message(FATAL_ERROR "wayland-scanner not found!") endif() message(STATUS "Found wayland-scanner: ${WAYLAND_SCANNER}") function(thedesk_wayfire_plugin_wayland_protocols target) set(multiValueArgs FILES) cmake_parse_arguments(REGISTER_WAYLAND_PROTOCOL_EXTENSIONS "" "" "${multiValueArgs}" ${ARGN}) foreach(_file ${REGISTER_WAYLAND_PROTOCOL_EXTENSIONS_FILES}) get_filename_component(_basename ${_file} NAME_WE) # Wayland scanner add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-server-protocol.h" COMMAND ${WAYLAND_SCANNER} server-header ${_file} "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-server-protocol.h" DEPENDS ${_file} VERBATIM) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-server-protocol.c" COMMAND ${WAYLAND_SCANNER} public-code ${_file} "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-server-protocol.c" DEPENDS ${_file} VERBATIM) # Include in sources set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-server-protocol.c" PROPERTY SKIP_AUTOGEN ON) set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-server-protocol.h" PROPERTY SKIP_AUTOGEN ON) target_sources(${target} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-server-protocol.c" "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-server-protocol.h") endforeach() endfunction() add_subdirectory(keygrab-plugin) add_subdirectory(startdesk-plugin) add_subdirectory(a11y-plugin) ================================================ FILE: wayfire-plugins/a11y-plugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) project(lib VERSION 1.0.0 LANGUAGES C CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) find_package(libcontemporary REQUIRED) cntp_find_pkgconfig(wayfire wayfire) cntp_find_pkgconfig(pixman pixman-1) set(SOURCES a11yplugin.cpp abstracta11ycontroller.cpp stickykeys.cpp mousekeys.cpp ) set(HEADERS a11yplugin.h abstracta11ycontroller.h stickykeys.h mousekeys.h ) set(PRIVATE_HEADERS ) add_library(wf-thedesk-a11y SHARED) cntp_init(wf-thedesk-a11y 20) set_target_properties(wf-thedesk-a11y PROPERTIES OUTPUT_NAME thedesk-a11y ) find_file(TDESKTOPENVIRONMENT_A11Y_FILE NAMES tdesktopenvironment-accessibility-v1.xml PATHS ENV XDG_DATA_DIRS PATH_SUFFIXES libtdesktopenvironment/wayland-protocols/tdesktopenvironment-protocols NO_DEFAULT_PATH REQUIRED ) if(NOT TDESKTOPENVIRONMENT_A11Y_FILE) message(FATAL_ERROR "Could not find tdesktopenvironment-accessibility-v1.xml") endif() thedesk_wayfire_plugin_wayland_protocols(wf-thedesk-a11y FILES ${TDESKTOPENVIRONMENT_A11Y_FILE} ) target_link_libraries(wf-thedesk-a11y Qt::Core libcontemporary PkgConfig::wayfire PkgConfig::pixman) target_compile_definitions(wf-thedesk-a11y PRIVATE A11YPLUGIN_LIBRARY WLR_USE_UNSTABLE QT_NO_KEYWORDS) target_sources(wf-thedesk-a11y PRIVATE ${SOURCES} ${HEADERS} ${PRIVATE_HEADERS}) install(TARGETS wf-thedesk-a11y INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/wayfire ) ================================================ FILE: wayfire-plugins/a11y-plugin/a11yplugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "a11yplugin.h" #include "mousekeys.h" #include "stickykeys.h" #include #include extern "C" { #include } struct A11yPluginPrivate { wlr_backend* backend; wlr_pointer pointer; wlr_keyboard keyboard; wl_resource* tdeKeygrabManager; StickyKeys* stickyKeys; MouseKeys* mouseKeys; wlr_pointer_impl pointerImpl = { "thedesk-a11y-pointer"}; wlr_keyboard_impl keyboardImpl = { "thedesk-a11y-keyboard", nullptr}; }; A11yPlugin::A11yPlugin() { d = new A11yPluginPrivate(); } A11yPlugin::~A11yPlugin() { delete d; } void A11yPlugin::init() { d->backend = wlr_headless_backend_create(wf::get_core().display); wlr_multi_backend_add(wf::get_core().backend, d->backend); wlr_pointer_init(&d->pointer, &d->pointerImpl, "thedesk-a11y-pointer"); wlr_keyboard_init(&d->keyboard, &d->keyboardImpl, "thedesk-a11y-keyboard"); wl_signal_emit_mutable(&d->backend->events.new_input, &d->pointer.base); wl_signal_emit_mutable(&d->backend->events.new_input, &d->keyboard.base); if (wf::get_core().get_current_state() == wf::compositor_state_t::RUNNING) { wlr_backend_start(d->backend); } d->stickyKeys = new StickyKeys(&d->keyboard); d->mouseKeys = new MouseKeys(&d->keyboard, &d->pointer); } void A11yPlugin::fini() { d->stickyKeys->deleteLater(); d->mouseKeys->deleteLater(); wlr_keyboard_finish(&d->keyboard); wlr_multi_backend_remove(wf::get_core().backend, d->backend); wlr_backend_destroy(d->backend); } bool A11yPlugin::is_unloadable() { return false; } ================================================ FILE: wayfire-plugins/a11y-plugin/a11yplugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYGRABPLUGIN_H #define KEYGRABPLUGIN_H #include struct wl_client; struct A11yPluginPrivate; class A11yPlugin : public wf::plugin_interface_t { public: A11yPlugin(); ~A11yPlugin(); // plugin_interface_t interface public: void init(); void fini(); bool is_unloadable(); private: A11yPluginPrivate* d; }; DECLARE_WAYFIRE_PLUGIN(A11yPlugin) #endif // KEYGRABPLUGIN_H ================================================ FILE: wayfire-plugins/a11y-plugin/abstracta11ycontroller.cpp ================================================ #include "abstracta11ycontroller.h" struct AbstractA11yControllerPrivate { bool enabled = false; }; AbstractA11yController::AbstractA11yController(QObject* parent) : QObject{parent} { d = new AbstractA11yControllerPrivate(); } AbstractA11yController::~AbstractA11yController() { delete d; } void AbstractA11yController::setEnabled(bool enabled) { if (enabled && !d->enabled) { d->enabled = true; this->enable(); } else if (!enabled && d->enabled) { d->enabled = false; this->disable(); } } bool AbstractA11yController::enabled() { return d->enabled; } ================================================ FILE: wayfire-plugins/a11y-plugin/abstracta11ycontroller.h ================================================ #ifndef ABSTRACTA11YCONTROLLER_H #define ABSTRACTA11YCONTROLLER_H #include struct AbstractA11yControllerPrivate; class AbstractA11yController : public QObject { Q_OBJECT public: explicit AbstractA11yController(QObject* parent = nullptr); ~AbstractA11yController(); void setEnabled(bool enabled); bool enabled(); Q_SIGNALS: private: AbstractA11yControllerPrivate* d; virtual void enable() = 0; virtual void disable() = 0; }; #endif // ABSTRACTA11YCONTROLLER_H ================================================ FILE: wayfire-plugins/a11y-plugin/mousekeys.cpp ================================================ #include "mousekeys.h" #include "wayland-tdesktopenvironment-accessibility-v1-server-protocol.h" #include #include #include #include struct MouseKeysPrivate { static constexpr int mouseKeysDelay = 100; static constexpr int mouseKeysPixels = 1; wlr_keyboard* keyboard; wlr_pointer* pointer; wl_resource* tdeA11yMouseKeys; MouseKeys* parent; wl_event_loop* eventLoop; wl_event_source* timer; Qt::Edges moveDirection; QDateTime lastPress; wf::signal::connection_t> keyboardButtonEvent = [this](wf::input_event_signal* ev) { parent->keyboardButtonPressed(ev); }; static int mouseKeysTimer(void* data) { return reinterpret_cast(data)->mouseKeysTimer(); } }; MouseKeys::MouseKeys(wlr_keyboard* keyboard, wlr_pointer* pointer, QObject* parent) : AbstractA11yController{parent} { d = new MouseKeysPrivate(); d->parent = this; d->keyboard = keyboard; d->pointer = pointer; wl_global_create(wf::get_core().display, &tdesktopenvironment_accessibility_mouse_keys_v1_interface, 1, this, [](wl_client* client, void* data, uint32_t version, uint32_t id) { auto* plugin = reinterpret_cast(data); plugin->d->tdeA11yMouseKeys = wl_resource_create(client, &tdesktopenvironment_accessibility_mouse_keys_v1_interface, 1, id); auto interface = new struct tdesktopenvironment_accessibility_sticky_keys_v1_interface(); interface->set_enabled = [](struct wl_client* client, struct wl_resource* resource, uint enabled) { reinterpret_cast(resource->data)->setEnabled(enabled); }; wl_resource_set_implementation(plugin->d->tdeA11yMouseKeys, interface, plugin, nullptr); }); d->eventLoop = wl_display_get_event_loop(wf::get_core().display); d->timer = wl_event_loop_add_timer(d->eventLoop, MouseKeysPrivate::mouseKeysTimer, this); } MouseKeys::~MouseKeys() { wl_event_source_remove(d->timer); delete d; } void MouseKeys::keyboardButtonPressed(wf::input_event_signal* event) { Qt::Edges edges; switch (event->event->keycode) { case KEY_KP7: edges = Qt::LeftEdge | Qt::TopEdge; break; case KEY_KP8: edges = Qt::TopEdge; break; case KEY_KP9: edges = Qt::RightEdge | Qt::TopEdge; break; case KEY_KP4: edges = Qt::LeftEdge; break; case KEY_KP6: edges = Qt::RightEdge; break; case KEY_KP1: edges = Qt::LeftEdge | Qt::BottomEdge; break; case KEY_KP2: edges = Qt::BottomEdge; break; case KEY_KP3: edges = Qt::RightEdge | Qt::BottomEdge; break; case KEY_KP5: { if (event->event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { this->pressMouse(); } else if (event->event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { this->releaseMouse(); } return; } } if (edges == 0) return; event->mode = wf::input_event_processing_mode_t::IGNORE; if (event->event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { // Always override the existing movement d->moveDirection = edges; d->lastPress = QDateTime::currentDateTimeUtc(); // Always move the mouse at least once processMouseMovement(); } else if (event->event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { // Only stop movement if the existing movement is the same if (d->moveDirection == edges) { d->moveDirection = {}; } } } int MouseKeys::mouseKeysTimer() { if (!this->enabled()) return 0; if (d->moveDirection) processMouseMovement(); wl_event_source_timer_update(d->timer, d->mouseKeysDelay); return 1; } void MouseKeys::enable() { wf::get_core().connect(&d->keyboardButtonEvent); wl_event_source_timer_update(d->timer, d->mouseKeysDelay); this->updateMouseKeysState(); } void MouseKeys::disable() { wf::get_core().disconnect(&d->keyboardButtonEvent); this->updateMouseKeysState(); } void MouseKeys::pressMouse() { wlr_pointer_button_event ev; ev.pointer = d->pointer; ev.button = BTN_LEFT; ev.state = WLR_BUTTON_PRESSED; ev.time_msec = wf::get_current_time(); wl_signal_emit(&d->pointer->events.button, &ev); wl_signal_emit(&d->pointer->events.frame, nullptr); } void MouseKeys::releaseMouse() { wlr_pointer_button_event ev; ev.pointer = d->pointer; ev.button = BTN_LEFT; ev.state = WLR_BUTTON_RELEASED; ev.time_msec = wf::get_current_time(); wl_signal_emit(&d->pointer->events.button, &ev); wl_signal_emit(&d->pointer->events.frame, nullptr); } void MouseKeys::processMouseMovement() { double x = 0; double y = 0; auto movement = d->mouseKeysPixels; auto stride = qMin(5000, d->lastPress.msecsTo(QDateTime::currentDateTimeUtc())); do { movement += d->mouseKeysPixels; stride -= 500; } while (stride >= 0); if (d->moveDirection & Qt::LeftEdge) x -= movement; if (d->moveDirection & Qt::RightEdge) x += movement; if (d->moveDirection & Qt::TopEdge) y -= movement; if (d->moveDirection & Qt::BottomEdge) y += movement; wlr_pointer_motion_event ev; ev.pointer = d->pointer; ev.time_msec = wf::get_current_time(); ev.delta_x = ev.unaccel_dx = x; ev.delta_y = ev.unaccel_dy = y; wl_signal_emit(&d->pointer->events.motion, &ev); wl_signal_emit(&d->pointer->events.frame, nullptr); } void MouseKeys::updateMouseKeysState() { tdesktopenvironment_accessibility_mouse_keys_v1_send_mouse_keys_enabled(d->tdeA11yMouseKeys, this->enabled()); } ================================================ FILE: wayfire-plugins/a11y-plugin/mousekeys.h ================================================ #ifndef MOUSEKEYS_H #define MOUSEKEYS_H #include "abstracta11ycontroller.h" #include struct MouseKeysPrivate; class MouseKeys : public AbstractA11yController { Q_OBJECT public: explicit MouseKeys(wlr_keyboard* keyboard, wlr_pointer* pointer, QObject* parent = nullptr); ~MouseKeys(); protected: friend MouseKeysPrivate; void keyboardButtonPressed(wf::input_event_signal* event); int mouseKeysTimer(); private: MouseKeysPrivate* d; void updateMouseKeysState(); // AbstractA11yController interface private: void enable(); void disable(); void pressMouse(); void releaseMouse(); void processMouseMovement(); }; #endif // MOUSEKEYS_H ================================================ FILE: wayfire-plugins/a11y-plugin/stickykeys.cpp ================================================ #include "stickykeys.h" #include "wayland-tdesktopenvironment-accessibility-v1-server-protocol.h" #include #include #include #include #include struct StickyKeysPrivate { wlr_keyboard* keyboard; wl_resource* tdeA11yStickyKeys; StickyKeys* parent; wf::signal::connection_t> keyboardButtonEvent = [this](wf::input_event_signal* ev) { parent->keyboardButtonPressed(ev); }; Qt::KeyboardModifiers heldModifiers = Qt::NoModifier; Qt::KeyboardModifiers latchedModifiers = Qt::NoModifier; bool processing = false; class KeySession { public: KeySession(wlr_keyboard* keyboard) { this->keyboard = keyboard; } ~KeySession() { for (auto keycode = keycodes.crbegin(); keycode != keycodes.crend(); keycode++) { wlr_keyboard_key_event newEvent; newEvent.keycode = *keycode; newEvent.update_state = true; newEvent.time_msec = wf::get_current_time(); newEvent.state = WL_KEYBOARD_KEY_STATE_RELEASED; wlr_keyboard_notify_key(keyboard, &newEvent); } } void push(quint32 keycode) { keycodes.append(keycode); wlr_keyboard_key_event newEvent; newEvent.keycode = keycode; newEvent.update_state = true; newEvent.time_msec = wf::get_current_time(); newEvent.state = WL_KEYBOARD_KEY_STATE_PRESSED; wlr_keyboard_notify_key(keyboard, &newEvent); } private: QList keycodes; wlr_keyboard* keyboard; }; }; StickyKeys::StickyKeys(wlr_keyboard* keyboard, QObject* parent) : AbstractA11yController{parent} { d = new StickyKeysPrivate(); d->parent = this; d->keyboard = keyboard; wl_global_create(wf::get_core().display, &tdesktopenvironment_accessibility_sticky_keys_v1_interface, 1, this, [](wl_client* client, void* data, uint32_t version, uint32_t id) { auto* plugin = reinterpret_cast(data); plugin->d->tdeA11yStickyKeys = wl_resource_create(client, &tdesktopenvironment_accessibility_sticky_keys_v1_interface, 1, id); auto interface = new struct tdesktopenvironment_accessibility_sticky_keys_v1_interface(); interface->set_enabled = [](struct wl_client* client, struct wl_resource* resource, uint enabled) { reinterpret_cast(resource->data)->setEnabled(enabled); }; wl_resource_set_implementation(plugin->d->tdeA11yStickyKeys, interface, plugin, nullptr); }); } StickyKeys::~StickyKeys() { delete d; } void StickyKeys::enable() { wf::get_core().connect(&d->keyboardButtonEvent); this->updateStickyKeysState(); } void StickyKeys::disable() { wf::get_core().disconnect(&d->keyboardButtonEvent); this->updateStickyKeysState(); } void StickyKeys::updateStickyKeysState() { tdesktopenvironment_accessibility_sticky_keys_v1_send_sticky_keys_enabled(d->tdeA11yStickyKeys, this->enabled()); } void StickyKeys::cycleModifier(Qt::KeyboardModifier modifier) { if (d->latchedModifiers.testFlag(modifier)) { // Turn off the latch d->latchedModifiers = d->latchedModifiers.setFlag(modifier, false); } else if (d->heldModifiers.testFlag(modifier)) { // Latch this key d->heldModifiers = d->heldModifiers.setFlag(modifier, false); d->latchedModifiers = d->latchedModifiers.setFlag(modifier, true); } else { // Hold this key d->heldModifiers = d->heldModifiers.setFlag(modifier); } sendUpdatedKeys(); } void StickyKeys::sendUpdatedKeys() { int heldMods = 0; if (d->heldModifiers.testFlag(Qt::ControlModifier)) heldMods |= TDESKTOPENVIRONMENT_ACCESSIBILITY_STICKY_KEYS_V1_MODIFIER_CONTROL; if (d->heldModifiers.testFlag(Qt::AltModifier)) heldMods |= TDESKTOPENVIRONMENT_ACCESSIBILITY_STICKY_KEYS_V1_MODIFIER_ALT; if (d->heldModifiers.testFlag(Qt::ShiftModifier)) heldMods |= TDESKTOPENVIRONMENT_ACCESSIBILITY_STICKY_KEYS_V1_MODIFIER_SHIFT; if (d->heldModifiers.testFlag(Qt::MetaModifier)) heldMods |= TDESKTOPENVIRONMENT_ACCESSIBILITY_STICKY_KEYS_V1_MODIFIER_SUPER; int latchedMods = 0; if (d->latchedModifiers.testFlag(Qt::ControlModifier)) latchedMods |= TDESKTOPENVIRONMENT_ACCESSIBILITY_STICKY_KEYS_V1_MODIFIER_CONTROL; if (d->latchedModifiers.testFlag(Qt::AltModifier)) latchedMods |= TDESKTOPENVIRONMENT_ACCESSIBILITY_STICKY_KEYS_V1_MODIFIER_ALT; if (d->latchedModifiers.testFlag(Qt::ShiftModifier)) latchedMods |= TDESKTOPENVIRONMENT_ACCESSIBILITY_STICKY_KEYS_V1_MODIFIER_SHIFT; if (d->latchedModifiers.testFlag(Qt::MetaModifier)) latchedMods |= TDESKTOPENVIRONMENT_ACCESSIBILITY_STICKY_KEYS_V1_MODIFIER_SUPER; tdesktopenvironment_accessibility_sticky_keys_v1_send_sticky_keys_held(d->tdeA11yStickyKeys, heldMods); tdesktopenvironment_accessibility_sticky_keys_v1_send_sticky_keys_latched(d->tdeA11yStickyKeys, latchedMods); } void StickyKeys::keyboardButtonPressed(wf::input_event_signal* event) { if (d->processing) return; QTextStream(stderr) << "Processing keycode: " << event->event->keycode << " state: " << event->event->state << "\n"; switch (event->event->keycode) { case KEY_LEFTCTRL: case KEY_RIGHTCTRL: event->mode = wf::input_event_processing_mode_t::IGNORE; if (event->event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { // Cycle the CTRL key this->cycleModifier(Qt::ControlModifier); } break; case KEY_LEFTALT: case KEY_RIGHTALT: event->mode = wf::input_event_processing_mode_t::IGNORE; if (event->event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { // Cycle the ALT key this->cycleModifier(Qt::AltModifier); } break; case KEY_LEFTSHIFT: case KEY_RIGHTSHIFT: event->mode = wf::input_event_processing_mode_t::IGNORE; if (event->event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { // Cycle the SHIFT key this->cycleModifier(Qt::ShiftModifier); } break; case KEY_LEFTMETA: case KEY_RIGHTMETA: event->mode = wf::input_event_processing_mode_t::IGNORE; if (event->event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { // Cycle the META key this->cycleModifier(Qt::MetaModifier); } break; default: { // If we have any keys held or latched, press them now auto thisModifiers = d->heldModifiers | d->latchedModifiers; if (thisModifiers != Qt::NoModifier) { event->mode = wf::input_event_processing_mode_t::IGNORE; if (event->event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { QTextStream(stderr) << "Pressing keycode: " << event->event->keycode << " modifiers: " << thisModifiers << "\n"; d->processing = true; { StickyKeysPrivate::KeySession session(d->keyboard); if (thisModifiers.testFlag(Qt::ControlModifier)) session.push(KEY_LEFTCTRL); if (thisModifiers.testFlag(Qt::AltModifier)) session.push(KEY_LEFTALT); if (thisModifiers.testFlag(Qt::ShiftModifier)) session.push(KEY_LEFTSHIFT); if (thisModifiers.testFlag(Qt::MetaModifier)) session.push(KEY_LEFTMETA); session.push(event->event->keycode); } d->processing = false; } } // Clear out all the held modifiers d->heldModifiers = Qt::NoModifier; sendUpdatedKeys(); } } } ================================================ FILE: wayfire-plugins/a11y-plugin/stickykeys.h ================================================ #ifndef STICKYKEYS_H #define STICKYKEYS_H #include "abstracta11ycontroller.h" #include struct StickyKeysPrivate; class StickyKeys : public AbstractA11yController { Q_OBJECT public: explicit StickyKeys(wlr_keyboard* keyboard, QObject* parent = nullptr); ~StickyKeys(); Q_SIGNALS: protected: friend StickyKeysPrivate; void keyboardButtonPressed(wf::input_event_signal* event); private: StickyKeysPrivate* d; // AbstractA11yController interface private: void enable(); void disable(); void updateStickyKeysState(); void cycleModifier(Qt::KeyboardModifier modifier); void sendUpdatedKeys(); }; #endif // STICKYKEYS_H ================================================ FILE: wayfire-plugins/keygrab-plugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) project(lib VERSION 1.0.0 LANGUAGES C CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) find_package(libcontemporary REQUIRED) cntp_find_pkgconfig(wayfire wayfire) cntp_find_pkgconfig(pixman pixman-1) set(SOURCES keygrabplugin.cpp ) set(HEADERS keygrabplugin.h ) set(PRIVATE_HEADERS ) add_library(wf-thedesk-keygrab SHARED) cntp_init(wf-thedesk-keygrab 20) set_target_properties(wf-thedesk-keygrab PROPERTIES OUTPUT_NAME thedesk-keygrab ) find_file(TDESKTOPENVIRONMENT_KEYGRAB_FILE NAMES tdesktopenvironment-keygrab-v1.xml PATHS ENV XDG_DATA_DIRS PATH_SUFFIXES libtdesktopenvironment/wayland-protocols/tdesktopenvironment-protocols NO_DEFAULT_PATH REQUIRED ) if(NOT TDESKTOPENVIRONMENT_KEYGRAB_FILE) message(FATAL_ERROR "Could not find tdesktopenvironment-keygrab-v1.xml") endif() thedesk_wayfire_plugin_wayland_protocols(wf-thedesk-keygrab FILES ${TDESKTOPENVIRONMENT_KEYGRAB_FILE} ) target_link_libraries(wf-thedesk-keygrab Qt::Core libcontemporary PkgConfig::wayfire PkgConfig::pixman) target_compile_definitions(wf-thedesk-keygrab PRIVATE KEYGRABPLUGIN_LIBRARY WLR_USE_UNSTABLE) target_sources(wf-thedesk-keygrab PRIVATE ${SOURCES} ${HEADERS} ${PRIVATE_HEADERS}) install(TARGETS wf-thedesk-keygrab INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/wayfire ) ================================================ FILE: wayfire-plugins/keygrab-plugin/keygrab-plugin.pro ================================================ CONFIG += qt TEMPLATE = lib DEFINES += KEYGRABPLUGIN_LIBRARY TARGET = thedesk-keygrab # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ keygrabplugin.cpp HEADERS += \ keygrabplugin.h WAYLAND_PROTOCOL_EXTENSIONS += /usr/share/libtdesktopenvironment/wayland-protocols/tdesktopenvironment-keygrab-v1.xml include(../plugins.pri) ================================================ FILE: wayfire-plugins/keygrab-plugin/keygrab-plugin_global.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYGRABPLUGIN_GLOBAL_H #define KEYGRABPLUGIN_GLOBAL_H #include #if defined(KEYGRABPLUGIN_LIBRARY) # define KEYGRABPLUGIN_EXPORT Q_DECL_EXPORT #else # define KEYGRABPLUGIN_EXPORT Q_DECL_IMPORT #endif #endif // KEYGRABPLUGIN_GLOBAL_H ================================================ FILE: wayfire-plugins/keygrab-plugin/keygrabplugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "keygrabplugin.h" #include #include #include #include #include "wayland-tdesktopenvironment-keygrab-v1-server-protocol.h" #include #include struct KeygrabPluginPrivate { wl_resource* tdeKeygrabManager; }; KeygrabPlugin::KeygrabPlugin() { d = new KeygrabPluginPrivate(); } KeygrabPlugin::~KeygrabPlugin() { delete d; } void KeygrabPlugin::grabKey(wl_client* client, uint32_t mod, uint32_t key) { std::cout << "Grabbing key " << key << " mod " << mod << "\n"; wf::get_core().bindings->add_key(wf::create_option(wf::keybinding_t(mod, key)), new wf::key_callback([=](const wf::keybinding_t& keybind) { std::cout << "Pressed " << key << " mod " << mod << "\n"; tdesktopenvironment_keygrab_manager_v1_send_activated(d->tdeKeygrabManager, mod, key, 0); return true; })); } void KeygrabPlugin::ungrabKey(wl_client* client, uint32_t mod, uint32_t key) { } void KeygrabPlugin::init() { wl_global_create(wf::get_core().display, &tdesktopenvironment_keygrab_manager_v1_interface, 1, this, [](wl_client* client, void* data, uint32_t version, uint32_t id) { KeygrabPlugin* plugin = reinterpret_cast(data); plugin->d->tdeKeygrabManager = wl_resource_create(client, &tdesktopenvironment_keygrab_manager_v1_interface, 1, id); struct tdesktopenvironment_keygrab_manager_v1_interface* interface = new struct tdesktopenvironment_keygrab_manager_v1_interface(); interface->grab_key = [](struct wl_client* client, struct wl_resource* resource, uint32_t mod, uint32_t key) { reinterpret_cast(resource->data)->grabKey(client, mod, key); }; interface->ungrab_key = [](struct wl_client* client, struct wl_resource* resource, uint32_t mod, uint32_t key) { reinterpret_cast(resource->data)->ungrabKey(client, mod, key); }; interface->destroy = [](struct wl_client* client, struct wl_resource* resource) { }; wl_resource_set_implementation(plugin->d->tdeKeygrabManager, interface, plugin, nullptr); }); } void KeygrabPlugin::fini() { } bool KeygrabPlugin::is_unloadable() { return false; } ================================================ FILE: wayfire-plugins/keygrab-plugin/keygrabplugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef KEYGRABPLUGIN_H #define KEYGRABPLUGIN_H #include struct wl_client; struct KeygrabPluginPrivate; class KeygrabPlugin : public wf::plugin_interface_t { public: KeygrabPlugin(); ~KeygrabPlugin(); void grabKey(wl_client* client, uint32_t mod, uint32_t key); void ungrabKey(wl_client* client, uint32_t mod, uint32_t key); // plugin_interface_t interface public: void init(); void fini(); bool is_unloadable(); private: KeygrabPluginPrivate* d; }; DECLARE_WAYFIRE_PLUGIN(KeygrabPlugin) #endif // KEYGRABPLUGIN_H ================================================ FILE: wayfire-plugins/plugins.pri ================================================ equals(THELIBS_BUILDTOOLS_PATH, "") { THELIBS_BUILDTOOLS_PATH = $$[QT_INSTALL_PREFIX]/share/the-libs/pri } include($$THELIBS_BUILDTOOLS_PATH/varset.pri) DEFINES += WLR_USE_UNSTABLE WAYFIRE_PLUGIN CONFIG += c++17 plugin CONFIG += link_pkgconfig PKGCONFIG += wayfire wlroots wayland_scanner_headers.output = wayland-${QMAKE_FILE_BASE}-server-protocol.h wayland_scanner_headers.commands = wayland-scanner server-header ${QMAKE_FILE_NAME} ${QMAKE_FILE_OUT} wayland_scanner_headers.input = WAYLAND_PROTOCOL_EXTENSIONS wayland_scanner_headers.CONFIG += target_predeps no_link wayland_scanner_sources.output = wayland-${QMAKE_FILE_BASE}-server-protocol.c wayland_scanner_sources.commands = wayland-scanner private-code ${QMAKE_FILE_NAME} ${QMAKE_FILE_OUT} wayland_scanner_sources.input = WAYLAND_PROTOCOL_EXTENSIONS wayland_scanner_sources.variable_out = SOURCES wayland_scanner_headers.CONFIG += target_predeps no_link QMAKE_EXTRA_COMPILERS += wayland_scanner_headers wayland_scanner_sources target.path = $$THELIBS_INSTALL_LIB/wayfire/ INSTALLS = target ================================================ FILE: wayfire-plugins/startdesk-plugin/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.24.0) project(lib VERSION 1.0.0 LANGUAGES C CXX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) find_package(libcontemporary REQUIRED) cntp_find_pkgconfig(wayfire wayfire) cntp_find_pkgconfig(pixman pixman-1) set(SOURCES startdeskplugin.cpp ) set(HEADERS startdeskplugin.h ) set(PRIVATE_HEADERS ) add_library(wf-thedesk-startdesk SHARED) cntp_init(wf-thedesk-startdesk 20) set_target_properties(wf-thedesk-startdesk PROPERTIES OUTPUT_NAME thedesk-startdesk ) target_link_libraries(wf-thedesk-startdesk Qt::Core libcontemporary PkgConfig::wayfire PkgConfig::pixman) target_compile_definitions(wf-thedesk-startdesk PRIVATE STARTDESKPLUGIN_LIBRARY WLR_USE_UNSTABLE) target_sources(wf-thedesk-startdesk PRIVATE ${SOURCES} ${HEADERS} ${PRIVATE_HEADERS}) install(TARGETS wf-thedesk-startdesk INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/wayfire ) ================================================ FILE: wayfire-plugins/startdesk-plugin/startdesk-plugin.pro ================================================ CONFIG += qt TEMPLATE = lib DEFINES += STARTDESKPLUGIN_LIBRARY TARGET = thedesk-startdesk # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ startdeskplugin.cpp HEADERS += \ startdeskplugin.h include(../plugins.pri) ================================================ FILE: wayfire-plugins/startdesk-plugin/startdeskplugin.cpp ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #include "startdeskplugin.h" #include #include #include #include #include #include StartdeskPlugin::StartdeskPlugin() { } void StartdeskPlugin::init() { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("QT_QPA_PLATFORM", "wayland"); env.insert("WAYLAND_DISPLAY", QString::fromStdString(wf::get_core().wayland_display)); if (qEnvironmentVariableIsSet("T_CHILD_LD_PRELOAD")) { env.insert("T_CHILD_LD_PRELOAD", "/usr/lib/libasan.so"); } QString x11Display = QString::fromStdString(wf::get_core().get_xwayland_display()); if (!x11Display.isEmpty()) { env.insert("DISPLAY", x11Display); } QString startdeskCommand = qEnvironmentVariable("TD_WF_STARTDESK", "startdesk"); QTextStream(stdout) << "Running startdesk command " << startdeskCommand << "\n"; QPointer deskProcess = new QProcess(); deskProcess->setProcessEnvironment(env); deskProcess->start(startdeskCommand, QStringList()); deskProcess->waitForStarted(); QObject::connect(deskProcess.data(), &QProcess::readyReadStandardOutput, [deskProcess] { QTextStream(stdout) << deskProcess->readAllStandardOutput(); }); QObject::connect(deskProcess.data(), &QProcess::readyReadStandardError, [deskProcess] { QTextStream(stderr) << deskProcess->readAllStandardError(); }); QObject::connect(deskProcess.data(), QOverload::of(&QProcess::finished), [=] { QTextStream(stdout) << "Finished!\n"; }); waiter.set_timeout(1000, [=] { if (!deskProcess || deskProcess->waitForFinished(0)) { wf::get_core().shutdown(); return false; } return true; }); } ================================================ FILE: wayfire-plugins/startdesk-plugin/startdeskplugin.h ================================================ /**************************************** * * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE * Copyright (C) 2021 Victor Tran * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *************************************/ #ifndef STARTDESKPLUGIN_H #define STARTDESKPLUGIN_H #include class StartdeskPlugin : public wf::plugin_interface_t { public: StartdeskPlugin(); private: wf::wl_timer waiter; // plugin_interface_t interface public: void init(); }; DECLARE_WAYFIRE_PLUGIN(StartdeskPlugin) #endif // STARTDESKPLUGIN_H ================================================ FILE: wayfire-plugins/wayfire-plugins.pro ================================================ TEMPLATE = subdirs SUBDIRS += \ keygrab-plugin \ startdesk-plugin