├── .gitignore ├── .gitlab-ci.yml ├── Changelog ├── LICENSE ├── README.md ├── ReleaseNotes ├── TODO ├── backgrounds ├── BlurryBlob.png ├── BlurryBlob.svg ├── BurningDesire.svg ├── Camel.Sunset.svg ├── Christmas.svg ├── Hexagons.svg ├── LayeredBlobsDark.svg ├── LayeredBlobsLight.svg ├── Mountains.Sunset.svg ├── Rectangles.svg ├── Rings.svg ├── Sailboats.svg ├── SmoothGradient.png ├── SmoothGradient.svg ├── Squares.svg ├── Sunrise.svg ├── Tree.svg └── Water.svg ├── configs ├── config.ini ├── config.toml ├── greetd ├── sway.cfg ├── users.conf └── wayfire.ini ├── meson.build ├── meson_options.txt ├── screenshots ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg └── 5.jpg ├── scripts ├── postinst └── postrm ├── src ├── Global.hpp ├── Main.cpp ├── QtGreet.qrc ├── backends │ ├── LoginManager.cpp │ ├── LoginManager.hpp │ └── greetd │ │ ├── GreetdManager.cpp │ │ └── GreetdManager.hpp ├── compositor │ ├── main.cpp │ ├── tinywl.c │ └── tinywl.h ├── customlogin │ ├── customlogin.hjson │ └── customlogin.qss ├── icons │ ├── QtGreet.png │ ├── QtGreet.svg │ ├── acpower.png │ ├── arrow-down.png │ ├── arrow-left.png │ ├── arrow-right.png │ ├── battery.png │ ├── edit.png │ ├── hibernate.png │ ├── logout.png │ ├── reboot.png │ ├── session.png │ ├── shutdown.png │ ├── suspend.png │ └── user.png ├── layoutmanager │ ├── CMakeLists.txt │ ├── LayoutManager.cpp │ ├── LayoutManager.hpp │ ├── LayoutUtils.cpp │ ├── LayoutUtils.hpp │ ├── main.cpp │ └── parser │ │ ├── LICENSE │ │ ├── hjson.h │ │ ├── hjson_decode.cpp │ │ ├── hjson_encode.cpp │ │ ├── hjson_parsenumber.cpp │ │ └── hjson_value.cpp ├── protocols │ ├── meson.build │ ├── wlr-layer-shell-unstable-v1.xml │ └── xdg-shell.xml ├── thememanager │ ├── ThemeManager.cpp │ └── ThemeManager.hpp ├── ui │ ├── QtGreet.cpp │ ├── QtGreet.hpp │ ├── ScreenManager.cpp │ └── ScreenManager.hpp └── widgets │ ├── buttons │ ├── buttons.cpp │ └── buttons.hpp │ ├── clock │ ├── ClockWidget.cpp │ └── ClockWidget.hpp │ ├── container │ ├── Container.cpp │ └── Container.hpp │ ├── factory │ ├── WidgetFactory.cpp │ └── WidgetFactory.hpp │ ├── key │ ├── labels │ ├── labels.cpp │ └── labels.hpp │ ├── power │ ├── power.cpp │ └── power.hpp │ ├── session │ ├── session.cpp │ └── session.hpp │ ├── user │ ├── user.cpp │ └── user.hpp │ └── videobg │ ├── MpvHelper.hpp │ ├── MpvWidget.cpp │ └── MpvWidget.hpp └── themes ├── LytMgr.py ├── aerial ├── 4k.m3u ├── all_sd.m3u ├── day.m3u ├── index.theme ├── layout.hjson ├── night.m3u └── style.qss ├── compact ├── index.theme ├── layout.hjson └── style.qss ├── default ├── index.theme ├── layout.hjson └── style.qss └── sidebar ├── index.theme ├── layout.hjson └── style.qss /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .build 3 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | debian_sid_amd64: 2 | stage: build 3 | image: debian:sid 4 | before_script: 5 | - apt-get update -yq 6 | - apt-get install -y g++ git ca-certificates make cmake ninja-build build-essential fakeroot debhelper-compat meson pkg-config 7 | - apt-get install -y cmake qttools5-dev g++ make libarchive-dev liblzma-dev libbz2-dev zlib1g-dev liblz-dev 8 | 9 | script: 10 | - dpkg-buildpackage -rfakeroot -uc -us 11 | - mv ../archiver_2.0.8_amd64.deb ./archiver_2.0.8_sid_amd64.deb 12 | - mv ../libarchiveqt_2.0.8_amd64.deb ./libarchiveqt_2.0.8_sid_amd64.deb 13 | - mv ../libarchiveqt-dev_2.0.8_amd64.deb ./libarchiveqt-dev_2.0.8_sid_amd64.deb 14 | 15 | artifacts: 16 | paths: 17 | - archiver_2.0.8_sid_amd64.deb 18 | - libarchiveqt_2.0.8_sid_amd64.deb 19 | - libarchiveqt-dev_2.0.8_sid_amd64.deb 20 | 21 | debian_testing_amd64: 22 | stage: build 23 | image: debian:testing 24 | before_script: 25 | - apt-get update -yq 26 | - apt-get install -y g++ git ca-certificates make cmake ninja-build build-essential fakeroot debhelper-compat meson pkg-config 27 | - apt-get install -y cmake qttools5-dev g++ make libarchive-dev liblzma-dev libbz2-dev zlib1g-dev liblz-dev 28 | 29 | script: 30 | - dpkg-buildpackage -rfakeroot -uc -us 31 | - mv ../archiver_2.0.8_amd64.deb ./archiver_2.0.8_testing_amd64.deb 32 | - mv ../libarchiveqt_2.0.8_amd64.deb ./libarchiveqt_2.0.8_testing_amd64.deb 33 | - mv ../libarchiveqt-dev_2.0.8_amd64.deb ./libarchiveqt-dev_2.0.8_testing_amd64.deb 34 | 35 | artifacts: 36 | paths: 37 | - archiver_2.0.8_testing_amd64.deb 38 | - libarchiveqt_2.0.8_testing_amd64.deb 39 | - libarchiveqt-dev_2.0.8_testing_amd64.deb 40 | 41 | debian_stable_amd64: 42 | stage: build 43 | image: debian:stable 44 | before_script: 45 | - apt-get update -yq 46 | - apt-get install -y g++ git ca-certificates make cmake ninja-build build-essential fakeroot debhelper-compat meson pkg-config 47 | - apt-get install -y cmake qttools5-dev g++ make libarchive-dev liblzma-dev libbz2-dev zlib1g-dev liblz-dev 48 | 49 | script: 50 | - dpkg-buildpackage -rfakeroot -uc -us 51 | - mv ../archiver_2.0.8_amd64.deb ./archiver_2.0.8_stable_amd64.deb 52 | - mv ../libarchiveqt_2.0.8_amd64.deb ./libarchiveqt_2.0.8_stable_amd64.deb 53 | - mv ../libarchiveqt-dev_2.0.8_amd64.deb ./libarchiveqt-dev_2.0.8_stable_amd64.deb 54 | 55 | artifacts: 56 | paths: 57 | - archiver_2.0.8_stable_amd64.deb 58 | - libarchiveqt_2.0.8_stable_amd64.deb 59 | - libarchiveqt-dev_2.0.8_stable_amd64.deb 60 | -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | Version 2.0.0 2 | - Deprecate the use of layer-shell: not all compositors support it, and we do not require it either. 3 | - Show all windows as full-screens, and place them on various screens using the wlr-foreign-toplevel protocol. 4 | - You can customize the appearance of the greeter to your heart's content using themes. 5 | - Some instructions and config files are provided (see the folder configs) to run QtGreet on wayfire and sway. 6 | - Introducing greetwl - a single screen compositor to display QtGreet. 7 | - Inbuilt support for Suspend, Hibernate, Shutdown and Reboot via (e)logind, using DFL::Login1. 8 | 9 | Version 1.0 10 | - Inital Release 11 | - Some working parts 12 | - Few bugs 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QtGreet 2 | 3 | #### Note: Github is a read-only mirror. You can open PRs and issues at [GitLab](https://gitlab.com/marcusbritanicus/QtGreet.git). 4 | 5 | Qt based greeter for [greetd](https://git.sr.ht/~kennylevinsen/greetd), to be run under wayfire or similar wlr-based compositors. 6 | 7 | Connect with us via [Matrix/IRC](https://app.element.io/#/room/#qtgreet:matrix.org) (#qtgreet:matrix.org) 8 | 9 |

10 |

11 | 12 | 13 | ### Dependencies: 14 | - Qt5 or Qt6 (duh...) 15 | - WayQt (https://gitlab.com/desktop-frameworks/wayqt.git) 16 | - DFL::Applications (https://gitlab.com/desktop-frameworks/applications.git) 17 | - DFL::IPC (https://gitlab.com/desktop-frameworks/ipc.git) 18 | - DFL::Utils (https://gitlab.com/desktop-frameworks/utils.git) 19 | - DFL::Login1 (https://gitlab.com/desktop-frameworks/login1.git) 20 | - wlroots (https://gitlab.freedesktop.org/wlroots/wlroots.git) 21 | - A wayland based compositor (wayfire, sway, labwc etc..) - Optional 22 | - Meson (to build this project) 23 | - Ninja (to compile this project) 24 | 25 | **Note:** wlroots is needed only if you are compiling `greetwl`. If you want to skip the compilation of `greetwl`, 26 | pass `-Dbuild_greetwl=false` to `meson` 27 | 28 | ### Compiling and installing 29 | 30 | - Get the sources of QtGreet 31 | * Git: `git clone https://gitlab.com/marcusbritanicus/QtGreet.git` 32 | - Enter the `QtGreet` folder 33 | * `cd QtGreet` 34 | - Configure the project - we use meson for project management 35 | * `meson .build --prefix=/usr --buildtype=release` 36 | - Compile and install - we use ninja 37 | * `ninja -C .build -k 0 -j $(nproc) && sudo ninja -C .build install` 38 | 39 | ### Configure greetd to run QtGreet 40 | 41 | If you wish to make use of greetd, then you will have to configure it to use QtGreet. 42 | You can either use the *inbuilt* `greetwl` compositor (a fork of `tinywl`), or use a full-fledged compositor like wayfire or sway. 43 | 44 | - To use `greetwl` compositor, 45 | * Open `/etc/greetd/config.toml` for editing with your favorite editor. 46 | * Under `[default_session]`, set `command = "greetwl"` 47 | 48 | - To use wayfire, 49 | * Open `/etc/greetd/config.toml` for editing with your favorite editor. 50 | * Under `[default_session]`, set `command = "wayfire --config /etc/qtgreet/wayfire.ini"` 51 | 52 | - Similarly for sway, 53 | * Open `/etc/greetd/config.toml` for editing with your favorite editor. 54 | * Under `[default_session]`, set `command = "sway --config /etc/qtgreet/sway.cfg"` 55 | 56 | - For labwc, 57 | * Open `/etc/greetd/config.toml` for editing with your favorite editor. 58 | * Under `[default_session]`, set `command = "labwc -s 'qtgreet && wayland-logout'"` 59 | 60 | Most compositors print debug messages to the terminal. You can hide them by redirecting the debug output. Add ` > /dev/null 2>&1` at the end of 61 | each command (ex. `command = "greetwl > /dev/null 2>&1"`). 62 | 63 | Custom login prompt can be activated by pressing `[Ctrl] - [Alt] - [X]` key combination. 64 | 65 | ### CLI Options 66 | Following command-line options are available: 67 | ``` 68 | -h, --help Displays help on commandline options. 69 | -v, --version Displays version information. 70 | -c, --config Configuration file (Default: /etc/qtgreet/config.ini) 71 | -d, --data-path Path to store dynamic data (Default: /var/lib/qtgreet/) 72 | -w, --wl-session-path Path(s) containing wayland session desktops (Default: /usr/share/wayland-sessions) 73 | -x, --x-session-path Path(s) containing x11 session desktops (Default: /usr/share/xsessions) 74 | -p, --passwd-path Path to passwd (Default: /etc/passwd) 75 | -l, --login-defs-path Path to login.defs (Default: /etc/login.defs) 76 | -r, --xserver-path Path to xserverrc (Default: /etc/X11/xinit/xserverrc) 77 | -t, --tmp-path System temp folder (Default: /tmp) 78 | -n, --vt-number VT number where the session is started (Default: 1; applicable for X11 only) 79 | -o, --log-path Path to store log files (Default: /var/tmp/qtgreet) 80 | ``` 81 | 82 | If you're using `greetwl` as the compositor, you can pass these options to `greetwl` which will forward them to `qtgreet`. 83 | 84 | ### Configuring the keyboard layout for wayfire 85 | Sometimes, it would be easier if the keyboard layout was not the default `us`. For wayfire, simply add the following line at the end of 86 | `/etc/qtgreet/wayfire.ini` file: 87 | 88 | ```ini 89 | [input] 90 | xkb_layout = us 91 | ``` 92 | `` 93 | -------------------------------------------------------------------------------- /ReleaseNotes: -------------------------------------------------------------------------------- 1 | Version 2.0 2 | - Deprecate the use of layer-shell: not all compositors support it, and we do not require it either. 3 | - Show all windows as full-screens, and place them on various screens using the wlr-foreign-toplevel protocol. 4 | - You can customize the appearance of the greeter to your heart's content using themes. 5 | - Some instructions and config files are provided (see the folder configs) to run QtGreet on wayfire and sway. 6 | - Introducing greetwl - a single screen compositor to display QtGreet. 7 | - Inbuilt support for Suspend, Hibernate, Shutdown and Reboot via (e)logind, using DFL::Login1. 8 | 9 | Version 1.0 10 | - Wayland sessions run smoothly, Custom sessions can be easily started. 11 | - We still do not have a way to start a new session when an existing session is running. 12 | - We cannot launch an X11 Session. 13 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | QtGreet v2.0.0 2 | 3 | 1. Custom User Icons 4 | We will use ~/.face or ~/.face.icon file to get the user icon failing which we will use the default image. 5 | To make the image have rounded corners use: Use the image as a brush, then draw a rounded rect with no pen. 6 | 7 | 2. QtGreet Widegt Factory 8 | Generate a widget given the name and type. Read the properties, and request the widget to apply the properties by itself. 9 | Following are the list of the widgets: 10 | 1. UserName 11 | 2. SessionName 12 | 3. Password 13 | 4. LoginButton 14 | 5. Date/Time 15 | 6. 16 | 7. 17 | 8. 18 | 9. 19 | 10. 20 | 21 | Every layout.hjson file should contain the first 4 widgets. Without them, you'll not be able to login properly. 22 | 23 | 3. Layout Manager using HJSON 24 | A simple HJSON file with a predefined set of keys will define the layout. We will use QBoxLayout to perform the actual layout of the 25 | widgets. Trials with default and sidebar themes have proved that this method is very effective. 26 | 27 | 4. Decouple GUI from Backends 28 | Currently, the greetd code in integrated with the GUI class. We have to decouple it and use a generic QtGreetBackend class to perform the 29 | various authenticaion/session lauching work. 30 | 31 | 5. Develop Backends 32 | We have to develop two backends, one for QGreetd and the other for LightDM. 33 | 34 | 6. Build a few default themes 35 | Currently, we have the following 4 themes 36 | 1. Default 37 | 2. Aerial 38 | 3. Compact 39 | 4. SideBar 40 | 41 | 7. Write a complete Theme and Layout Guide 42 | 43 | 8. Refactor all the widgets. Currently WidgetFactory applies all the widget properties. Each of the widgets should handle the properties by 44 | themselves. 45 | -------------------------------------------------------------------------------- /backgrounds/BlurryBlob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/backgrounds/BlurryBlob.png -------------------------------------------------------------------------------- /backgrounds/BlurryBlob.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 22 | 26 | 32 | 36 | 37 | 43 | 47 | 53 | 57 | 58 | 64 | 68 | 74 | 78 | 79 | 85 | 89 | 95 | 99 | 100 | 106 | 110 | 116 | 120 | 121 | 127 | 131 | 137 | 141 | 142 | 150 | 154 | 155 | 156 | 175 | 178 | 185 | 192 | 199 | 206 | 213 | 220 | 227 | 228 | 232 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /backgrounds/LayeredBlobsDark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /backgrounds/LayeredBlobsLight.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /backgrounds/SmoothGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/backgrounds/SmoothGradient.png -------------------------------------------------------------------------------- /backgrounds/SmoothGradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /backgrounds/Water.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | image/svg+xml 50 | 51 | 52 | 53 | 54 | Openclipart 55 | 56 | 57 | Abstract Water Wallpaper 58 | 2012-12-17T10:02:29 59 | A large abstract water wallpaper. The size is 1366x768. 60 | https://openclipart.org/detail/173816/abstract-water-wallpaper-by-ali2013-173816 61 | 62 | 63 | ali2013 64 | 65 | 66 | 67 | 68 | Abstract wallpaper 69 | Wallpaper 70 | Wallpaper vector 71 | Wallpaper water 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /configs/config.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | Backend = GreetD 3 | Theme = default 4 | BlurBackground = true 5 | IconTheme = breeze 6 | 7 | [Overrides] 8 | Background = Theme 9 | BaseColor = Theme 10 | TextColor = Theme 11 | FontFamily = Theme 12 | 13 | [Environment] 14 | 15 | [PowerCommands] 16 | Suspend = dbus 17 | Hibernate = dbus 18 | Shutdown = dbus 19 | Reboot = dbus 20 | -------------------------------------------------------------------------------- /configs/config.toml: -------------------------------------------------------------------------------- 1 | [terminal] 2 | # The VT to run the greeter on. Can be "next", "current" or a number 3 | # designating the VT. 4 | vt = 7 5 | 6 | # The default session, also known as the greeter. 7 | [default_session] 8 | command = "dbus-run-session wayfire --config /etc/qtgreet/wayfire.ini > /dev/null 2>&1" 9 | 10 | # The user to run the command as. The privileges this user must have depends 11 | # on the greeter. A graphical greeter may for example require the user to be 12 | # in the `video` group. 13 | user = "greeter" 14 | -------------------------------------------------------------------------------- /configs/greetd: -------------------------------------------------------------------------------- 1 | #%PAM-1.0 2 | 3 | # Block login if they are globally disabled 4 | auth requisite pam_nologin.so 5 | auth required pam_succeed_if.so user != root quiet_success 6 | 7 | # auth sufficient pam_succeed_if.so user ingroup nopasswdlogin 8 | @include common-auth 9 | # gnome_keyring breaks QProcess 10 | auth optional pam_gnome_keyring.so 11 | auth optional pam_kwallet5.so 12 | 13 | @include common-account 14 | 15 | # SELinux needs to be the first session rule. This ensures that any 16 | # lingering context has been cleared. Without this it is possible that a 17 | # module could execute code in the wrong domain. 18 | session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close 19 | # Create a new session keyring. 20 | session optional pam_keyinit.so force revoke 21 | session required pam_limits.so 22 | session required pam_loginuid.so 23 | @include common-session 24 | # SELinux needs to intervene at login time to ensure that the process starts 25 | # in the proper default security context. Only sessions which are intended 26 | # to run in the user's context should be run after this. 27 | session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open 28 | session optional pam_gnome_keyring.so auto_start 29 | session optional pam_kwallet5.so auto_start 30 | 31 | @include common-password 32 | 33 | # From the pam_env man page 34 | # Since setting of PAM environment variables can have side effects to other modules, this module should be the last one on the stack. 35 | 36 | # Load environment from /etc/environment 37 | session required pam_env.so 38 | 39 | # Load environment from /etc/default/locale and ~/.pam_environment 40 | session required pam_env.so envfile=/etc/default/locale user_readenv=1 41 | -------------------------------------------------------------------------------- /configs/sway.cfg: -------------------------------------------------------------------------------- 1 | exec "qtgreet; swaymsg exit" 2 | 3 | bindsym Mod4+shift+e exec swaynag \ 4 | -t warning \ 5 | -m 'What do you want to do?' \ 6 | -b 'Poweroff' 'systemctl poweroff' \ 7 | -b 'Reboot' 'systemctl reboot' 8 | 9 | include /etc/sway/config.d/* 10 | -------------------------------------------------------------------------------- /configs/users.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/configs/users.conf -------------------------------------------------------------------------------- /configs/wayfire.ini: -------------------------------------------------------------------------------- 1 | [autostart] 2 | autostart_wf_shell = false 3 | dm = qtgreet && wayland-logout 4 | 5 | [core] 6 | plugins = autostart 7 | vheight = 1 8 | vwidth = 1 9 | xwayland = false 10 | preferred_decoration_mode = server 11 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'QtGreet', 3 | 'c', 4 | 'cpp', 5 | version: '2.0.0', 6 | license: 'MIT', 7 | meson_version: '>=0.60.0', 8 | default_options: [ 9 | 'cpp_std=c++17', 10 | 'c_std=c11', 11 | 'warning_level=2', 12 | 'werror=false', 13 | ], 14 | ) 15 | 16 | add_global_arguments( '-DPROJECT_VERSION="v@0@"'.format( meson.project_version() ), language : 'cpp' ) 17 | add_project_link_arguments( ['-rdynamic','-fPIC'], language:'cpp' ) 18 | 19 | if get_option( 'nodynpath' ) == false 20 | add_global_arguments( '-DDYNPATH="@0@"'.format( get_option( 'dynpath' ) ), language : 'cpp' ) 21 | else 22 | add_global_arguments( '-DDYNPATH=""', language : 'cpp' ) 23 | endif 24 | 25 | add_global_arguments( '-DLOGPATH="@0@"'.format( get_option( 'logpath' ) ), language : 'cpp' ) 26 | 27 | # If use_qt_version is 'auto', we will first search for Qt6. 28 | # If all Qt6 packages are available, we'll use it. Otherwise, 29 | # we'll switch to Qt5. 30 | if get_option('use_qt_version') == 'auto' 31 | # Check if Qt6 is available 32 | QtDeps = dependency( 'qt6', modules: [ 'Core', 'Gui', 'Widgets', 'DBus', 'OpenGLWidgets' ], required: false ) 33 | wayqt = dependency( 'wayqt-qt6', required: false ) 34 | DFApp = dependency( 'df6application', required: false ) 35 | DFIpc = dependency( 'df6ipc', required: false ) 36 | DFUtl = dependency( 'df6utils', required: false ) 37 | DFLgn = dependency( 'df6login1', required: false ) 38 | 39 | Qt6_is_Found = QtDeps.found() and wayqt.found() and DFApp.found() and DFIpc.found() and DFUtl.found() and DFLgn.found() 40 | 41 | if Qt6_is_Found 42 | Qt = import( 'qt6' ) 43 | 44 | else 45 | QtDeps = dependency( 'qt5', modules: [ 'Core', 'Gui', 'Widgets', 'DBus' ], required: true ) 46 | Qt = import( 'qt5' ) 47 | 48 | wayqt = dependency( 'wayqt', required: true ) 49 | DFApp = dependency( 'df5application', required: true ) 50 | DFIpc = dependency( 'df5ipc', required: true ) 51 | DFUtl = dependency( 'df5utils', required: true ) 52 | DFLgn = dependency( 'df5login1', required: true ) 53 | endif 54 | 55 | # User specifically wants to user Qt5 56 | elif get_option('use_qt_version') == 'qt5' 57 | QtDeps = dependency( 'qt5', modules: [ 'Core', 'Gui', 'Widgets', 'DBus' ], required: true ) 58 | Qt = import( 'qt5' ) 59 | 60 | wayqt = dependency( 'wayqt', required: true ) 61 | DFApp = dependency( 'df5application', required: true ) 62 | DFIpc = dependency( 'df5ipc', required: true ) 63 | DFUtl = dependency( 'df5utils', required: true ) 64 | DFLgn = dependency( 'df5login1', required: true ) 65 | 66 | # User specifically wants to user Qt6 67 | elif get_option('use_qt_version') == 'qt6' 68 | QtDeps = dependency( 'qt6', modules: [ 'Core', 'Gui', 'Widgets', 'DBus', 'OpenGLWidgets' ], required: false ) 69 | Qt = import( 'qt6' ) 70 | 71 | wayqt = dependency( 'wayqt-qt6', required: true ) 72 | DFApp = dependency( 'df6application', required: true ) 73 | DFIpc = dependency( 'df6ipc', required: true ) 74 | DFUtl = dependency( 'df6utils', required: true ) 75 | DFLgn = dependency( 'df6login1', required: true ) 76 | endif 77 | 78 | # MPV for video bg 79 | Mpv = dependency( 'mpv' ) 80 | 81 | Includes = [ 82 | 'src', 83 | 'src/backends', 84 | 'src/backends/greetd', 85 | 'src/layoutmanager', 86 | 'src/layoutmanager/parser', 87 | 'src/thememanager', 88 | 'src/ui', 89 | 'src/widgets', 90 | 'src/widgets/buttons', 91 | 'src/widgets/clock', 92 | 'src/widgets/container', 93 | 'src/widgets/labels', 94 | 'src/widgets/power', 95 | 'src/widgets/session', 96 | 'src/widgets/user', 97 | 'src/widgets/videobg', 98 | 'src/widgets/factory', 99 | ] 100 | 101 | Headers = [ 102 | 'src/Global.hpp', 103 | 'src/backends/LoginManager.hpp', 104 | 'src/backends/greetd/GreetdManager.hpp', 105 | 'src/layoutmanager/parser/hjson.h', 106 | 'src/layoutmanager/LayoutManager.hpp', 107 | 'src/layoutmanager/LayoutUtils.hpp', 108 | 'src/thememanager/ThemeManager.hpp', 109 | 'src/ui/QtGreet.hpp', 110 | 'src/ui/ScreenManager.hpp', 111 | 'src/widgets/factory/WidgetFactory.hpp', 112 | 'src/widgets/buttons/buttons.hpp', 113 | 'src/widgets/clock/ClockWidget.hpp', 114 | 'src/widgets/container/Container.hpp', 115 | 'src/widgets/labels/labels.hpp', 116 | 'src/widgets/power/power.hpp', 117 | 'src/widgets/session/session.hpp', 118 | 'src/widgets/user/user.hpp', 119 | 'src/widgets/videobg/MpvWidget.hpp', 120 | 'src/widgets/videobg/MpvHelper.hpp', 121 | ] 122 | 123 | Sources = [ 124 | 'src/backends/LoginManager.cpp', 125 | 'src/backends/greetd/GreetdManager.cpp', 126 | 'src/layoutmanager/LayoutManager.cpp', 127 | 'src/layoutmanager/LayoutUtils.cpp', 128 | 'src/layoutmanager/parser/hjson_decode.cpp', 129 | 'src/layoutmanager/parser/hjson_encode.cpp', 130 | 'src/layoutmanager/parser/hjson_parsenumber.cpp', 131 | 'src/layoutmanager/parser/hjson_value.cpp', 132 | 'src/thememanager/ThemeManager.cpp', 133 | 'src/Main.cpp', 134 | 'src/ui/QtGreet.cpp', 135 | 'src/ui/ScreenManager.cpp', 136 | 'src/widgets/factory/WidgetFactory.cpp', 137 | 'src/widgets/buttons/buttons.cpp', 138 | 'src/widgets/clock/ClockWidget.cpp', 139 | 'src/widgets/container/Container.cpp', 140 | 'src/widgets/labels/labels.cpp', 141 | 'src/widgets/power/power.cpp', 142 | 'src/widgets/session/session.cpp', 143 | 'src/widgets/user/user.cpp', 144 | 'src/widgets/videobg/MpvWidget.cpp', 145 | ] 146 | 147 | Mocs = Qt.compile_moc( 148 | headers : Headers, 149 | dependencies: QtDeps 150 | ) 151 | 152 | Resources = Qt.compile_resources( 153 | name: 'QtGreetRes', 154 | sources: 'src/QtGreet.qrc' 155 | ) 156 | 157 | qtgreet = executable( 158 | 'qtgreet', [ Sources, Mocs, Resources ], 159 | dependencies: [ QtDeps, wayqt, DFApp, DFIpc, DFUtl, DFLgn, Mpv ], 160 | include_directories: [ Includes ], 161 | install: true 162 | ) 163 | 164 | if ( get_option( 'build_greetwl' ) == true ) 165 | # Required for greetwl 166 | wlr = dependency( 'wlroots', version: '>= 0.17.0' ) 167 | wayland_server = dependency( 'wayland-server' ) 168 | wayland_client = dependency( 'wayland-client' ) 169 | xkbcommon = dependency( 'xkbcommon' ) 170 | rt = meson.get_compiler( 'cpp' ).find_library( 'rt' ) 171 | 172 | subdir( 'src/protocols' ) 173 | 174 | greetwl = executable( 175 | 'greetwl', [ 'src/compositor/main.cpp', 'src/compositor/tinywl.c' ], 176 | dependencies: [ QtDeps, wlr, wayland_server, wayland_client, xkbcommon, rt, protos ], 177 | include_directories: [ 'src/compositor' ], 178 | install: true 179 | ) 180 | endif 181 | 182 | # Backgrounds 183 | install_subdir( 184 | 'backgrounds', 185 | install_dir : get_option( 'datadir' ) / 'qtgreet' 186 | ) 187 | 188 | # Backgrounds 189 | install_subdir( 190 | 'themes', 191 | install_dir : get_option( 'datadir' ) / 'qtgreet' 192 | ) 193 | 194 | # Readme, Changelog, etc 195 | install_data( 196 | [ 'README.md', 'Changelog', 'ReleaseNotes' ], 197 | install_dir : get_option( 'datadir' ) / 'qtgreet' 198 | ) 199 | 200 | # Configuration files 201 | install_data( 202 | [ 'configs/config.ini', 'configs/wayfire.ini', 'configs/users.conf', 'configs/sway.cfg' ], 203 | install_dir : join_paths( get_option( 'sysconfdir' ), 'qtgreet' ) 204 | ) 205 | 206 | # Icons 207 | install_data( 208 | 'src/icons/QtGreet.svg', 209 | install_dir : join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', 'scalable', 'apps'), 210 | ) 211 | 212 | install_data( 213 | 'src/icons/QtGreet.png', 214 | install_dir : join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', '512x512', 'apps'), 215 | ) 216 | 217 | # Configuration file path: create it only if it's not disabled 218 | if get_option( 'nodynpath' ) == false 219 | install_emptydir( 220 | get_option( 'dynpath' ), 221 | install_mode: [ 'rwxr-xr-x', get_option( 'username' ), get_option( 'username' ) ], 222 | ) 223 | endif 224 | 225 | summary = [ 226 | '', 227 | '--------------', 228 | 'QtGreet v@0@'.format( meson.project_version() ), 229 | '--------------', 230 | '' 231 | ] 232 | message( '\n'.join( summary ) ) 233 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'use_qt_version', 3 | type: 'combo', 4 | choices: ['auto', 'qt5', 'qt6'], 5 | value: 'auto', 6 | description: 'Select the Qt version to use' 7 | ) 8 | 9 | option( 10 | 'build_greetwl', 11 | type: 'boolean', 12 | value: true, 13 | description: 'Build greetwl compositor' 14 | ) 15 | 16 | option( 17 | 'dynpath', 18 | type: 'string', 19 | value: '/var/lib/qtgreet', 20 | description: 'Location where dynamic data can be stored', 21 | ) 22 | 23 | option( 24 | 'username', 25 | type: 'string', 26 | value: 'greeter', 27 | description: 'Set the username', 28 | ) 29 | 30 | option( 31 | 'nodynpath', 32 | type: 'boolean', 33 | value: false, 34 | description: 'Don\'t create the dynpath directory', 35 | ) 36 | 37 | option( 38 | 'logpath', 39 | type: 'string', 40 | value: '/var/tmp/qtgreet', 41 | description: 'Location where user session logs can be stored', 42 | ) 43 | -------------------------------------------------------------------------------- /screenshots/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/screenshots/1.jpg -------------------------------------------------------------------------------- /screenshots/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/screenshots/2.jpg -------------------------------------------------------------------------------- /screenshots/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/screenshots/3.jpg -------------------------------------------------------------------------------- /screenshots/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/screenshots/4.jpg -------------------------------------------------------------------------------- /screenshots/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/screenshots/5.jpg -------------------------------------------------------------------------------- /scripts/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | /bin/egrep -i "^greeter:" /etc/passwd 5 | if [ $? -neq 0 ]; then 6 | # Create the system user: greeter 7 | useradd -r -M -G video greeter 8 | fi 9 | 10 | # Create the default 11 | chown -R greeter:greeter /etc/xdg/greetd/ 12 | chown -R greeter:greeter /etc/xdg/qtgreet/ 13 | 14 | # Enable greetd as the display manager - we need it 15 | systemctl enable greetd 16 | -------------------------------------------------------------------------------- /scripts/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Delete the system user: greeter 4 | userdel -d greeter 5 | 6 | # Create the default 7 | rm -rf /etc/greetd/ /etc/qtgreet 8 | rm /etc/systemd/system/greetd.service 9 | 10 | # Enable greetd as the display manager 11 | systemctl disable greetd 12 | -------------------------------------------------------------------------------- /src/Global.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | /** Multiple classes require these */ 28 | extern QSettings *sett; 29 | extern QSettings *users; 30 | 31 | extern QString configPath; 32 | extern QString dynDataPath; 33 | 34 | extern QString wlSessPath; 35 | extern QString xSessPath; 36 | 37 | extern QString passwdPath; 38 | extern QString loginPath; 39 | 40 | extern QString xrcPath; 41 | extern QString tmpPath; 42 | 43 | extern QString vtNum; 44 | extern QString logPath; 45 | 46 | extern QString themeName; 47 | 48 | extern QMap paths; 49 | -------------------------------------------------------------------------------- /src/QtGreet.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icons/arrow-down.png 4 | icons/arrow-left.png 5 | icons/arrow-right.png 6 | icons/session.png 7 | icons/user.png 8 | icons/edit.png 9 | icons/battery.png 10 | icons/acpower.png 11 | icons/shutdown.png 12 | icons/reboot.png 13 | icons/suspend.png 14 | icons/hibernate.png 15 | icons/logout.png 16 | icons/QtGreet.png 17 | 18 | customlogin/customlogin.hjson 19 | customlogin/customlogin.qss 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/backends/LoginManager.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include "LoginManager.hpp" 22 | 23 | LoginManager::LoginManager() { 24 | /** Nothing much */ 25 | } 26 | -------------------------------------------------------------------------------- /src/backends/LoginManager.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include "Global.hpp" 24 | 25 | class LoginManager : public QObject { 26 | Q_OBJECT; 27 | 28 | public: 29 | LoginManager(); 30 | 31 | /** Make an attempt to authenticate the user @user using the password @passwd */ 32 | virtual bool authenticate( QString user, QString passwd ) = 0; 33 | 34 | /** User authentication was successful. Try to start the session */ 35 | virtual bool startSession( QString command, QString type ) = 0; 36 | 37 | /** 38 | * If authenticate/startSession failed, retrieve the error message. 39 | * The error message will be reset if another command is issued. 40 | */ 41 | virtual QString errorMessage() = 0; 42 | }; 43 | -------------------------------------------------------------------------------- /src/backends/greetd/GreetdManager.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include "LoginManager.hpp" 24 | 25 | class Response { 26 | public: 27 | enum Type { 28 | Invalid = 0, /* Response was invalid */ 29 | Success = 1, /* Request was a success */ 30 | Error = 2, /* Request failed */ 31 | AuthMessage = 3, /* Request succeeded, auth required */ 32 | }; 33 | 34 | enum AuthType { 35 | AuthTypeInvalid = 0, /* Not an Authentication Response */ 36 | AuthTypeVisible = 1, /* Authentication in visible form */ 37 | AuthTypeSecret = 2, /* Authentication in secret form */ 38 | AuthTypeInfo = 3, /* Authentication request was Information */ 39 | AuthTypeError = 4, /* Authentication failed */ 40 | }; 41 | 42 | enum ErrorType { 43 | ErrorTypeNone = 0, /* No Error */ 44 | ErrorTypeGeneric = 1, /* Generic error */ 45 | ErrorTypeAuthError = 2, /* Authentication error, typically bad credentials */ 46 | }; 47 | 48 | /** We will be given a json string. Parse it */ 49 | Response( QByteArray ); 50 | 51 | /** Get the response from greetd server */ 52 | Response::Type responseType(); 53 | 54 | /** 55 | * Auth type and message 56 | * If responseType() != Response::Type::AuthMessage, 57 | * authType() will return AuthTypeNone and authMessage() 58 | * will return empty string. 59 | */ 60 | Response::AuthType authType(); 61 | QString authMessage(); 62 | 63 | /** 64 | * Error type and message 65 | * If responseType() != Response::Type::Error, 66 | * errorType() will return ErrorTypeNone and errorMessage() 67 | * will return empty string. 68 | */ 69 | Response::ErrorType errorType(); 70 | QString errorMessage(); 71 | 72 | private: 73 | Response::Type mType = Invalid; 74 | Response::AuthType mAuthType = AuthTypeInvalid; 75 | Response::ErrorType mErrorType = ErrorTypeNone; 76 | 77 | QString mAuthMsg; 78 | QString mErrorMsg; 79 | }; 80 | 81 | class GreetdLogin : public LoginManager { 82 | Q_OBJECT; 83 | 84 | public: 85 | GreetdLogin(); 86 | 87 | virtual bool authenticate( QString user, QString passwd ) override; 88 | virtual bool startSession( QString command, QString type ) override; 89 | virtual QString errorMessage() override; 90 | 91 | private: 92 | /** Send create_session message to greetd-ipc */ 93 | Response createSession( QString username ); 94 | 95 | /** Send post_auth_message_response message to greetd-ipc */ 96 | Response postResponse( QString response = QString() ); 97 | 98 | /** Send start_session message to greetd-ipc */ 99 | Response startSession( QString cmd, QStringList ); 100 | 101 | /** Send cancel_session message to greetd-ipc */ 102 | Response cancelSession(); 103 | 104 | bool connectToServer(); 105 | QByteArray roundtrip( QByteArray ); 106 | 107 | /** Get the X11 Session String */ 108 | QString getX11Session( QString command ); 109 | 110 | /** Prepare the environment variables */ 111 | QStringList prepareEnv(); 112 | 113 | /** GreetD socket FD */ 114 | int mFD = -1; 115 | 116 | /** Error message */ 117 | QString mErrorMsg; 118 | }; 119 | -------------------------------------------------------------------------------- /src/compositor/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | extern "C" { 29 | #include "tinywl.h" 30 | } 31 | 32 | TinyWlServer *server = NULL; 33 | 34 | static const char *COLOR_WARN = "\033[01;33m"; 35 | static const char *COLOR_CRITICAL = "\033[01;31m"; 36 | static const char *COLOR_FATAL = "\033[01;41m"; 37 | static const char *COLOR_RESET = "\033[00;00m"; 38 | 39 | void handleSignals( int signum ) { 40 | switch ( signum ) { 41 | case SIGINT: { 42 | printf( "%sInterrupt signalled.%s\n", COLOR_WARN, COLOR_RESET ); 43 | break; 44 | } 45 | 46 | case SIGTERM: { 47 | printf( "%sPolite term request received.%s\n", COLOR_WARN, COLOR_RESET ); 48 | break; 49 | } 50 | 51 | case SIGQUIT: { 52 | printf( "%sSigQuit received.%s\n", COLOR_WARN, COLOR_RESET ); 53 | break; 54 | } 55 | 56 | default: { 57 | return; 58 | } 59 | } 60 | 61 | printf( "%sClosing down the server.%s\n", COLOR_CRITICAL, COLOR_RESET ); 62 | haltWlEventLoop(); 63 | } 64 | 65 | 66 | static void startQtGreet( int argc, char *argv[] ) { 67 | QCoreApplication app( argc, argv ); 68 | 69 | QProcess *proc = new QProcess(); 70 | 71 | QObject::connect( 72 | proc, &QProcess::readyReadStandardError, [ = ] () { 73 | /** Redirect the stderr of qtgreet to our stderr */ 74 | qDebug() << proc->readAllStandardError().trimmed().data(); 75 | } 76 | ); 77 | 78 | QObject::connect( 79 | proc, &QProcess::readyReadStandardOutput, [ = ] () { 80 | /** Redirect the stdout of qtgreet to our stderr */ 81 | qDebug() << proc->readAllStandardOutput().trimmed().data(); 82 | } 83 | ); 84 | 85 | /** 86 | * Pass the arguments sent to greetwl to qtgreet. 87 | * This way we can quite easily use the cli args of qtgreet while using greetwl 88 | */ 89 | proc->start( "qtgreet", app.arguments().mid( 1 ) ); 90 | proc->waitForFinished( -1 ); 91 | } 92 | 93 | 94 | int main( int argc, char **argv ) { 95 | /** Init TinyWlServer */ 96 | server = new TinyWlServer(); 97 | 98 | /** Start the compositor */ 99 | if ( !startCompositor() ) { 100 | printf( "%sFailed to start TinyWL Compositor%s\n", COLOR_FATAL, COLOR_RESET ); 101 | return -1; 102 | } 103 | 104 | /** Setup the environment variables for Qt to start properly */ 105 | setupEnv(); 106 | 107 | if ( fork() == 0 ) { 108 | startQtGreet( argc, argv ); 109 | 110 | /** Request the parent to shutdown */ 111 | kill( getppid(), SIGTERM ); 112 | } 113 | 114 | signal( SIGINT, handleSignals ); 115 | signal( SIGTERM, handleSignals ); 116 | signal( SIGQUIT, handleSignals ); 117 | 118 | /** Run the wayland event loop instead of QApplication. Will this work? */ 119 | runWlEventLoop(); 120 | 121 | closeCompositor(); 122 | 123 | delete server; 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /src/compositor/tinywl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | enum tinywl_cursor_mode { 28 | TINYWL_CURSOR_PASSTHROUGH, 29 | TINYWL_CURSOR_MOVE, 30 | TINYWL_CURSOR_RESIZE, 31 | }; 32 | 33 | typedef struct tinywl_server { 34 | struct wl_display *display; 35 | struct wlr_backend *backend; 36 | struct wlr_session *session; 37 | struct wlr_renderer *renderer; 38 | struct wlr_allocator *allocator; 39 | struct wlr_scene *scene; 40 | 41 | struct wlr_xdg_shell *xdg_shell; 42 | struct wl_listener new_xdg_surface; 43 | struct wl_list views; 44 | 45 | struct wlr_cursor *cursor; 46 | struct wlr_xcursor_manager *cursor_mgr; 47 | struct wl_listener cursor_motion; 48 | struct wl_listener cursor_motion_absolute; 49 | struct wl_listener cursor_button; 50 | struct wl_listener cursor_axis; 51 | struct wl_listener cursor_frame; 52 | 53 | struct wlr_seat *seat; 54 | struct wl_listener new_input; 55 | struct wl_listener request_cursor; 56 | struct wl_listener request_set_selection; 57 | struct wl_list keyboards; 58 | enum tinywl_cursor_mode cursor_mode; 59 | struct tinywl_view *grabbed_view; 60 | double grab_x, grab_y; 61 | struct wlr_box grab_geobox; 62 | uint32_t resize_edges; 63 | 64 | struct wlr_output_layout *output_layout; 65 | struct wl_list outputs; 66 | struct wl_listener new_output; 67 | } TinyWlServer; 68 | 69 | struct tinywl_output { 70 | struct wl_list link; 71 | struct tinywl_server *server; 72 | struct wlr_output *wlr_output; 73 | struct wl_listener frame; 74 | struct wl_listener destroy; 75 | }; 76 | 77 | struct tinywl_view { 78 | struct wl_list link; 79 | struct tinywl_server *server; 80 | struct wlr_xdg_toplevel *xdg_toplevel; 81 | struct wlr_scene_tree *scene_tree; 82 | struct wl_listener map; 83 | struct wl_listener unmap; 84 | struct wl_listener destroy; 85 | struct wl_listener request_move; 86 | struct wl_listener request_resize; 87 | struct wl_listener request_maximize; 88 | struct wl_listener request_fullscreen; 89 | int x, y; 90 | }; 91 | 92 | struct tinywl_keyboard { 93 | struct wl_list link; 94 | struct tinywl_server *server; 95 | struct wlr_keyboard *wlr_keyboard; 96 | 97 | struct wl_listener modifiers; 98 | struct wl_listener key; 99 | struct wl_listener destroy; 100 | }; 101 | 102 | /** Start the tinywl compositor */ 103 | int startCompositor(); 104 | 105 | /** Start the wayland event loop */ 106 | void runWlEventLoop(); 107 | 108 | /** Halt the wayland event loop */ 109 | void haltWlEventLoop(); 110 | 111 | /** Close compositor: sends the terminate signal */ 112 | void closeCompositor(); 113 | 114 | /** 115 | * Setup the environment to start QtGreet. 116 | * Set XCURSOR_THEME 117 | * Set XCURSOR_SIZE 118 | * Set QT_QPA_PLATFORM 119 | * Set QT_SCALE_FACTOR 120 | */ 121 | void setupEnv(); 122 | 123 | extern TinyWlServer *server; 124 | -------------------------------------------------------------------------------- /src/customlogin/customlogin.hjson: -------------------------------------------------------------------------------- 1 | { 2 | Layout: { 3 | Direction: Vertical 4 | Keys: [ "C1" ] 5 | C1: [ "C2" ] 6 | C2: [ "R1", "R2", "R3", "R4", "Stretch", "R5" ] 7 | R1: [ "QLabel-1", "UserName" ] 8 | R2: [ "QLabel-2", "Password" ] 9 | R3: [ "QLabel-3" ] 10 | R4: [ "QLabel-4", "SessionEdit" ] 11 | R5: [ "Stretch", "Button", "LoginButton" ] 12 | Margins: 0.25 13 | Spacing: 10 14 | } 15 | 16 | Properties: { 17 | C1: { 18 | Height: 1.0 19 | Width: 1.0 20 | BGColor: { 21 | Red: 0.0 22 | Green: 0.0 23 | Blue: 0.0 24 | Alpha: 0.25 25 | } 26 | } 27 | 28 | C2: { 29 | Height: 0.15 30 | Width: 0.3 31 | Margins: 0.05 32 | Spacing: 10 33 | BGColor: { 34 | Red: 0.0 35 | Green: 0.0 36 | Blue: 0.0 37 | Alpha: 0.72 38 | } 39 | } 40 | 41 | R1: { 42 | Height: 36 43 | } 44 | 45 | R2: { 46 | Height: 36 47 | } 48 | 49 | R3: { 50 | Height: 36 51 | } 52 | 53 | R4: { 54 | Height: 36 55 | } 56 | 57 | R5: { 58 | Height: 36 59 | Spacing: 10 60 | } 61 | 62 | QLabel-1: { 63 | Text: "Username:" 64 | } 65 | 66 | QLabel-2: { 67 | Text: "Password:" 68 | } 69 | 70 | QLabel-3: { 71 | Text:
72 | } 73 | 74 | QLabel-4: { 75 | Text: "Session:" 76 | } 77 | 78 | UserName: { 79 | Type: LineEdit 80 | Width: 0.18 81 | Height: 36 82 | TextAlign: Center 83 | }, 84 | 85 | Password: { 86 | Width: 0.18 87 | Height: 36 88 | }, 89 | 90 | Button: { 91 | Width: 36 92 | Height: 36 93 | Type: ToolButton 94 | ObjectName: BackButton 95 | TextAlign: Center 96 | IconSize: 24 97 | ThemeIcon: arrow-left 98 | }, 99 | 100 | LoginButton: { 101 | Width: 150 102 | Height: 36 103 | Type: PushButton 104 | ObjectName: CustomLogin 105 | TextAlign: Center 106 | IconSize: 16 107 | }, 108 | 109 | SessionEdit: { 110 | Width: 0.18 111 | Height: 36 112 | TextAlign: Center 113 | }, 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/customlogin/customlogin.qss: -------------------------------------------------------------------------------- 1 | QWidget { 2 | color: #ffffff; 3 | } 4 | 5 | #CustomLogin { 6 | border: 1px solid gray; 7 | border-radius: 18px; 8 | } 9 | 10 | #CustomLogin:hover { 11 | background-color: rgba(255, 255, 255, 30); 12 | border: 1px solid cornflowerblue; 13 | border-radius: 18px; 14 | } 15 | 16 | #CustomLogin:pressed { 17 | background-color: rgba(255, 255, 255, 10); 18 | padding-top: 1px; 19 | padding-left: 1px; 20 | border: 2px solid cornflowerblue; 21 | border-radius: 18px; 22 | } 23 | 24 | #CustomLogin:focus { 25 | border: 2px solid cornflowerblue; 26 | border-radius: 18px; 27 | } 28 | 29 | #BackButton:focus { 30 | border: 2px solid cornflowerblue; 31 | border-radius: 18px; 32 | } 33 | 34 | #BackButton:hover { 35 | background-color: rgba(255, 255, 255, 30); 36 | border-radius: 18px; 37 | } 38 | 39 | #BackButton:pressed { 40 | background-color: rgba(255, 255, 255, 10); 41 | padding-top: 2px; 42 | padding-left: 2px; 43 | border-radius: 18px; 44 | } 45 | 46 | #CustomLogin:focus { 47 | border: 1px solid cornflowerblue; 48 | border-radius: 18px; 49 | } 50 | 51 | #BackButton { 52 | border: 1px solid gray; 53 | border-radius: 18px; 54 | padding-top: 1px; 55 | padding-left: 1px; 56 | } 57 | 58 | QLineEdit { 59 | background-color: transparent; 60 | border: 1px solid gray; 61 | border-radius: 18px; 62 | padding-left: 10px; 63 | padding-right: 10px; 64 | } 65 | 66 | QLineEdit:focus { 67 | border: 2px solid cornflowerblue; 68 | } 69 | 70 | QLineEdit:edit-focus { 71 | border: 2px solid cornflowerblue; 72 | } 73 | 74 | #OverLay { 75 | background-color: rgba(10, 10, 10, 250); 76 | } 77 | -------------------------------------------------------------------------------- /src/icons/QtGreet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/QtGreet.png -------------------------------------------------------------------------------- /src/icons/acpower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/acpower.png -------------------------------------------------------------------------------- /src/icons/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/arrow-down.png -------------------------------------------------------------------------------- /src/icons/arrow-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/arrow-left.png -------------------------------------------------------------------------------- /src/icons/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/arrow-right.png -------------------------------------------------------------------------------- /src/icons/battery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/battery.png -------------------------------------------------------------------------------- /src/icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/edit.png -------------------------------------------------------------------------------- /src/icons/hibernate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/hibernate.png -------------------------------------------------------------------------------- /src/icons/logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/logout.png -------------------------------------------------------------------------------- /src/icons/reboot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/reboot.png -------------------------------------------------------------------------------- /src/icons/session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/session.png -------------------------------------------------------------------------------- /src/icons/shutdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/shutdown.png -------------------------------------------------------------------------------- /src/icons/suspend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/suspend.png -------------------------------------------------------------------------------- /src/icons/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/QtGreet/35ff6aa1b44e1c3f52b920c619b171bc8a5ee1df/src/icons/user.png -------------------------------------------------------------------------------- /src/layoutmanager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project( LytParser ) 2 | 3 | cmake_minimum_required(VERSION 3.10) 4 | 5 | set( CMAKE_CXX_STANDARD 17 ) 6 | set( CMAKE_INCLUDE_CURRENT_DIR ON ) 7 | set( CMAKE_BUILD_TYPE Release ) 8 | 9 | add_definitions ( -Wall ) 10 | 11 | set( CMAKE_AUTOMOC ON ) 12 | set( CMAKE_AUTORCC ON ) 13 | set( CMAKE_AUTOUIC ON ) 14 | cmake_policy( SET CMP0071 NEW ) 15 | 16 | find_package ( Qt5Widgets REQUIRED ) 17 | find_package ( Qt5Core REQUIRED ) 18 | find_package ( Qt5Gui REQUIRED ) 19 | 20 | include_directories( 21 | parser 22 | ../widgetfactory 23 | ) 24 | 25 | set ( SRCS 26 | ../widgetfactory/WidgetFactory.cpp 27 | ../widgetfactory/WidgetFactory.hpp 28 | parser/hjson_decode.cpp 29 | parser/hjson_encode.cpp 30 | parser/hjson_parsenumber.cpp 31 | parser/hjson_value.cpp 32 | LayoutManager.cpp 33 | LayoutManager.hpp 34 | main.cpp 35 | ) 36 | 37 | add_executable( parser ${SRCS} ) 38 | target_link_libraries( parser Qt5::Core Qt5::Gui Qt5::Widgets ) 39 | -------------------------------------------------------------------------------- /src/layoutmanager/LayoutManager.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include 22 | 23 | #include "LayoutManager.hpp" 24 | #include "WidgetFactory.hpp" 25 | 26 | #include "Container.hpp" 27 | #include "LayoutUtils.hpp" 28 | 29 | QtGreet::LayoutManager::LayoutManager( QScreen *scrn ) { 30 | mScreenSize = scrn->size(); 31 | } 32 | 33 | 34 | QBoxLayout * QtGreet::LayoutManager::generateLayout( QString lytFile ) { 35 | Hjson::Value layout; 36 | 37 | /** Simple hack to load customlogin.hjson */ 38 | if ( lytFile.startsWith( ":/" ) ) { 39 | QFile hjson( lytFile ); 40 | hjson.open( QFile::ReadOnly ); 41 | layout = Hjson::Unmarshal( QString::fromUtf8( hjson.readAll() ).toStdString() ); 42 | hjson.close(); 43 | } 44 | 45 | /** Other files */ 46 | else { 47 | layout = Hjson::UnmarshalFromFile( lytFile.toStdString() ); 48 | } 49 | 50 | mLayout = layout[ "Layout" ]; 51 | mProperties = layout[ "Properties" ]; 52 | 53 | Hjson::Value layoutItems( mLayout[ "Keys" ] ); 54 | 55 | /** Do we have a row? If yes, we will be expanding the size vertically */ 56 | QRegularExpression rows = QRegularExpression( "^R[0-9]+$" ); 57 | 58 | /** Do we have a column? If yes, we will be expanding the size horizontally */ 59 | QRegularExpression cols = QRegularExpression( "^C[0-9]+$" ); 60 | 61 | QBoxLayout *topLyt; 62 | 63 | /** Vertical Layout */ 64 | if ( mLayout[ "Direction" ].to_string() == "Vertical" ) { 65 | topLyt = new QBoxLayout( QBoxLayout::TopToBottom ); 66 | } 67 | 68 | else { 69 | topLyt = new QBoxLayout( QBoxLayout::LeftToRight ); 70 | } 71 | 72 | topLyt->setContentsMargins( getMargins( mLayout[ "Margins" ], mScreenSize ) ); 73 | topLyt->setSpacing( getSpacing( mLayout[ "Spacing" ], mScreenSize ) ); 74 | 75 | topLyt->setGeometry( QRect( QPoint( 0, 0 ), mScreenSize ) ); 76 | 77 | for ( int idx = 0; idx < (int)layoutItems.size(); ++idx ) { 78 | QString key( layoutItems[ idx ].to_string().c_str() ); 79 | 80 | /** Vertical Layout: Each key will lead to new rows */ 81 | if ( rows.match( key ).hasMatch() ) { 82 | Hjson::Value row = mLayout[ key.toUtf8().data() ]; 83 | topLyt->addWidget( addRow( row, key, mProperties[ key.toStdString() ] ) ); 84 | } 85 | 86 | /** Horizontal Layout: Each key will lead to new columns */ 87 | else if ( cols.match( key ).hasMatch() ) { 88 | Hjson::Value col = mLayout[ key.toUtf8().data() ]; 89 | topLyt->addWidget( addColumn( col, key, mProperties[ key.toStdString() ] ) ); 90 | } 91 | 92 | /** Should not have come here */ 93 | else { 94 | return topLyt; 95 | } 96 | } 97 | 98 | return topLyt; 99 | } 100 | 101 | 102 | QWidget * QtGreet::LayoutManager::addRow( Hjson::Value row, QString name, Hjson::Value props ) { 103 | /** Do we have a row? If yes, we will be expanding the size vertically */ 104 | QRegularExpression rows = QRegularExpression( "^R[0-9]+$" ); 105 | /** Do we have a column? If yes, we will be expanding the size horizontally */ 106 | QRegularExpression cols = QRegularExpression( "^C[0-9]+$" ); 107 | 108 | QBoxLayout *lyt = new QBoxLayout( QBoxLayout::LeftToRight ); 109 | 110 | lyt->setContentsMargins( getMargins( props[ "Margins" ], mScreenSize ) ); 111 | lyt->setSpacing( getSpacing( props[ "Spacing" ], mScreenSize ) ); 112 | 113 | double height = getHeight( props[ "Height" ], mScreenSize ); 114 | 115 | if ( height ) { 116 | if ( height < 1.0 ) { 117 | lyt->addStrut( height * mScreenSize.height() ); 118 | } 119 | 120 | else { 121 | lyt->addStrut( (int)height ); 122 | } 123 | } 124 | 125 | for ( int idx = 0; idx < (int)row.size(); ++idx ) { 126 | QString key( row[ idx ].to_string().c_str() ); 127 | Hjson::Value properties( mProperties[ key.toStdString() ] ); 128 | 129 | /** Vertical Layout: Each key will leat to new rows */ 130 | if ( rows.match( key ).hasMatch() ) { 131 | Hjson::Value row = mLayout[ key.toUtf8().data() ]; 132 | lyt->addWidget( addRow( row, key, properties ) ); 133 | } 134 | 135 | /** Horizontal Layout: Each key will leat to new columns */ 136 | else if ( cols.match( key ).hasMatch() ) { 137 | Hjson::Value col = mLayout[ key.toUtf8().data() ]; 138 | lyt->addWidget( addColumn( col, key, properties ) ); 139 | } 140 | 141 | /** Initialize the widget */ 142 | else { 143 | if ( key == "Stretch" ) { 144 | lyt->addStretch(); 145 | continue; 146 | } 147 | 148 | /** We can have multiple widgets with same name (ex: Clock(Time), Clock(Date)) */ 149 | QString widget = key.split( "-" ).at( 0 ); 150 | 151 | QWidget *w = WidgetFactory::createWidget( widget, getType( properties[ "Type" ] ), properties, mScreenSize ); 152 | lyt->addWidget( w, 0, getAlignment( props[ "Alignment" ] ) ); 153 | } 154 | } 155 | 156 | Container *cw = new Container( props[ "BGColor" ], name ); 157 | 158 | cw->setLayout( lyt ); 159 | 160 | return cw; 161 | } 162 | 163 | 164 | QWidget * QtGreet::LayoutManager::addColumn( Hjson::Value col, QString name, Hjson::Value props ) { 165 | /** Do we have a row? If yes, we will be expanding the size vertically */ 166 | QRegularExpression rows = QRegularExpression( "^R[0-9]+$" ); 167 | /** Do we have a column? If yes, we will be expanding the size horizontally */ 168 | QRegularExpression cols = QRegularExpression( "^C[0-9]+$" ); 169 | 170 | QBoxLayout *lyt = new QBoxLayout( QBoxLayout::TopToBottom ); 171 | 172 | lyt->setContentsMargins( getMargins( props[ "Margins" ], mScreenSize ) ); 173 | lyt->setSpacing( getSpacing( props[ "Spacing" ], mScreenSize ) ); 174 | 175 | double width = getWidth( props[ "Width" ], mScreenSize ); 176 | 177 | lyt->addStrut( (int)width ); 178 | 179 | for ( int idx = 0; idx < (int)col.size(); ++idx ) { 180 | QString key( col[ idx ].to_string().c_str() ); 181 | Hjson::Value properties = mProperties[ key.toStdString() ]; 182 | 183 | /** Vertical Layout: Each key will leat to new rows */ 184 | if ( rows.match( key ).hasMatch() ) { 185 | Hjson::Value row = mLayout[ key.toUtf8().data() ]; 186 | lyt->addWidget( addRow( row, key, properties ) ); 187 | } 188 | 189 | /** Horizontal Layout: Each key will leat to new columns */ 190 | else if ( cols.match( key ).hasMatch() ) { 191 | Hjson::Value col = mLayout[ key.toUtf8().data() ]; 192 | lyt->addWidget( addColumn( col, key, properties ) ); 193 | } 194 | 195 | /** Initialize the widget */ 196 | else { 197 | if ( key == "Stretch" ) { 198 | lyt->addStretch(); 199 | continue; 200 | } 201 | 202 | QString widget = key.split( "-" ).at( 0 ); 203 | 204 | QWidget *w = WidgetFactory::createWidget( widget, getType( properties[ "Type" ] ), properties, mScreenSize ); 205 | lyt->addWidget( w, 0, getAlignment( props[ "Alignment" ] ) ); 206 | } 207 | } 208 | 209 | Container *cw = new Container( props[ "BGColor" ], name ); 210 | 211 | cw->setLayout( lyt ); 212 | 213 | return cw; 214 | } 215 | -------------------------------------------------------------------------------- /src/layoutmanager/LayoutManager.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "hjson.h" 28 | 29 | namespace QtGreet { 30 | class LayoutManager; 31 | } 32 | 33 | class QtGreet::LayoutManager { 34 | public: 35 | LayoutManager( QScreen *scrn ); 36 | 37 | QBoxLayout * generateLayout( QString layoutFile ); 38 | 39 | private: 40 | /** Screen size */ 41 | QSize mScreenSize; 42 | 43 | /** Parsed layout file */ 44 | Hjson::Value mLayout; 45 | Hjson::Value mProperties; 46 | 47 | /** Parse the layout */ 48 | void readLayout( Hjson::Value layout ); 49 | 50 | /** Initialize a row and it's widgets */ 51 | QWidget * addRow( Hjson::Value row, QString name, Hjson::Value props ); 52 | 53 | /** Initialize a column and it's widgets */ 54 | QWidget * addColumn( Hjson::Value row, QString name, Hjson::Value props ); 55 | }; 56 | -------------------------------------------------------------------------------- /src/layoutmanager/LayoutUtils.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include 22 | 23 | #include "LayoutUtils.hpp" 24 | #include "WidgetFactory.hpp" 25 | 26 | bool isNumeric( Hjson::Value val ) { 27 | switch ( val.type() ) { 28 | case Hjson::Type::Double: 29 | case Hjson::Type::Int64: { 30 | return true; 31 | } 32 | 33 | default: { 34 | return false; 35 | } 36 | } 37 | 38 | return false; 39 | } 40 | 41 | 42 | QMargins getMargins( Hjson::Value margins, QSize screenSize ) { 43 | if ( margins.empty() or not margins.defined() ) { 44 | return QMargins(); 45 | } 46 | 47 | double left = 0; 48 | double right = 0; 49 | double top = 0; 50 | double bottom = 0; 51 | 52 | if ( isNumeric( margins ) ) { 53 | left = right = top = bottom = margins.to_double(); 54 | } 55 | 56 | else if ( margins.type() == Hjson::Type::Vector ) { 57 | if ( margins.size() < 4 ) { 58 | left = right = top = bottom = margins.to_double(); 59 | } 60 | 61 | else { 62 | left = margins[ 0 ]; 63 | right = margins[ 1 ]; 64 | top = margins[ 2 ]; 65 | bottom = margins[ 3 ]; 66 | } 67 | } 68 | 69 | else { 70 | if ( isNumeric( margins[ "Left" ] ) ) { 71 | left = margins[ "Left" ]; 72 | } 73 | 74 | if ( isNumeric( margins[ "Right" ] ) ) { 75 | right = margins[ "Right" ]; 76 | } 77 | 78 | if ( isNumeric( margins[ "Top" ] ) ) { 79 | top = margins[ "Top" ]; 80 | } 81 | 82 | if ( isNumeric( margins[ "Bottom" ] ) ) { 83 | bottom = margins[ "Bottom" ]; 84 | } 85 | } 86 | 87 | if ( left < 1.0 ) { 88 | left *= screenSize.width(); 89 | } 90 | 91 | if ( right < 1.0 ) { 92 | right *= screenSize.width(); 93 | } 94 | 95 | if ( top < 1.0 ) { 96 | top *= screenSize.height(); 97 | } 98 | 99 | if ( bottom < 1.0 ) { 100 | bottom *= screenSize.height(); 101 | } 102 | 103 | return QMargins( left, top, right, bottom ); 104 | } 105 | 106 | 107 | int getSpacing( Hjson::Value value, QSize ) { 108 | if ( value.empty() or not value.defined() ) { 109 | return 0; 110 | } 111 | 112 | if ( value.type() != Hjson::Type::Int64 ) { 113 | return 0; 114 | } 115 | 116 | return value.to_int64(); 117 | } 118 | 119 | 120 | Qt::Alignment getAlignment( Hjson::Value value ) { 121 | QString align( value.to_string().c_str() ); 122 | Qt::Alignment XX; 123 | 124 | /** We'll manage the alignment externally */ 125 | if ( align.isEmpty() ) { 126 | return XX; 127 | } 128 | 129 | if ( align.at( 0 ) == QChar( 'T' ) ) { 130 | XX = Qt::AlignTop; 131 | } 132 | 133 | else if ( align.at( 0 ) == QChar( 'M' ) ) { 134 | XX = Qt::AlignVCenter; 135 | } 136 | 137 | else if ( align.at( 0 ) == QChar( 'B' ) ) { 138 | XX = Qt::AlignBottom; 139 | } 140 | 141 | if ( align.size() == 2 ) { 142 | if ( align.at( 1 ) == QChar( 'L' ) ) { 143 | XX |= Qt::AlignLeft; 144 | } 145 | 146 | else if ( align.at( 1 ) == QChar( 'M' ) ) { 147 | XX |= Qt::AlignHCenter; 148 | } 149 | 150 | else if ( align.at( 1 ) == QChar( 'R' ) ) { 151 | XX |= Qt::AlignRight; 152 | } 153 | } 154 | 155 | else { 156 | XX |= Qt::AlignLeft; 157 | } 158 | 159 | return XX; 160 | } 161 | 162 | 163 | int getWidth( Hjson::Value obj, QSize screenSize ) { 164 | double width = obj.to_double(); 165 | 166 | if ( width <= 1.0 ) { 167 | width *= screenSize.width(); 168 | } 169 | 170 | if ( width < 0 ) { 171 | width = 0; 172 | } 173 | 174 | return (int)width; 175 | } 176 | 177 | 178 | int getHeight( Hjson::Value obj, QSize screenSize ) { 179 | double height = obj.to_double(); 180 | 181 | if ( height <= 1.0 ) { 182 | height *= screenSize.height(); 183 | } 184 | 185 | if ( height < 0 ) { 186 | height = 0; 187 | } 188 | 189 | return (int)height; 190 | } 191 | 192 | 193 | QString getType( Hjson::Value type ) { 194 | return type.to_string().c_str(); 195 | } 196 | 197 | 198 | QFont::Weight getFontWeight( Hjson::Value weight ) { 199 | if ( weight.type() == Hjson::Type::String ) { 200 | std::string w( weight ); 201 | 202 | if ( w == "Thin" ) { 203 | return QFont::Thin; 204 | } 205 | 206 | else if ( w == "ExtraLight" ) { 207 | return QFont::ExtraLight; 208 | } 209 | 210 | else if ( w == "Light" ) { 211 | return QFont::Light; 212 | } 213 | 214 | else if ( w == "Normal" ) { 215 | return QFont::Normal; 216 | } 217 | 218 | else if ( w == "Medium" ) { 219 | return QFont::Medium; 220 | } 221 | 222 | else if ( w == "DemiBold" ) { 223 | return QFont::DemiBold; 224 | } 225 | 226 | else if ( w == "Bold" ) { 227 | return QFont::Bold; 228 | } 229 | 230 | else if ( w == "ExtraBold" ) { 231 | return QFont::ExtraBold; 232 | } 233 | 234 | else if ( w == "Black" ) { 235 | return QFont::Black; 236 | } 237 | 238 | else { 239 | return QFont::Normal; 240 | } 241 | } 242 | 243 | else if ( weight.type() == Hjson::Type::Int64 ) { 244 | int w( weight ); 245 | 246 | if ( w >= 87 ) { 247 | return QFont::Black; 248 | } 249 | 250 | else if ( w >= 81 ) { 251 | return QFont::ExtraBold; 252 | } 253 | 254 | else if ( w >= 75 ) { 255 | return QFont::Bold; 256 | } 257 | 258 | else if ( w >= 63 ) { 259 | return QFont::DemiBold; 260 | } 261 | 262 | else if ( w >= 57 ) { 263 | return QFont::Medium; 264 | } 265 | 266 | else if ( w >= 50 ) { 267 | return QFont::Normal; 268 | } 269 | 270 | else if ( w >= 25 ) { 271 | return QFont::Light; 272 | } 273 | 274 | else if ( w >= 12 ) { 275 | return QFont::ExtraLight; 276 | } 277 | 278 | else { 279 | return QFont::Thin; 280 | } 281 | } 282 | 283 | return QFont::Normal; 284 | } 285 | -------------------------------------------------------------------------------- /src/layoutmanager/LayoutUtils.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include "Global.hpp" 22 | #include "hjson.h" 23 | 24 | /** Check if the Hjson value is numeric */ 25 | bool isNumeric( Hjson::Value val ); 26 | 27 | /** Convert Hjson::Value to QMargins */ 28 | QMargins getMargins( Hjson::Value margins, QSize screenSize ); 29 | 30 | /** Convert Hjson::Value to int */ 31 | int getSpacing( Hjson::Value spacing, QSize screenSize ); 32 | 33 | /** Convert two-char alignment value to Qt::Alignment */ 34 | Qt::Alignment getAlignment( Hjson::Value obj ); 35 | 36 | /** Convert Hjson::Value to width */ 37 | int getWidth( Hjson::Value obj, QSize screenSize ); 38 | 39 | /** Convert Hjson::Value to height */ 40 | int getHeight( Hjson::Value obj, QSize screenSize ); 41 | 42 | /** Get the widget type */ 43 | QString getType( Hjson::Value type ); 44 | 45 | /** Get the font weigth from string/number */ 46 | QFont::Weight getFontWeight( Hjson::Value weight ); 47 | -------------------------------------------------------------------------------- /src/layoutmanager/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "LayoutManager.hpp" 3 | 4 | int main( int argc, char *argv[] ) { 5 | QApplication app( argc, argv ); 6 | 7 | QtGreet::Layout *lyt = new QtGreet::Layout(); 8 | 9 | lyt->generateLayout( argv[ 1 ] ); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /src/layoutmanager/parser/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016, 2017 Christian Zangl, Fredrik Trobro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/layoutmanager/parser/hjson_parsenumber.cpp: -------------------------------------------------------------------------------- 1 | #include "hjson.h" 2 | #include 3 | #if HJSON_USE_CHARCONV 4 | # include 5 | #elif HJSON_USE_STRTOD 6 | # include 7 | # include 8 | #else 9 | # include 10 | #endif 11 | 12 | 13 | namespace Hjson { 14 | struct Parser { 15 | const unsigned char *data; 16 | size_t dataSize; 17 | int at; 18 | unsigned char ch; 19 | }; 20 | 21 | 22 | static bool _parseFloat( double *pNumber, const char *pCh, size_t nCh ) { 23 | #if HJSON_USE_CHARCONV 24 | auto res = std::from_chars( pCh, pCh + nCh, *pNumber ); 25 | 26 | return res.ptr == pCh + nCh && res.ec != std::errc::result_out_of_range && 27 | !std::isinf( *pNumber ) && !std::isnan( *pNumber ); 28 | 29 | #elif HJSON_USE_STRTOD 30 | char *endptr; 31 | errno = 0; 32 | *pNumber = std::strtod( pCh, &endptr ); 33 | 34 | return !errno && endptr - pCh == nCh && !std::isinf( *pNumber ) && !std::isnan( *pNumber ); 35 | 36 | #else 37 | std::string str( pCh, nCh ); 38 | std::stringstream ss( str ); 39 | 40 | // Make sure we expect dot (not comma) as decimal point. 41 | ss.imbue( std::locale::classic() ); 42 | 43 | ss >> *pNumber; 44 | 45 | return ss.eof() && !ss.fail() && !std::isinf( *pNumber ) && !std::isnan( *pNumber ); 46 | 47 | #endif 48 | } 49 | 50 | 51 | static bool _parseInt( std::int64_t *pNumber, const char *pCh, size_t nCh ) { 52 | #if HJSON_USE_CHARCONV 53 | auto res = std::from_chars( pCh, pCh + nCh, *pNumber ); 54 | 55 | return res.ptr == pCh + nCh && res.ec != std::errc::result_out_of_range; 56 | 57 | #elif HJSON_USE_STRTOD 58 | char *endptr; 59 | errno = 0; 60 | *pNumber = std::strtoll( pCh, &endptr, 0 ); 61 | 62 | return !errno && endptr - pCh == nCh; 63 | 64 | #else 65 | std::string str( pCh, nCh ); 66 | std::stringstream ss( str ); 67 | 68 | // Avoid localization surprises. 69 | ss.imbue( std::locale::classic() ); 70 | 71 | ss >> *pNumber; 72 | 73 | return ss.eof() && !ss.fail(); 74 | 75 | #endif 76 | } 77 | 78 | 79 | static bool _next( Parser *p ) { 80 | // get the next character. 81 | if ( (size_t)p->at < p->dataSize ) { 82 | p->ch = p->data[ p->at++ ]; 83 | return true; 84 | } 85 | 86 | if ( (size_t)p->at == p->dataSize ) { 87 | p->at++; 88 | p->ch = 0; 89 | } 90 | 91 | return false; 92 | } 93 | 94 | 95 | // Parse a number value. The parameter "text" must be zero terminated. 96 | bool tryParseNumber( Value *pValue, const char *text, size_t textSize, bool stopAtNext ) { 97 | Parser p = { 98 | (const unsigned char *)text, 99 | textSize, 100 | 0, 101 | ' ' 102 | }; 103 | 104 | int leadingZeros = 0; 105 | bool testLeading = true; 106 | 107 | _next( &p ); 108 | 109 | if ( p.ch == '-' ) { 110 | _next( &p ); 111 | } 112 | 113 | while ( p.ch >= '0' && p.ch <= '9' ) { 114 | if ( testLeading ) { 115 | if ( p.ch == '0' ) { 116 | leadingZeros++; 117 | } 118 | else { 119 | testLeading = false; 120 | } 121 | } 122 | 123 | _next( &p ); 124 | } 125 | 126 | if ( testLeading ) { 127 | leadingZeros--; 128 | } // single 0 is allowed 129 | 130 | if ( p.ch == '.' ) { 131 | while ( _next( &p ) && p.ch >= '0' && p.ch <= '9' ) { 132 | } 133 | } 134 | 135 | if ( (p.ch == 'e') || (p.ch == 'E') ) { 136 | _next( &p ); 137 | 138 | if ( (p.ch == '-') || (p.ch == '+') ) { 139 | _next( &p ); 140 | } 141 | 142 | while ( p.ch >= '0' && p.ch <= '9' ) { 143 | _next( &p ); 144 | } 145 | } 146 | 147 | auto end = p.at; 148 | 149 | // skip white/to (newline) 150 | while ( p.ch > 0 && p.ch <= ' ' ) { 151 | _next( &p ); 152 | } 153 | 154 | if ( stopAtNext ) { 155 | // end scan if we find a punctuator character like ,}] or a comment 156 | if ( (p.ch == ',') || (p.ch == '}') || (p.ch == ']') || 157 | (p.ch == '#') || ( (p.ch == '/') && ( (p.data[ p.at ] == '/') || (p.data[ p.at ] == '*') ) ) ) { 158 | p.ch = 0; 159 | } 160 | } 161 | 162 | if ( (p.ch > 0) || (leadingZeros != 0) ) { 163 | // Invalid number. 164 | return false; 165 | } 166 | 167 | std::int64_t i; 168 | 169 | if ( _parseInt( &i, (char *)p.data, end - 1 ) ) { 170 | *pValue = Value( i ); 171 | return true; 172 | } 173 | else { 174 | double d; 175 | 176 | if ( _parseFloat( &d, (char *)p.data, end - 1 ) ) { 177 | *pValue = Value( d ); 178 | return true; 179 | } 180 | } 181 | 182 | return false; 183 | } 184 | 185 | 186 | bool startsWithNumber( const char *text, size_t textSize ) { 187 | Value number; 188 | 189 | return tryParseNumber( &number, text, textSize, true ); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/protocols/meson.build: -------------------------------------------------------------------------------- 1 | wayland_scanner = find_program( 'wayland-scanner' ) 2 | 3 | wayland_scanner_code = generator( 4 | wayland_scanner, 5 | output: '@BASENAME@-protocol.c', 6 | arguments: ['private-code', '@INPUT@', '@OUTPUT@'], 7 | ) 8 | 9 | wayland_scanner_server = generator( 10 | wayland_scanner, 11 | output: '@BASENAME@-protocol.h', 12 | arguments: ['server-header', '@INPUT@', '@OUTPUT@'], 13 | ) 14 | 15 | protocols = [ 16 | 'xdg-shell.xml', 17 | ] 18 | 19 | wl_protos_src = [] 20 | wl_protos_headers = [] 21 | 22 | foreach p : protocols 23 | xml = join_paths( p ) 24 | wl_protos_src += wayland_scanner_code.process( xml ) 25 | wl_protos_headers += wayland_scanner_server.process( xml ) 26 | endforeach 27 | 28 | lib_wl_protos = static_library( 29 | 'wl_protos', wl_protos_src + wl_protos_headers, 30 | dependencies: [wayland_client], 31 | ) # for the include directory 32 | 33 | protos = declare_dependency( 34 | link_with: lib_wl_protos, 35 | sources: wl_protos_headers, 36 | ) 37 | -------------------------------------------------------------------------------- /src/thememanager/ThemeManager.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | // Local Headers 22 | #include "ThemeManager.hpp" 23 | 24 | static QStringList themePaths = QStandardPaths::locateAll( QStandardPaths::GenericDataLocation, "qtgreet/themes", QStandardPaths::LocateDirectory ); 25 | 26 | QtGreet::ThemeManager::ThemeManager( QString themeName ) { 27 | /** Read the env variable: QTGREET_THEME_DIRS */ 28 | for ( QString themeDir: qEnvironmentVariable( "QTGREET_THEME_DIRS" ).split( ":" ) ) { 29 | if ( not themePaths.contains( QDir( themeDir ).path() ) ) { 30 | themePaths << themeDir; 31 | } 32 | } 33 | 34 | /** If this theme does not exist, use the 'default' theme */ 35 | if ( not availableThemes().contains( themeName ) ) { 36 | themeName = "default"; 37 | } 38 | 39 | readTheme( themeName ); 40 | } 41 | 42 | 43 | QString QtGreet::ThemeManager::getLayout() { 44 | return mLayout; 45 | } 46 | 47 | 48 | QString QtGreet::ThemeManager::getStyleSheet() { 49 | QFile qss( mQSS ); 50 | 51 | qss.open( QFile::ReadOnly ); 52 | QString ss = QString::fromLocal8Bit( qss.readAll() ); 53 | 54 | qss.close(); 55 | 56 | return ss; 57 | } 58 | 59 | 60 | QString QtGreet::ThemeManager::background() { 61 | return imageBG; 62 | } 63 | 64 | 65 | bool QtGreet::ThemeManager::isVideoBG() { 66 | return mIsVideoBG; 67 | } 68 | 69 | 70 | QString QtGreet::ThemeManager::video() { 71 | return videoBG; 72 | } 73 | 74 | 75 | QStringList QtGreet::ThemeManager::availableThemes() { 76 | QStringList themes; 77 | 78 | for ( QString path: themePaths ) { 79 | QDirIterator dirIt( path, QStringList(), QDir::Dirs | QDir::NoDotAndDotDot ); 80 | while ( dirIt.hasNext() ) { 81 | dirIt.next(); 82 | 83 | if ( QFile::exists( dirIt.filePath() + "/index.theme" ) ) { 84 | themes << dirIt.fileName(); 85 | } 86 | } 87 | } 88 | 89 | return themes; 90 | } 91 | 92 | 93 | void QtGreet::ThemeManager::readTheme( QString name ) { 94 | QString themePath; 95 | 96 | for ( QString path: themePaths ) { 97 | if ( QFile::exists( path + "/" + name ) ) { 98 | themePath = path + "/" + name + "/"; 99 | break; 100 | } 101 | } 102 | 103 | QSettings theme( themePath + "/index.theme", QSettings::IniFormat ); 104 | 105 | mIsVideoBG = theme.value( "Theme/Type" ).toString() == "Video"; 106 | mLayout = themePath + theme.value( "Files/Layout" ).toString(); 107 | mQSS = themePath + theme.value( "Files/StyleSheet" ).toString(); 108 | 109 | if ( mIsVideoBG == false ) { 110 | imageBG = QDir( themePath ).filePath( theme.value( "Theme/Background" ).toString() ); 111 | } 112 | 113 | else { 114 | if ( theme.value( "videobg/File" ).toString().length() ) { 115 | videoBG = QDir( themePath ).filePath( theme.value( "videobg/File" ).toString() ); 116 | } 117 | 118 | else if ( theme.value( "videobg/Playlist" ).toString().length() ) { 119 | videoBG = QDir( themePath ).filePath( theme.value( "videobg/Playlist" ).toString() ); 120 | } 121 | } 122 | 123 | mBaseColor = QColor( QString( "#%1" ).arg( theme.value( "Theme/BaseColor" ).toString() ) ); 124 | mTextColor = QColor( QString( "#%1" ).arg( theme.value( "Theme/TextColor" ).toString() ) ); 125 | 126 | /** Overrides: image */ 127 | QString background = sett->value( "Overrides/Background", "Theme" ).toString(); 128 | 129 | if ( background != "Theme" ) { 130 | imageBG = background; 131 | } 132 | 133 | /** Overrides: video */ 134 | if ( sett->value( "videobg/File" ).toString().length() ) { 135 | videoBG = QDir( themePath ).filePath( sett->value( "videobg/File" ).toString() ); 136 | } 137 | 138 | else if ( sett->value( "videobg/Playlist" ).toString().length() ) { 139 | videoBG = QDir( themePath ).filePath( sett->value( "videobg/Playlist" ).toString() ); 140 | } 141 | 142 | QString baseColor = sett->value( "Overrides/BaseColor", "Theme" ).toString(); 143 | 144 | if ( baseColor != "Theme" ) { 145 | mBaseColor = QColor( QString( "#%1" ).arg( baseColor ) ); 146 | } 147 | 148 | QString textColor = sett->value( "Overrides/TextColor", "Theme" ).toString(); 149 | 150 | if ( textColor != "Theme" ) { 151 | mTextColor = QColor( QString( "#%1" ).arg( textColor ) ); 152 | } 153 | 154 | qDebug() << videoBG; 155 | } 156 | -------------------------------------------------------------------------------- /src/thememanager/ThemeManager.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include "Global.hpp" 24 | 25 | namespace QtGreet { 26 | class ThemeManager; 27 | } 28 | 29 | class QtGreet::ThemeManager { 30 | public: 31 | ThemeManager( QString themeName ); 32 | 33 | /** Get the layout path */ 34 | QString getLayout(); 35 | 36 | /** Get the stylesheet path */ 37 | QString getStyleSheet(); 38 | 39 | /** Path to background image/video */ 40 | QString background(); 41 | 42 | /** Base Color */ 43 | QColor baseColor(); 44 | 45 | /** Base Color */ 46 | QColor textColor(); 47 | 48 | /** Does the theme require video bg? */ 49 | bool isVideoBG(); 50 | 51 | /** Does the theme require video bg? */ 52 | QString video(); 53 | 54 | /** All the available themes */ 55 | static QStringList availableThemes(); 56 | 57 | private: 58 | void readTheme( QString ); 59 | 60 | QString imageBG; 61 | QString videoBG; 62 | QString mLayout; 63 | QString mQSS; 64 | bool mIsVideoBG; 65 | 66 | QColor mBaseColor; 67 | QColor mTextColor; 68 | }; 69 | -------------------------------------------------------------------------------- /src/ui/QtGreet.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include "Global.hpp" 24 | #include "user.hpp" 25 | #include "session.hpp" 26 | 27 | #include 28 | 29 | class LoginManager; 30 | 31 | namespace QtGreet { 32 | class UI; 33 | class LayoutManager; 34 | class ThemeManager; 35 | } 36 | 37 | class QtGreet::UI : public QMainWindow { 38 | Q_OBJECT; 39 | 40 | public: 41 | UI( QScreen *scrn ); 42 | ~UI(); 43 | 44 | private: 45 | /* Create UI */ 46 | void createUI(); 47 | 48 | /* Prepare first use */ 49 | void prepareUIforUse(); 50 | 51 | /* Update the username on the screen */ 52 | void updateUser( User ); 53 | 54 | /* Update the session on the screen */ 55 | void updateSession( uint ); 56 | 57 | /* Show the validating message */ 58 | void showValidating(); 59 | 60 | /* Show the validating message */ 61 | void showCustomLogin(); 62 | 63 | /* Show the power message */ 64 | void showPowerMessage( bool reboot, bool done ); 65 | 66 | User mCurUser; 67 | Session mCurSession; 68 | 69 | /* Background image */ 70 | QImage background; 71 | 72 | /* QtGreet theme manager, and layout manager */ 73 | QtGreet::ThemeManager *themeMgr; 74 | QtGreet::LayoutManager *lytMgr; 75 | 76 | /* Base to show multiple widgets */ 77 | QStackedWidget *base = nullptr; 78 | 79 | /* Login manager backend */ 80 | LoginManager *login; 81 | 82 | /* Login1 backend */ 83 | DFL::Login1 *login1; 84 | 85 | /* Validation message */ 86 | QLabel *validating; 87 | QWidget *cLogin = nullptr; 88 | 89 | /* The screen on which this will be shown */ 90 | QScreen *mScreen; 91 | 92 | protected: 93 | /** Draw background image */ 94 | void paintEvent( QPaintEvent *pEvent ); 95 | 96 | /** To detect Caps/Num lock */ 97 | void keyPressEvent( QKeyEvent *kEvent ); 98 | 99 | private Q_SLOTS: 100 | // Try to login: If successful, store the username/userid and the session path. 101 | void tryLogin(); 102 | 103 | // Try to login using values from Custom Login widget. 104 | void tryCustomLogin(); 105 | 106 | // ComboBox 107 | void on_UserEdit_textEdited( QString ); 108 | 109 | // ComboBox 110 | void on_UserCombo_currentIndexChanged( int ); 111 | 112 | // ListWidget 113 | void on_UserList_currentItemChanged( QListWidgetItem *, QListWidgetItem * ); 114 | 115 | // UserNavButton - Right - Next User 116 | void on_UserNavRight_clicked(); 117 | 118 | // UserNavButton - Left - Previous User 119 | void on_UserNavLeft_clicked(); 120 | 121 | // SessionNavButton - Right - Next User 122 | void on_SessionNavRight_clicked(); 123 | 124 | // SessionNavButton - Left - Previous User 125 | void on_SessionNavLeft_clicked(); 126 | 127 | // SessionEditButton - Convert the SessionEdit from ReadOnly to ReadWrite 128 | void on_SessionEditButton_clicked(); 129 | 130 | // LoginButton - ToolButton and PushButton - Perform the login: tryLogin() 131 | void on_LoginButton_clicked(); 132 | 133 | // Password - Return pressed - Perform the login: tryLogin() 134 | void on_Password_returnPressed(); 135 | 136 | // SessionEdit - Return pressed - Perform the login: tryLogin() 137 | void on_SessionEdit_returnPressed(); 138 | 139 | // ComboBox 140 | void on_SessionCombo_currentIndexChanged( int ); 141 | 142 | // ListWidget 143 | void on_SessionList_currentItemChanged( QListWidgetItem *, QListWidgetItem * ); 144 | 145 | // PowerButton/Reboot/Halt/Suspend/Hibernate 146 | void on_PowerButton_suspend(); 147 | void on_PowerButton_hibernate(); 148 | void on_PowerButton_shutdown( bool ); 149 | void on_PowerButton_reboot( bool ); 150 | void on_Suspend_suspend(); 151 | void on_Hibernate_hibernate(); 152 | void on_Halt_shutdown( bool ); 153 | void on_Reboot_reboot( bool ); 154 | }; 155 | -------------------------------------------------------------------------------- /src/ui/ScreenManager.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include "QtGreet.hpp" 22 | #include "ScreenManager.hpp" 23 | 24 | #include 25 | 26 | QtGreet::ScreenManager::ScreenManager() { 27 | /** All the screens are currently "available", since none of them have been used */ 28 | QList availScrns = qApp->screens(); 29 | 30 | /** Let's now start creating instances of QtGreet for each of the available screens */ 31 | for ( QScreen *scrn: availScrns ) { 32 | QtGreet::UI *ui = new QtGreet::UI( scrn ); 33 | 34 | /** Map the screento the greeter */ 35 | screenGreeterMap[ scrn ] = ui; 36 | 37 | /** Map the UI to the screen */ 38 | greeterScreenMap[ ui->windowTitle() ] = scrn; 39 | } 40 | 41 | /** Create a new instance when a screen is added */ 42 | connect( 43 | qApp, &QApplication::screenAdded, [ = ] ( QScreen *scrn ) mutable { 44 | QtGreet::UI *ui = new QtGreet::UI( scrn ); 45 | 46 | /** Map the screento the greeter */ 47 | screenGreeterMap[ scrn ] = ui; 48 | 49 | /** Map the UI to the screen */ 50 | greeterScreenMap[ ui->windowTitle() ] = scrn; 51 | 52 | /** Show the greeter */ 53 | ui->showFullScreen(); 54 | 55 | /** Wait for Qt to process the pending events */ 56 | qApp->processEvents(); 57 | 58 | /** Sleep for 10 ms */ 59 | usleep( 10 * 1000 ); 60 | } 61 | ); 62 | 63 | /** Remove the existing instance when a screen is removed */ 64 | connect( 65 | qApp, &QApplication::screenRemoved, [ = ] ( QScreen *scrn ) mutable { 66 | QString instance = QString( "QtGreet-%1-%2x%3" ).arg( scrn->name() ).arg( scrn->size().width() ).arg( scrn->size().height() ); 67 | 68 | greeterScreenMap.remove( instance ); 69 | QtGreet::UI *ui = screenGreeterMap.take( scrn ); 70 | ui->close(); 71 | 72 | delete ui; 73 | } 74 | ); 75 | } 76 | 77 | 78 | void QtGreet::ScreenManager::showInstacnes() { 79 | /** Show each of the greeters, force Qt to process the event queue, sleep of 10 ms */ 80 | for ( QtGreet::UI *ui: screenGreeterMap.values() ) { 81 | /** Show the greeter */ 82 | ui->showFullScreen(); 83 | 84 | /** Wait for Qt to process the pending events */ 85 | qApp->processEvents(); 86 | 87 | /** Sleep for 10 ms */ 88 | usleep( 10 * 1000 ); 89 | } 90 | } 91 | 92 | 93 | QScreen * QtGreet::ScreenManager::screenForWindow( QString title ) { 94 | if ( greeterScreenMap.contains( title ) ) { 95 | return greeterScreenMap[ title ]; 96 | } 97 | 98 | return nullptr; 99 | } 100 | -------------------------------------------------------------------------------- /src/ui/ScreenManager.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include "Global.hpp" 24 | 25 | #include 26 | 27 | class LoginManager; 28 | 29 | namespace QtGreet { 30 | class UI; 31 | class ScreenManager; 32 | } 33 | 34 | class QtGreet::ScreenManager : public QObject { 35 | Q_OBJECT; 36 | 37 | public: 38 | ScreenManager(); 39 | 40 | /** The parameter @title uniquely identifies a window */ 41 | QScreen * screenForWindow( QString title ); 42 | 43 | /** Show the already initialized instances */ 44 | void showInstacnes(); 45 | 46 | private: 47 | /** List of greeters */ 48 | QMap screenGreeterMap; 49 | 50 | /** Greeter <-> Screen map */ 51 | QMap greeterScreenMap; 52 | }; 53 | -------------------------------------------------------------------------------- /src/widgets/buttons/buttons.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include 22 | 23 | #include "buttons.hpp" 24 | 25 | NavButton::NavButton( QString name, QString type ) : QToolButton() { 26 | setObjectName( name + type ); 27 | setFixedSize( QSize( 27, 27 ) ); 28 | setIconSize( QSize( 22, 22 ) ); 29 | setAutoRaise( true ); 30 | 31 | if ( type == "Right" ) { 32 | setIcon( QIcon( ":/icons/arrow-right.png" ) ); 33 | } 34 | 35 | else { 36 | setIcon( QIcon( ":/icons/arrow-left.png" ) ); 37 | } 38 | } 39 | 40 | 41 | SessionEditButton::SessionEditButton() : QToolButton() { 42 | setObjectName( "SessionEditButton" ); 43 | setFixedSize( QSize( 27, 27 ) ); 44 | setIconSize( QSize( 22, 22 ) ); 45 | setAutoRaise( true ); 46 | 47 | setIcon( QIcon( ":/icons/edit.png" ) ); 48 | } 49 | 50 | 51 | LoginToolButton::LoginToolButton() : QToolButton() { 52 | setObjectName( "LoginButton" ); 53 | setFixedSize( QSize( 27, 27 ) ); 54 | setIconSize( QSize( 22, 22 ) ); 55 | setAutoRaise( true ); 56 | 57 | setIcon( QIcon( ":/icons/arrow-right.png" ) ); 58 | } 59 | 60 | 61 | LoginPushButton::LoginPushButton() : QPushButton() { 62 | setObjectName( "LoginButton" ); 63 | setFixedSize( QSize( 27, 27 ) ); 64 | setIconSize( QSize( 22, 22 ) ); 65 | setFlat( true ); 66 | 67 | setText( "&Login" ); 68 | setIcon( QIcon( ":/icons/arrow-right.png" ) ); 69 | } 70 | -------------------------------------------------------------------------------- /src/widgets/buttons/buttons.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | class NavButton : public QToolButton { 26 | Q_OBJECT; 27 | 28 | public: 29 | NavButton( QString name, QString type ); 30 | }; 31 | 32 | class SessionEditButton : public QToolButton { 33 | Q_OBJECT; 34 | 35 | public: 36 | SessionEditButton(); 37 | }; 38 | 39 | class LoginToolButton : public QToolButton { 40 | Q_OBJECT; 41 | 42 | public: 43 | LoginToolButton(); 44 | }; 45 | 46 | class LoginPushButton : public QPushButton { 47 | Q_OBJECT; 48 | 49 | public: 50 | LoginPushButton(); 51 | }; 52 | -------------------------------------------------------------------------------- /src/widgets/clock/ClockWidget.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | class QDBusInterface; 30 | class BatteryInfo; 31 | 32 | class AnalogClock : public QWidget { 33 | Q_OBJECT; 34 | 35 | public: 36 | AnalogClock( QColor text, QWidget *parent = 0 ); 37 | 38 | private: 39 | QColor mTextColor; 40 | QColor mShadowColor; 41 | 42 | BatteryInfo *battery; 43 | qreal mCharge = 100.0; 44 | bool mOnBattery = false; 45 | QImage battImg; 46 | 47 | protected: 48 | void paintEvent( QPaintEvent *event ) override; 49 | }; 50 | 51 | class DigitalClock : public QWidget { 52 | Q_OBJECT 53 | 54 | public: 55 | DigitalClock( QWidget *parent = 0 ); 56 | 57 | private: 58 | QLCDNumber *time; 59 | QLCDNumber *secs; 60 | QLabel *ampm; 61 | QLabel *date; 62 | QLabel *alrm; 63 | 64 | QBasicTimer *timer; 65 | 66 | protected: 67 | void timerEvent( QTimerEvent *event ) override; 68 | }; 69 | 70 | class SimpleClock : public QLabel { 71 | Q_OBJECT 72 | 73 | public: 74 | SimpleClock( bool time, bool date, QWidget *parent = 0 ); 75 | 76 | void setDateFormat( QString ); 77 | void setTimeFormat( QString ); 78 | 79 | private: 80 | QBasicTimer *timer; 81 | QString timeFmt; 82 | QString dateFmt; 83 | QString clockFmt; 84 | 85 | bool mShowTime = true; 86 | bool mShowDate = true; 87 | 88 | protected: 89 | void timerEvent( QTimerEvent *event ) override; 90 | }; 91 | 92 | class BatteryInfo : public QObject { 93 | Q_OBJECT; 94 | 95 | public: 96 | BatteryInfo(); 97 | 98 | qreal currentCharge(); 99 | bool onBattery(); 100 | 101 | private: 102 | QDBusInterface *iface; 103 | qreal mLastPercentage = 100.0; 104 | bool mOnBattery = false; 105 | 106 | private Q_SLOTS: 107 | void handlePowerChanges( QString, QVariantMap, QStringList ); 108 | 109 | Q_SIGNALS: 110 | /* Battery Charge/Discharge Signals */ 111 | void onBatteryChanged( bool ); 112 | 113 | /* Battery charge changed */ 114 | void chargeChanged( double ); 115 | }; 116 | -------------------------------------------------------------------------------- /src/widgets/container/Container.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include 22 | 23 | #include "Container.hpp" 24 | 25 | Container::Container( Hjson::Value bgClr, QString name ) : QWidget() { 26 | /** Object Name */ 27 | setObjectName( name ); 28 | 29 | /** Default Background will be transparent */ 30 | bgColor = QColor( Qt::transparent ); 31 | 32 | if ( not bgClr.empty() ) { 33 | int red, green, blue, alpha; 34 | red = bgClr[ "Red" ].to_double() * 255; 35 | green = bgClr[ "Green" ].to_double() * 255; 36 | blue = bgClr[ "Blue" ].to_double() * 255; 37 | alpha = bgClr[ "Alpha" ].to_double() * 255; 38 | 39 | bgColor = QColor( red, green, blue, alpha ); 40 | } 41 | } 42 | 43 | 44 | void Container::paintEvent( QPaintEvent *pEvent ) { 45 | if ( bgColor != QColor( Qt::transparent ) ) { 46 | QPainter painter( this ); 47 | 48 | painter.setBrush( bgColor ); 49 | painter.setPen( Qt::NoPen ); 50 | 51 | painter.drawRoundedRect( rect(), 5, 5 ); 52 | 53 | painter.end(); 54 | } 55 | 56 | QWidget::paintEvent( pEvent ); 57 | } 58 | -------------------------------------------------------------------------------- /src/widgets/container/Container.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "hjson.h" 28 | 29 | class Container : public QWidget { 30 | Q_OBJECT; 31 | 32 | public: 33 | Container( Hjson::Value value, QString name ); 34 | 35 | private: 36 | QColor bgColor; 37 | QColor border; 38 | 39 | protected: 40 | void paintEvent( QPaintEvent * ); 41 | }; 42 | -------------------------------------------------------------------------------- /src/widgets/factory/WidgetFactory.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include "Global.hpp" 24 | 25 | #include "hjson.h" 26 | 27 | class WidgetFactory { 28 | public: 29 | /* Create a widget, given its name, and apply the properties given in the map */ 30 | static QWidget *createWidget( QString name, QString type, Hjson::Value properties, QSize size ); 31 | 32 | private: 33 | 34 | /* 35 | * Most of the properties given can be applied directly, like width and height 36 | * Some properties like text, or icon need to be applied after casting them into suitable types. 37 | * Invalid properties will be ignored. Ex. icon for a label 38 | */ 39 | static void applyWidgetProperties( QWidget *, QString, QString, Hjson::Value, QSize size ); 40 | }; 41 | -------------------------------------------------------------------------------- /src/widgets/key: -------------------------------------------------------------------------------- 1 | +==============================================================+=======================+========================+ 2 | | Widget | Name | Type | 3 | +--------------------------------------------------------------+-----------------------+------------------------+ 4 | | | | | 5 | | buttons - All generic buttons | | | 6 | | 1. Okay button | OkayButton | OkayButton | 7 | | 2. Cancel button | CancelButton | CancelButton | 8 | | 3. Session Edit Button | SessionEditButton | SessionEditButton | 9 | | 4. User nav buttons | UserNav | Left|Right | 10 | | 5. Session nav buttons | SessionNav | Left|Right | 11 | | 6. Login button | LoginButton | Tool|Push Button | 12 | +--------------------------------------------------------------+-----------------------+------------------------+ 13 | | | | | 14 | | clock - various clock widgets | | | 15 | | 1. Analog Clock | Clock | AnalogClock | 16 | | 2. Digital Clock | Clock | DigitalClock | 17 | | 3. Simple Clock | Clock | Time|Date|Simple | 18 | +--------------------------------------------------------------+-----------------------+------------------------+ 19 | | | | | 20 | | labels - simple labels | | | 21 | | 1. Caps lock | CapsLock | CapsLock | 22 | | 2. Num lock | NumLock | NumLock | 23 | | 3. User Icon | UserIcon | UserIcon | 24 | | 4. Logo | Logo | Logo | 25 | +--------------------------------------------------------------+-----------------------+------------------------+ 26 | | | | | 27 | | power - power related buttons | | | 28 | | 1. Power menu button | PowerButton | Menu | 29 | | 2. Halt button | PowerButton | Halt | 30 | | 3. Reboot button | PowerButton | Reboot | 31 | | 4. Suspend button | PowerButton | Suspend | 32 | | 5. Hibernate button | PowerButton | Hibernate | 33 | | 6. Logout button | PowerButton | Logout | 34 | +--------------------------------------------------------------+-----------------------+------------------------+ 35 | | | | | 36 | | password - Password entry | | | 37 | | 1. Password edit | Password | LineEdit | 38 | +--------------------------------------------------------------+-----------------------+------------------------+ 39 | | | | | 40 | | session - Session name | | | 41 | | 1. Session combo | SessionName | Combo | 42 | | 2. Session list | SessionName | List | 43 | | 3. Session button | SessionName | PushButton | 44 | | 4. Session label | SessionName | Label | 45 | | 5. Session edit | SessionName | LineEdit | 46 | +--------------------------------------------------------------+-----------------------+------------------------+ 47 | | | | | 48 | | user - User name | | | 49 | | 1. User combo | UserName | Combo | 50 | | 2. User list | UserName | List | 51 | | 3. User edit | UserName | LineEdit | 52 | | 4. User label | UserName | Label | 53 | | 5. User button | UserName | PushButton | 54 | +==============================================================+=======================+========================+ 55 | -------------------------------------------------------------------------------- /src/widgets/labels/labels.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include 22 | 23 | #include "labels.hpp" 24 | 25 | LockState::LockState( QString type ) : QWidget() { 26 | /* Initial Status */ 27 | QFile file; 28 | 29 | if ( type == "CapsLock" ) { 30 | setObjectName( "CapsLock" ); 31 | file.setFileName( "/sys/class/leds/input0::capslock/brightness" ); 32 | text = "A"; 33 | } 34 | 35 | else { 36 | setObjectName( "NumLock" ); 37 | file.setFileName( "/sys/class/leds/input0::numlock/brightness" ); 38 | text = "#"; 39 | } 40 | 41 | if ( file.open( QFile::ReadOnly ) ) { 42 | if ( file.readAll().toInt() ) { 43 | isOn = true; 44 | } 45 | 46 | else { 47 | isOn = false; 48 | } 49 | 50 | file.close(); 51 | } 52 | 53 | mFont = font(); 54 | mFont.setPointSize( qMin( width(), height() ) - 4 ); 55 | mFont.setWeight( QFont::Bold ); 56 | 57 | setFont( mFont ); 58 | 59 | textClr = palette().color( QPalette::Text ); 60 | 61 | setMinimumSize( QSize( 16, 16 ) ); 62 | } 63 | 64 | 65 | void LockState::setState( bool state ) { 66 | isOn = state; 67 | repaint(); 68 | } 69 | 70 | 71 | void LockState::toggle() { 72 | isOn = not isOn; 73 | repaint(); 74 | } 75 | 76 | 77 | void LockState::paintEvent( QPaintEvent *pEvent ) { 78 | QPainter painter( this ); 79 | 80 | painter.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing ); 81 | 82 | if ( isOn ) { 83 | textClr.setAlphaF( 1.0 ); 84 | } 85 | 86 | else { 87 | textClr.setAlphaF( 0.2 ); 88 | } 89 | 90 | painter.setPen( textClr ); 91 | painter.drawText( rect(), Qt::AlignCenter, text ); 92 | 93 | painter.end(); 94 | 95 | pEvent->accept(); 96 | } 97 | 98 | 99 | UserIcon::UserIcon() : QLabel() { 100 | setObjectName( "UserIcon" ); 101 | setAlignment( Qt::AlignCenter ); 102 | setFixedSize( QSize( 72, 72 ) ); 103 | 104 | iconSize = QSize( 64, 64 ); 105 | 106 | img = QImage( ":/icons/user.png" ); 107 | } 108 | 109 | 110 | void UserIcon::setPixmap( QString path ) { 111 | img = QImage( path ); 112 | update(); 113 | } 114 | 115 | 116 | void UserIcon::paintEvent( QPaintEvent *pEvent ) { 117 | QPainter painter( this ); 118 | 119 | painter.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform ); 120 | 121 | QImage brush = img.scaled( iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation ); 122 | 123 | if ( brush.isNull() ) { 124 | brush = QImage( ":/icons/user.png" ).scaled( iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation ); 125 | } 126 | 127 | painter.save(); 128 | painter.setPen( QPen( Qt::gray, 2.0 ) ); 129 | painter.drawRoundedRect( rect().adjusted( 1, 1, -1, -1 ), 5.0, 5.0 ); 130 | painter.restore(); 131 | 132 | painter.save(); 133 | painter.translate( 4, 4 ); 134 | painter.setBrush( brush ); 135 | painter.setPen( Qt::NoPen ); 136 | painter.drawRoundedRect( QRectF( QPointF( 0, 0 ), iconSize ), 5.0, 5.0 ); 137 | painter.restore(); 138 | 139 | painter.end(); 140 | 141 | pEvent->accept(); 142 | } 143 | 144 | 145 | Logo::Logo() : QWidget() { 146 | setObjectName( "Logo" ); 147 | setFixedSize( 40, 40 ); 148 | mIcon = ":/icons/QtGreet.png"; 149 | } 150 | 151 | 152 | void Logo::setIconSize( QSize size ) { 153 | mIconSize = size.width(); 154 | mPix = QPixmap( mIcon ).scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation ); 155 | 156 | repaint(); 157 | } 158 | 159 | 160 | void Logo::setIcon( QString img ) { 161 | mIcon = img; 162 | QSize size( mIconSize, mIconSize ); 163 | 164 | mPix = QPixmap( mIcon ).scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation ); 165 | 166 | repaint(); 167 | } 168 | 169 | 170 | void Logo::paintEvent( QPaintEvent *pEvent ) { 171 | QPainter painter( this ); 172 | 173 | painter.setRenderHints( QPainter::Antialiasing ); 174 | painter.drawPixmap( QRect( (width() - mIconSize) / 2, (height() - mIconSize) / 2, mIconSize, mIconSize ), mPix ); 175 | painter.end(); 176 | 177 | pEvent->accept(); 178 | } 179 | -------------------------------------------------------------------------------- /src/widgets/labels/labels.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | class LockState : public QWidget { 26 | Q_OBJECT; 27 | 28 | public: 29 | LockState( QString type ); 30 | 31 | void setState( bool state ); 32 | void toggle(); 33 | 34 | private: 35 | bool isOn = false; 36 | QFont mFont; 37 | QColor textClr; 38 | QString text; 39 | 40 | protected: 41 | void paintEvent( QPaintEvent *pEvent ); 42 | }; 43 | 44 | class UserIcon : public QLabel { 45 | Q_OBJECT; 46 | 47 | public: 48 | UserIcon(); 49 | 50 | void setPixmap( QString ); 51 | 52 | private: 53 | QImage img; 54 | QSize iconSize; 55 | 56 | protected: 57 | void paintEvent( QPaintEvent * ); 58 | }; 59 | 60 | class Logo : public QWidget { 61 | Q_OBJECT; 62 | 63 | public: 64 | Logo(); 65 | 66 | void setIconSize( QSize ); 67 | void setIcon( QString ); 68 | 69 | private: 70 | int mIconSize; 71 | QString mIcon; 72 | QPixmap mPix; 73 | 74 | protected: 75 | void paintEvent( QPaintEvent *pEvent ); 76 | }; 77 | -------------------------------------------------------------------------------- /src/widgets/power/power.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include 22 | 23 | #include "Global.hpp" 24 | #include "power.hpp" 25 | 26 | QString getCommand( QString what ) { 27 | return sett->value( "PowerCommands/" + what ).toString(); 28 | } 29 | 30 | 31 | PowerButton::PowerButton( QString type ) : QToolButton() { 32 | setAutoRaise( true ); 33 | setFixedSize( QSize( 40, 40 ) ); 34 | setIconSize( QSize( 32, 32 ) ); 35 | 36 | if ( type == "Menu" ) { 37 | setIcon( QIcon( ":/icons/shutdown.png" ) ); 38 | setObjectName( "PowerButton" ); 39 | 40 | setToolTip( "Logout Menu" ); 41 | 42 | QMenu *menu = new QMenu(); 43 | menu->addAction( 44 | QIcon( ":/icons/suspend.png" ), "Suspend to RAM", [ = ] () { 45 | QStringList args = getCommand( "Suspend" ).split( " " ); 46 | 47 | if ( args.at( 0 ) == "dbus" ) { 48 | emit suspend(); 49 | } 50 | 51 | else { 52 | QProcess::startDetached( args.takeAt( 0 ), args ); 53 | } 54 | } 55 | ); 56 | 57 | menu->addAction( 58 | QIcon( ":/icons/hibernate.png" ), "Suspend to Disk", [ = ] () { 59 | QStringList args = getCommand( "Hibernate" ).split( " " ); 60 | 61 | if ( args.at( 0 ) == "dbus" ) { 62 | emit hibernate(); 63 | } 64 | 65 | else { 66 | QProcess::startDetached( args.takeAt( 0 ), args ); 67 | } 68 | } 69 | ); 70 | 71 | menu->addAction( 72 | QIcon( ":/icons/shutdown.png" ), "Halt System", [ = ] () { 73 | QStringList args = getCommand( "Shutdown" ).split( " " ); 74 | 75 | if ( args.at( 0 ) == "dbus" ) { 76 | emit shutdown( false ); 77 | } 78 | 79 | else { 80 | QProcess::startDetached( args.takeAt( 0 ), args ); 81 | emit shutdown( true ); 82 | } 83 | } 84 | ); 85 | 86 | menu->addAction( 87 | QIcon( ":/icons/reboot.png" ), "Reboot System", [ = ] () { 88 | QStringList args = getCommand( "Reboot" ).split( " " ); 89 | 90 | if ( args.at( 0 ) == "dbus" ) { 91 | emit reboot( false ); 92 | } 93 | 94 | else { 95 | QProcess::startDetached( args.takeAt( 0 ), args ); 96 | emit reboot( true ); 97 | } 98 | } 99 | ); 100 | 101 | setMenu( menu ); 102 | setPopupMode( QToolButton::InstantPopup ); 103 | } 104 | 105 | else if ( type == "Suspend" ) { 106 | setObjectName( "Suspend" ); 107 | setToolTip( "Suspend to RAM" ); 108 | setIcon( QIcon( ":/icons/suspend.png" ) ); 109 | connect( 110 | this, &QToolButton::clicked, [ = ] () { 111 | QStringList args = getCommand( "Suspend" ).split( " " ); 112 | 113 | if ( args.at( 0 ) == "dbus" ) { 114 | emit suspend(); 115 | } 116 | 117 | else { 118 | QProcess::startDetached( args.takeAt( 0 ), args ); 119 | } 120 | } 121 | ); 122 | } 123 | 124 | else if ( type == "Hibernate" ) { 125 | setObjectName( "Hibernate" ); 126 | setToolTip( "Suspend to Disk" ); 127 | setIcon( QIcon( ":/icons/hibernate.png" ) ); 128 | connect( 129 | this, &QToolButton::clicked, [ = ] () { 130 | QStringList args = getCommand( "Hibernate" ).split( " " ); 131 | 132 | if ( args.at( 0 ) == "dbus" ) { 133 | emit hibernate(); 134 | } 135 | 136 | else { 137 | QProcess::startDetached( args.takeAt( 0 ), args ); 138 | } 139 | } 140 | ); 141 | } 142 | 143 | else if ( type == "Halt" ) { 144 | setObjectName( "Halt" ); 145 | setToolTip( "Shutdown the system" ); 146 | setIcon( QIcon( ":/icons/shutdown.png" ) ); 147 | connect( 148 | this, &QToolButton::clicked, [ = ] () { 149 | QStringList args = getCommand( "Shutdown" ).split( " " ); 150 | 151 | if ( args.at( 0 ) == "dbus" ) { 152 | emit shutdown( false ); 153 | } 154 | 155 | else { 156 | QProcess::startDetached( args.takeAt( 0 ), args ); 157 | emit shutdown( true ); 158 | } 159 | } 160 | ); 161 | } 162 | 163 | else if ( type == "Reboot" ) { 164 | setObjectName( "Reboot" ); 165 | setToolTip( "Reboot the system" ); 166 | setIcon( QIcon( ":/icons/reboot.png" ) ); 167 | connect( 168 | this, &QToolButton::clicked, [ = ] () { 169 | QStringList args = getCommand( "Reboot" ).split( " " ); 170 | 171 | if ( args.at( 0 ) == "dbus" ) { 172 | emit reboot( false ); 173 | } 174 | 175 | else { 176 | QProcess::startDetached( args.takeAt( 0 ), args ); 177 | emit reboot( true ); 178 | } 179 | } 180 | ); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/widgets/power/power.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | class PowerButton : public QToolButton { 27 | Q_OBJECT; 28 | 29 | public: 30 | PowerButton( QString type ); 31 | 32 | /** Perform a suspend */ 33 | Q_SIGNAL void suspend(); 34 | 35 | /** Perform a hibernate */ 36 | Q_SIGNAL void hibernate(); 37 | 38 | /** 39 | * Perform a shutdown or inform the user of a shutdown. 40 | * @done - The action has been done, just inform the user. 41 | */ 42 | Q_SIGNAL void shutdown( bool done ); 43 | 44 | /** 45 | * Perform a reboot or inform the user of a reboot. 46 | * @done - The action has been done, just inform the user. 47 | */ 48 | Q_SIGNAL void reboot( bool done ); 49 | }; 50 | -------------------------------------------------------------------------------- /src/widgets/session/session.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #include 22 | #include "Global.hpp" 23 | 24 | #include "session.hpp" 25 | 26 | static bool IsExec( QString exec ) { 27 | /* If this is a full path (ex: /usr/bin/fish) */ 28 | if ( access( exec.toUtf8().constData(), R_OK | X_OK ) == 0 ) { 29 | return true; 30 | } 31 | 32 | QStringList parts = exec.split( QRegularExpression( "\\s+" ) ); 33 | QString cmd; 34 | 35 | /** Pick the first part which is not a env variable as cmd */ 36 | for ( QString part: parts ) { 37 | if ( part.contains( "=" ) ) { 38 | continue; 39 | } 40 | 41 | cmd = part; 42 | break; 43 | } 44 | 45 | /* Otherwise (ex: plasmashell) */ 46 | for ( QString path : qgetenv( "PATH" ).split( ':' ) ) { 47 | if ( QFileInfo( path + "/" + exec ).isExecutable() ) { 48 | return true; 49 | } 50 | 51 | if ( QFileInfo( path + "/" + cmd ).isExecutable() ) { 52 | return true; 53 | } 54 | } 55 | 56 | return false; 57 | } 58 | 59 | 60 | Sessions getSessions( bool custom ) { 61 | Sessions mSessions; 62 | 63 | QStringList wlSessPaths; 64 | 65 | if ( wlSessPath == "default" ) { 66 | wlSessPaths = QStandardPaths::locateAll( QStandardPaths::GenericDataLocation, "wayland-sessions", QStandardPaths::LocateDirectory ); 67 | } 68 | 69 | else { 70 | wlSessPaths = wlSessPath.split( ";", Qt::SkipEmptyParts ); 71 | } 72 | 73 | for ( QString wlSessDir: wlSessPaths ) { 74 | for ( QFileInfo sess: QDir( wlSessDir ).entryInfoList( { "*.desktop" } ) ) { 75 | QSettings session( sess.absoluteFilePath(), QSettings::IniFormat ); 76 | 77 | bool isAvailable = IsExec( session.value( "Desktop Entry/TryExec" ).toString() ); 78 | isAvailable |= IsExec( session.value( "Desktop Entry/Exec" ).toString() ); 79 | 80 | if ( isAvailable ) { 81 | Session s = Session{ 82 | session.value( "Desktop Entry/Name" ).toString(), 83 | session.value( "Desktop Entry/Icon", ":/icons/session.png" ).toString(), 84 | "wayland", 85 | session.value( "Desktop Entry/Exec" ).toString(), 86 | sess.absoluteFilePath() 87 | }; 88 | 89 | if ( not s.name.contains( "wayland", Qt::CaseInsensitive ) ) { 90 | s.name += " (Wayland)"; 91 | } 92 | 93 | mSessions << s; 94 | } 95 | } 96 | } 97 | 98 | QStringList xSessPaths; 99 | 100 | if ( xSessPath == "default" ) { 101 | xSessPaths = QStandardPaths::locateAll( QStandardPaths::GenericDataLocation, "xsessions", QStandardPaths::LocateDirectory ); 102 | } 103 | 104 | else { 105 | xSessPaths = xSessPath.split( ";", Qt::SkipEmptyParts ); 106 | } 107 | 108 | for ( QString xSessDir: xSessPaths ) { 109 | for ( QFileInfo sess: QDir( xSessDir ).entryInfoList( { "*.desktop" } ) ) { 110 | QSettings session( sess.absoluteFilePath(), QSettings::IniFormat ); 111 | 112 | bool isAvailable = IsExec( session.value( "Desktop Entry/TryExec" ).toString() ); 113 | isAvailable |= IsExec( session.value( "Desktop Entry/Exec" ).toString() ); 114 | 115 | if ( isAvailable ) { 116 | Session s = Session{ 117 | session.value( "Desktop Entry/Name" ).toString() + " (X11)", 118 | session.value( "Desktop Entry/Icon", ":/icons/session.png" ).toString(), 119 | "X11", 120 | session.value( "Desktop Entry/Exec" ).toString(), 121 | sess.absoluteFilePath() 122 | }; 123 | 124 | mSessions << s; 125 | } 126 | } 127 | } 128 | 129 | if ( custom ) { 130 | Session customSess{ "Custom", "application-x-executable", "unknown", "", "" }; 131 | mSessions << customSess; 132 | } 133 | 134 | return mSessions; 135 | } 136 | 137 | 138 | SessionEdit::SessionEdit() : QLineEdit() { 139 | setObjectName( "SessionEdit" ); 140 | setMinimumSize( QSize( 200, 27 ) ); 141 | setAlignment( Qt::AlignCenter ); 142 | } 143 | 144 | 145 | /* Session Name - Generic Class */ 146 | 147 | SessionName::SessionName( bool custom ) { 148 | mSessionList = getSessions( custom ); 149 | } 150 | 151 | 152 | void SessionName::switchToNextSession() { 153 | curSess++; 154 | 155 | if ( curSess >= mSessionList.count() ) { 156 | curSess = 0; 157 | } 158 | } 159 | 160 | 161 | void SessionName::switchToPreviousSession() { 162 | curSess--; 163 | 164 | if ( curSess < 0 ) { 165 | curSess = mSessionList.count() - 1; 166 | } 167 | } 168 | 169 | 170 | Sessions SessionName::sessions() { 171 | return mSessionList; 172 | } 173 | 174 | 175 | Session SessionName::currentSession() { 176 | // Return an invalid session 177 | return mSessionList.at( curSess ); 178 | } 179 | 180 | 181 | /* Session ComboBox */ 182 | 183 | SessionCombo::SessionCombo( bool custom ) : QComboBox(), SessionName( custom ) { 184 | setObjectName( "SessionCombo" ); 185 | for ( Session sess: mSessionList ) { 186 | addItem( QIcon( sess.icon ), sess.name ); 187 | } 188 | } 189 | 190 | 191 | void SessionCombo::switchToNextSession() { 192 | SessionName::switchToNextSession(); 193 | setCurrentIndex( curSess ); 194 | } 195 | 196 | 197 | void SessionCombo::switchToPreviousSession() { 198 | SessionName::switchToPreviousSession(); 199 | setCurrentIndex( curSess ); 200 | } 201 | 202 | 203 | /* Session List */ 204 | 205 | SessionList::SessionList( bool custom ) : QListWidget(), SessionName( custom ) { 206 | setObjectName( "SessionList" ); 207 | setIconSize( QSize( 24, 24 ) ); 208 | setFont( QFont( "Quicksand", 12 ) ); 209 | setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 210 | setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 211 | 212 | for ( Session sess: mSessionList ) { 213 | addItem( new QListWidgetItem( QIcon::fromTheme( sess.icon, QIcon( sess.icon ) ), sess.name, this ) ); 214 | } 215 | } 216 | 217 | 218 | void SessionList::switchToNextSession() { 219 | SessionName::switchToNextSession(); 220 | setCurrentRow( curSess ); 221 | } 222 | 223 | 224 | void SessionList::switchToPreviousSession() { 225 | SessionName::switchToPreviousSession(); 226 | setCurrentRow( curSess ); 227 | } 228 | 229 | 230 | /* Session Label */ 231 | 232 | SessionLabel::SessionLabel( bool custom ) : QWidget(), SessionName( custom ) { 233 | setObjectName( "SessionLabel" ); 234 | 235 | prevBtn = new QToolButton(); 236 | prevBtn->setObjectName( "SessionNavLeft" ); 237 | prevBtn->setIcon( QIcon( ":/icons/arrow-left.png" ) ); 238 | 239 | lbl = new QLabel(); 240 | lbl->setObjectName( "SessionLabel" ); 241 | 242 | nextBtn = new QToolButton(); 243 | nextBtn->setObjectName( "SessionNavRight" ); 244 | nextBtn->setIcon( QIcon( ":/icons/arrow-right.png" ) ); 245 | 246 | QHBoxLayout *lyt = new QHBoxLayout(); 247 | 248 | lyt->setContentsMargins( QMargins() ); 249 | lyt->setSpacing( 5 ); 250 | 251 | lyt->addWidget( prevBtn ); 252 | lyt->addWidget( lbl ); 253 | lyt->addWidget( nextBtn ); 254 | 255 | setLayout( lyt ); 256 | 257 | nextBtn->hide(); 258 | prevBtn->hide(); 259 | 260 | setFixedHeight( 27 ); 261 | } 262 | 263 | 264 | void SessionLabel::setText( QString text ) { 265 | lbl->setText( text ); 266 | } 267 | 268 | 269 | void SessionLabel::setAlignment( Qt::Alignment a ) { 270 | lbl->setAlignment( a ); 271 | } 272 | 273 | 274 | void SessionLabel::switchToNextSession() { 275 | SessionName::switchToNextSession(); 276 | setText( mSessionList.at( curSess ).name ); 277 | } 278 | 279 | 280 | void SessionLabel::switchToPreviousSession() { 281 | SessionName::switchToPreviousSession(); 282 | setText( mSessionList.at( curSess ).name ); 283 | } 284 | 285 | 286 | void SessionLabel::setShowNavButtons( bool show ) { 287 | if ( show ) { 288 | prevBtn->show(); 289 | nextBtn->show(); 290 | } 291 | 292 | else { 293 | prevBtn->hide(); 294 | nextBtn->hide(); 295 | } 296 | } 297 | 298 | 299 | void SessionLabel::setIconSize( QSize size ) { 300 | nextBtn->setIconSize( size ); 301 | prevBtn->setIconSize( size ); 302 | } 303 | 304 | 305 | void SessionLabel::setFixedHeight( int h ) { 306 | QWidget::setFixedHeight( h ); 307 | 308 | nextBtn->setFixedWidth( h ); 309 | nextBtn->setFixedHeight( h ); 310 | 311 | prevBtn->setFixedWidth( h ); 312 | prevBtn->setFixedHeight( h ); 313 | } 314 | -------------------------------------------------------------------------------- /src/widgets/session/session.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | typedef struct session_t { 26 | QString name; 27 | QString icon; 28 | QString type; 29 | QString exec; 30 | QString file; 31 | } Session; 32 | Q_DECLARE_METATYPE( Session ); 33 | 34 | typedef QList Sessions; 35 | 36 | class SessionEdit : public QLineEdit { 37 | Q_OBJECT; 38 | 39 | public: 40 | SessionEdit(); 41 | }; 42 | 43 | class SessionName { 44 | public: 45 | SessionName( bool ); 46 | 47 | void switchToNextSession(); 48 | void switchToPreviousSession(); 49 | 50 | Sessions sessions(); 51 | Session currentSession(); 52 | 53 | protected: 54 | Sessions mSessionList; 55 | int curSess = 0; 56 | }; 57 | 58 | class SessionCombo : public QComboBox, public SessionName { 59 | Q_OBJECT; 60 | 61 | public: 62 | SessionCombo( bool ); 63 | 64 | void switchToNextSession(); 65 | void switchToPreviousSession(); 66 | }; 67 | 68 | class SessionList : public QListWidget, public SessionName { 69 | Q_OBJECT; 70 | 71 | public: 72 | SessionList( bool ); 73 | 74 | void switchToNextSession(); 75 | void switchToPreviousSession(); 76 | }; 77 | 78 | class SessionLabel : public QWidget, public SessionName { 79 | Q_OBJECT; 80 | 81 | public: 82 | SessionLabel( bool ); 83 | 84 | void setText( QString ); 85 | 86 | void setAlignment( Qt::Alignment ); 87 | 88 | void switchToNextSession(); 89 | void switchToPreviousSession(); 90 | 91 | void setShowNavButtons( bool show ); 92 | 93 | void setIconSize( QSize ); 94 | 95 | void setFixedHeight( int ); 96 | 97 | private: 98 | QLabel *lbl; 99 | QToolButton *prevBtn, *nextBtn; 100 | }; 101 | -------------------------------------------------------------------------------- /src/widgets/user/user.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020-2022 Britanicus 3 | * This file is a part of QtGreet project (https://gitlab.com/marcusbritanicus/QtGreet) 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301, USA. 19 | **/ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | typedef struct user_t { 26 | QString username; 27 | uint uid; 28 | uint gid; 29 | QString name; 30 | QString homePath; 31 | QString shell; 32 | QString icon; 33 | } User; 34 | 35 | Q_DECLARE_METATYPE( User ); 36 | 37 | typedef QList Users; 38 | 39 | class UserName { 40 | public: 41 | UserName(); 42 | 43 | Users users(); 44 | User currentUser(); 45 | 46 | virtual void switchToNextUser(); 47 | virtual void switchToPreviousUser(); 48 | 49 | /** 50 | * Set the current user based on the struct user_t. 51 | * Here we compare the username and user id. 52 | */ 53 | virtual bool setCurrentUser( User usr ); 54 | 55 | /** 56 | * Set the current user based on the user id. 57 | * Here we compare only the user id. 58 | */ 59 | virtual bool setCurrentUser( uint uid ); 60 | 61 | protected: 62 | Users mUserList; 63 | int curUser = -1; 64 | }; 65 | 66 | class UserEdit : public QLineEdit, public UserName { 67 | Q_OBJECT; 68 | 69 | public: 70 | UserEdit(); 71 | 72 | void switchToNextUser(); 73 | void switchToPreviousUser(); 74 | 75 | bool setCurrentUser( User usr ); 76 | bool setCurrentUser( uint uid ); 77 | }; 78 | 79 | class UserCombo : public QComboBox, public UserName { 80 | Q_OBJECT; 81 | 82 | public: 83 | UserCombo(); 84 | 85 | void switchToNextUser(); 86 | void switchToPreviousUser(); 87 | 88 | bool setCurrentUser( User usr ); 89 | bool setCurrentUser( uint uid ); 90 | }; 91 | 92 | class UserList : public QListWidget, public UserName { 93 | Q_OBJECT; 94 | 95 | public: 96 | UserList(); 97 | 98 | void switchToNextUser(); 99 | void switchToPreviousUser(); 100 | 101 | bool setCurrentUser( User usr ); 102 | bool setCurrentUser( uint uid ); 103 | }; 104 | 105 | class UserLabel : public QWidget, public UserName { 106 | Q_OBJECT; 107 | 108 | public: 109 | UserLabel(); 110 | 111 | void setText( QString ); 112 | 113 | void setAlignment( Qt::Alignment ); 114 | 115 | void switchToNextUser(); 116 | void switchToPreviousUser(); 117 | 118 | bool setCurrentUser( User usr ); 119 | bool setCurrentUser( uint uid ); 120 | 121 | void setShowNavButtons( bool show ); 122 | void setIconSize( QSize ); 123 | 124 | void setFixedHeight( int ); 125 | 126 | private: 127 | QLabel *lbl; 128 | QToolButton *prevBtn, *nextBtn; 129 | }; 130 | -------------------------------------------------------------------------------- /src/widgets/videobg/MpvWidget.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "MpvWidget.hpp" 6 | 7 | static void wakeup( void *ctx ) { 8 | QMetaObject::invokeMethod( (MpvWidget *)ctx, "on_mpv_events", Qt::QueuedConnection ); 9 | } 10 | 11 | 12 | static void *get_proc_address( void *ctx, const char *name ) { 13 | Q_UNUSED( ctx ); 14 | QOpenGLContext *glctx = QOpenGLContext::currentContext(); 15 | 16 | if ( !glctx ) { 17 | return nullptr; 18 | } 19 | 20 | return reinterpret_cast(glctx->getProcAddress( QByteArray( name ) ) ); 21 | } 22 | 23 | 24 | MpvWidget::MpvWidget( QWidget *parent ) : QOpenGLWidget( parent ) { 25 | mpv = mpv_create(); 26 | 27 | if ( !mpv ) { 28 | throw std::runtime_error( "could not create mpv context" ); 29 | } 30 | 31 | mpv_set_option_string( mpv, "terminal", "no" ); 32 | mpv_set_option_string( mpv, "msg-level", "all=error" ); 33 | 34 | if ( mpv_initialize( mpv ) < 0 ) { 35 | throw std::runtime_error( "could not initialize mpv context" ); 36 | } 37 | 38 | Mpv::Qt::set_option_variant( mpv, "hwdec", "auto" ); 39 | 40 | mpv_observe_property( mpv, 0, "duration", MPV_FORMAT_DOUBLE ); 41 | mpv_observe_property( mpv, 0, "time-pos", MPV_FORMAT_DOUBLE ); 42 | mpv_set_wakeup_callback( mpv, wakeup, this ); 43 | } 44 | 45 | 46 | MpvWidget::~MpvWidget() { 47 | makeCurrent(); 48 | 49 | if ( mpv_gl ) { 50 | mpv_render_context_free( mpv_gl ); 51 | } 52 | 53 | mpv_terminate_destroy( mpv ); 54 | } 55 | 56 | 57 | void MpvWidget::command( const QVariant& params ) { 58 | Mpv::Qt::command_variant( mpv, params ); 59 | } 60 | 61 | 62 | void MpvWidget::setProperty( const QString& name, const QVariant& value ) { 63 | Mpv::Qt::set_property_variant( mpv, name, value ); 64 | } 65 | 66 | 67 | QVariant MpvWidget::getProperty( const QString& name ) const { 68 | return Mpv::Qt::get_property_variant( mpv, name ); 69 | } 70 | 71 | 72 | void MpvWidget::initializeGL() { 73 | mpv_opengl_init_params gl_init_params[ 1 ] = { get_proc_address, nullptr }; 74 | mpv_render_param params[]{ 75 | { MPV_RENDER_PARAM_API_TYPE, const_cast(MPV_RENDER_API_TYPE_OPENGL) }, 76 | { MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params }, 77 | { MPV_RENDER_PARAM_INVALID, nullptr } 78 | }; 79 | 80 | if ( mpv_render_context_create( &mpv_gl, mpv, params ) < 0 ) { 81 | throw std::runtime_error( "failed to initialize mpv GL context" ); 82 | } 83 | 84 | mpv_render_context_set_update_callback( mpv_gl, MpvWidget::on_update, reinterpret_cast(this) ); 85 | } 86 | 87 | 88 | void MpvWidget::paintGL() { 89 | mpv_opengl_fbo mpfbo{ static_cast(defaultFramebufferObject() ), width(), height(), 0 }; 90 | int flip_y{ 1 }; 91 | 92 | mpv_render_param params[] = { 93 | { MPV_RENDER_PARAM_OPENGL_FBO, &mpfbo }, 94 | { MPV_RENDER_PARAM_FLIP_Y, &flip_y }, 95 | { MPV_RENDER_PARAM_INVALID, nullptr } 96 | }; 97 | 98 | mpv_render_context_render( mpv_gl, params ); 99 | } 100 | 101 | 102 | void MpvWidget::on_mpv_events() { 103 | // Process all events, until the event queue is empty. 104 | while ( mpv ) { 105 | mpv_event *event = mpv_wait_event( mpv, 0 ); 106 | 107 | if ( event->event_id == MPV_EVENT_NONE ) { 108 | break; 109 | } 110 | 111 | handle_mpv_event( event ); 112 | } 113 | } 114 | 115 | 116 | void MpvWidget::handle_mpv_event( mpv_event *event ) { 117 | switch ( event->event_id ) { 118 | case MPV_EVENT_PROPERTY_CHANGE: { 119 | mpv_event_property *prop = (mpv_event_property *)event->data; 120 | 121 | if ( strcmp( prop->name, "time-pos" ) == 0 ) { 122 | if ( prop->format == MPV_FORMAT_DOUBLE ) { 123 | double time = *(double *)prop->data; 124 | Q_EMIT positionChanged( time ); 125 | } 126 | } 127 | else if ( strcmp( prop->name, "duration" ) == 0 ) { 128 | if ( prop->format == MPV_FORMAT_DOUBLE ) { 129 | double time = *(double *)prop->data; 130 | Q_EMIT durationChanged( time ); 131 | } 132 | } 133 | 134 | break; 135 | } 136 | 137 | default: { } 138 | // Ignore uninteresting or unknown events. 139 | } 140 | } 141 | 142 | 143 | void MpvWidget::maybeUpdate() { 144 | if ( window()->isMinimized() ) { 145 | makeCurrent(); 146 | paintGL(); 147 | context()->swapBuffers( context()->surface() ); 148 | doneCurrent(); 149 | } 150 | else { 151 | update(); 152 | } 153 | } 154 | 155 | 156 | void MpvWidget::on_update( void *ctx ) { 157 | QMetaObject::invokeMethod( (MpvWidget *)ctx, "maybeUpdate" ); 158 | } 159 | -------------------------------------------------------------------------------- /src/widgets/videobg/MpvWidget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "MpvHelper.hpp" 8 | 9 | class MpvWidget : public QOpenGLWidget { 10 | Q_OBJECT 11 | 12 | public: 13 | MpvWidget( QWidget *parent ); 14 | ~MpvWidget(); 15 | 16 | void command( const QVariant& params ); 17 | void setProperty( const QString& name, const QVariant& value ); 18 | QVariant getProperty( const QString& name ) const; 19 | 20 | QSize minimumSizeHint() const { return QSize( 640, 480 ); } 21 | 22 | Q_SIGNALS: 23 | void durationChanged( int value ); 24 | void positionChanged( int value ); 25 | 26 | protected: 27 | void initializeGL() Q_DECL_OVERRIDE; 28 | void paintGL() Q_DECL_OVERRIDE; 29 | 30 | private Q_SLOTS: 31 | void on_mpv_events(); 32 | void maybeUpdate(); 33 | 34 | private: 35 | void handle_mpv_event( mpv_event *event ); 36 | static void on_update( void *ctx ); 37 | 38 | mpv_handle *mpv; 39 | mpv_render_context *mpv_gl; 40 | }; 41 | -------------------------------------------------------------------------------- /themes/LytMgr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from PyQt5.QtCore import * 4 | from PyQt5.QtGui import * 5 | from PyQt5.QtWidgets import * 6 | -------------------------------------------------------------------------------- /themes/aerial/4k.m3u: -------------------------------------------------------------------------------- 1 | http://sylvan.apple.com/Aerials/2x/Videos/comp_CH_C007_C011_PSNK_v02_SDR_PS_FINAL_20180709_SDR_4K_HEVC.mov 2 | http://sylvan.apple.com/Aerials/2x/Videos/comp_CH_C002_C005_PSNK_v05_SDR_PS_FINAL_20180709_SDR_4K_HEVC.mov 3 | http://sylvan.apple.com/Aerials/2x/Videos/comp_CH_C007_C004_PSNK_v02_SDR_PS_FINAL_20180709_SDR_4K_HEVC.mov 4 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D008_C010_4K_SDR_HEVC.mov 5 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D001_C001_4K_SDR_HEVC.mov 6 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D011_C010_4K_SDR_HEVC.mov 7 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D002_C003_4K_SDR_HEVC.mov 8 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D001_C005_4K_SDR_HEVC.mov 9 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D011_C009_4K_SDR_HEVC.mov 10 | http://sylvan.apple.com/Aerials/2x/Videos/GL_G004_C010_4K_SDR_HEVC.mov 11 | http://sylvan.apple.com/Aerials/2x/Videos/GL_G002_C002_4K_SDR_HEVC.mov 12 | http://sylvan.apple.com/Aerials/2x/Videos/HK_B005_C011_4K_SDR_HEVC.mov 13 | http://sylvan.apple.com/Aerials/2x/Videos/HK_H004_C010_4K_SDR_HEVC.mov 14 | http://sylvan.apple.com/Aerials/2x/Videos/HK_H004_C013_4K_SDR_HEVC.mov 15 | http://sylvan.apple.com/Aerials/2x/Videos/HK_H004_C001_4K_SDR_HEVC.mov 16 | http://sylvan.apple.com/Aerials/2x/Videos/HK_H004_C008_4K_SDR_HEVC.mov 17 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT312_162NC_139M_1041_AFRICA_NIGHT_v14_SDR_FINAL_20180706_SDR_4K_HEVC.mov 18 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A103_C002_0205DG_v12_SDR_FINAL_20180706_SDR_4K_HEVC.mov 19 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT306_139NC_139J_3066_CALI_TO_VEGAS_v07_SDR_FINAL_22062018_SDR_4K_HEVC.mov 20 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A108_C001_v09_SDR_FINAL_22062018_SDR_4K_HEVC.mov 21 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT308_139K_142NC_CARIBBEAN_DAY_v09_SDR_FINAL_22062018_SDR_4K_HEVC.mov 22 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT329_113NC_396B_1105_CHINA_v04_SDR_FINAL_20180706_F900F2700_SDR_4K_HEVC.mov 23 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A083_C002_1130KZ_v04_SDR_PS_FINAL_20180725_SDR_4K_HEVC.mov 24 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT329_117NC_401C_1037_IRELAND_TO_ASIA_v48_SDR_PS_FINAL_20180725_F0F6300_SDR_4K_HEVC.mov 25 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT026_363A_103NC_E1027_KOREA_JAPAN_NIGHT_v17_SDR_FINAL_25062018_SDR_4K_HEVC.mov 26 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A105_C003_0212CT_FLARE_v10_SDR_PS_FINAL_20180711_SDR_4K_HEVC.mov 27 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A009_C001_010181A_v09_SDR_PS_FINAL_20180725_SDR_4K_HEVC.mov 28 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A114_C001_0305OT_v10_SDR_FINAL_22062018_SDR_4K_HEVC.mov 29 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A001_C004_1207W5_v23_SDR_FINAL_20180706_SDR_4K_HEVC.mov 30 | http://sylvan.apple.com/Aerials/2x/Videos/LW_L001_C006_4K_SDR_HEVC.mov 31 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A006_C008_4K_SDR_HEVC.mov 32 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A009_C009_4K_SDR_HEVC.mov 33 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A008_C004_4K_SDR_HEVC.mov 34 | http://sylvan.apple.com/Aerials/2x/Videos/comp_LA_A006_C004_v01_SDR_FINAL_PS_20180730_SDR_4K_HEVC.mov 35 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A005_C009_4K_SDR_HEVC.mov 36 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A011_C003_4K_SDR_HEVC.mov 37 | -------------------------------------------------------------------------------- /themes/aerial/all_sd.m3u: -------------------------------------------------------------------------------- 1 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b2-1.mov 2 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b5-1.mov 3 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b6-1.mov 4 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//comp_GL_G010_C006_v08_6Mbps.mov 5 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b1-1.mov 6 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b2-2.mov 7 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b4-1.mov 8 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b6-2.mov 9 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b7-1.mov 10 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b8-1.mov 11 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b1-2.mov 12 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b3-1.mov 13 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b5-2.mov 14 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b6-3.mov 15 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b1-3.mov 16 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b2-3.mov 17 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b3-2.mov 18 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b4-2.mov 19 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b7-2.mov 20 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b1-4.mov 21 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b2-4.mov 22 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b3-3.mov 23 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b4-3.mov 24 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b5-3.mov 25 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b6-4.mov 26 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b7-3.mov 27 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b8-2.mov 28 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b8-3.mov 29 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b9-2.mov 30 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b9-3.mov 31 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos//b10-3.mov 32 | http://sylvan.apple.com/Aerials/2x/Videos//comp_CH_C007_C011_PSNK_v02_SDR_PS_FINAL_20180709_SDR_2K_HEVC.mov 33 | http://sylvan.apple.com/Aerials/2x/Videos//comp_CH_C002_C005_PSNK_v05_SDR_PS_FINAL_20180709_SDR_2K_HEVC.mov 34 | http://sylvan.apple.com/Aerials/2x/Videos//comp_CH_C007_C004_PSNK_v02_SDR_PS_FINAL_20180709_SDR_2K_HEVC.mov 35 | http://sylvan.apple.com/Aerials/2x/Videos//DB_D008_C010_2K_SDR_HEVC.mov 36 | http://sylvan.apple.com/Aerials/2x/Videos//DB_D001_C001_2K_SDR_HEVC.mov 37 | http://sylvan.apple.com/Aerials/2x/Videos//DB_D011_C010_2K_SDR_HEVC.mov 38 | http://sylvan.apple.com/Aerials/2x/Videos//DB_D002_C003_2K_SDR_HEVC.mov 39 | http://sylvan.apple.com/Aerials/2x/Videos//DB_D001_C005_2K_SDR_HEVC.mov 40 | http://sylvan.apple.com/Aerials/2x/Videos//DB_D011_C009_2K_SDR_HEVC.mov 41 | http://sylvan.apple.com/Aerials/2x/Videos//GL_G004_C010_2K_SDR_HEVC.mov 42 | http://sylvan.apple.com/Aerials/2x/Videos//GL_G002_C002_2K_SDR_HEVC.mov 43 | http://sylvan.apple.com/Aerials/2x/Videos//HK_B005_C011_2K_SDR_HEVC.mov 44 | http://sylvan.apple.com/Aerials/2x/Videos//HK_H004_C010_2K_SDR_HEVC.mov 45 | http://sylvan.apple.com/Aerials/2x/Videos//HK_H004_C013_2K_SDR_HEVC.mov 46 | http://sylvan.apple.com/Aerials/2x/Videos//HK_H004_C001_2K_SDR_HEVC.mov 47 | http://sylvan.apple.com/Aerials/2x/Videos//HK_H004_C008_2K_SDR_HEVC.mov 48 | http://sylvan.apple.com/Aerials/2x/Videos//comp_GMT312_162NC_139M_1041_AFRICA_NIGHT_v14_SDR_FINAL_20180706_SDR_2K_HEVC.mov 49 | http://sylvan.apple.com/Aerials/2x/Videos//comp_A103_C002_0205DG_v12_SDR_FINAL_20180706_SDR_2K_HEVC.mov 50 | http://sylvan.apple.com/Aerials/2x/Videos//comp_GMT306_139NC_139J_3066_CALI_TO_VEGAS_v07_SDR_FINAL_22062018_SDR_4K_HEVC.mov 51 | http://sylvan.apple.com/Aerials/2x/Videos//comp_A108_C001_v09_SDR_FINAL_22062018_SDR_2K_HEVC.mov 52 | http://sylvan.apple.com/Aerials/2x/Videos//comp_GMT308_139K_142NC_CARIBBEAN_DAY_v09_SDR_FINAL_22062018_SDR_2K_HEVC.mov 53 | http://sylvan.apple.com/Aerials/2x/Videos//comp_GMT329_113NC_396B_1105_CHINA_v04_SDR_FINAL_20180706_F900F2700_SDR_2K_HEVC.mov 54 | http://sylvan.apple.com/Aerials/2x/Videos//comp_A083_C002_1130KZ_v04_SDR_PS_FINAL_20180725_SDR_2K_HEVC.mov 55 | http://sylvan.apple.com/Aerials/2x/Videos//comp_GMT329_117NC_401C_1037_IRELAND_TO_ASIA_v48_SDR_PS_FINAL_20180725_F0F6300_SDR_2K_HEVC.mov 56 | http://sylvan.apple.com/Aerials/2x/Videos//comp_GMT026_363A_103NC_E1027_KOREA_JAPAN_NIGHT_v17_SDR_FINAL_25062018_SDR_2K_HEVC.mov 57 | http://sylvan.apple.com/Aerials/2x/Videos//comp_A105_C003_0212CT_FLARE_v10_SDR_PS_FINAL_20180711_SDR_2K_HEVC.mov 58 | http://sylvan.apple.com/Aerials/2x/Videos//comp_A009_C001_010181A_v09_SDR_PS_FINAL_20180725_SDR_2K_HEVC.mov 59 | http://sylvan.apple.com/Aerials/2x/Videos//comp_A114_C001_0305OT_v10_SDR_FINAL_22062018_SDR_2K_HEVC.mov 60 | http://sylvan.apple.com/Aerials/2x/Videos//comp_A001_C004_1207W5_v23_SDR_FINAL_20180706_SDR_2K_HEVC.mov 61 | http://sylvan.apple.com/Aerials/2x/Videos//LA_A006_C008_2K_SDR_HEVC.mov 62 | http://sylvan.apple.com/Aerials/2x/Videos//LA_A009_C009_2K_SDR_HEVC.mov 63 | http://sylvan.apple.com/Aerials/2x/Videos//LA_A008_C004_2K_SDR_HEVC.mov 64 | http://sylvan.apple.com/Aerials/2x/Videos//comp_LA_A006_C004_v01_SDR_FINAL_PS_20180730_SDR_2K_HEVC.mov 65 | http://sylvan.apple.com/Aerials/2x/Videos//LA_A005_C009_2K_SDR_HEVC.mov 66 | http://sylvan.apple.com/Aerials/2x/Videos//LA_A011_C003_2K_SDR_HEVC.mov 67 | -------------------------------------------------------------------------------- /themes/aerial/day.m3u: -------------------------------------------------------------------------------- 1 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b2-1.mov 2 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b6-1.mov 3 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b1-1.mov 4 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b2-2.mov 5 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b4-1.mov 6 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b7-1.mov 7 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b5-2.mov 8 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b1-3.mov 9 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b3-2.mov 10 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b7-2.mov 11 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b8-2.mov 12 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b4-3.mov 13 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b8-3.mov 14 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b9-3.mov 15 | http://sylvan.apple.com/Aerials/2x/Videos/comp_CH_C007_C011_PSNK_v02_SDR_PS_FINAL_20180709_SDR_2K_HEVC.mov 16 | http://sylvan.apple.com/Aerials/2x/Videos/comp_CH_C002_C005_PSNK_v05_SDR_PS_FINAL_20180709_SDR_2K_HEVC.mov 17 | http://sylvan.apple.com/Aerials/2x/Videos/comp_CH_C007_C004_PSNK_v02_SDR_PS_FINAL_20180709_SDR_2K_HEVC.mov 18 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D008_C010_2K_SDR_HEVC.mov 19 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D001_C001_2K_SDR_HEVC.mov 20 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D002_C003_2K_SDR_HEVC.mov 21 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D001_C005_2K_SDR_HEVC.mov 22 | http://sylvan.apple.com/Aerials/2x/Videos/GL_G004_C010_2K_SDR_HEVC.mov 23 | http://sylvan.apple.com/Aerials/2x/Videos/GL_G002_C002_2K_SDR_HEVC.mov 24 | http://sylvan.apple.com/Aerials/2x/Videos/HK_H004_C010_2K_SDR_HEVC.mov 25 | http://sylvan.apple.com/Aerials/2x/Videos/HK_H004_C013_2K_SDR_HEVC.mov 26 | http://sylvan.apple.com/Aerials/2x/Videos/HK_H004_C008_2K_SDR_HEVC.mov 27 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A103_C002_0205DG_v12_SDR_FINAL_20180706_SDR_2K_HEVC.mov 28 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A108_C001_v09_SDR_FINAL_22062018_SDR_2K_HEVC.mov 29 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT308_139K_142NC_CARIBBEAN_DAY_v09_SDR_FINAL_22062018_SDR_2K_HEVC.mov 30 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A105_C003_0212CT_FLARE_v10_SDR_PS_FINAL_20180711_SDR_2K_HEVC.mov 31 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A009_C001_010181A_v09_SDR_PS_FINAL_20180725_SDR_2K_HEVC.mov 32 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A114_C001_0305OT_v10_SDR_FINAL_22062018_SDR_2K_HEVC.mov 33 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A001_C004_1207W5_v23_SDR_FINAL_20180706_SDR_2K_HEVC.mov 34 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A006_C008_2K_SDR_HEVC.mov 35 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A008_C004_2K_SDR_HEVC.mov 36 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A005_C009_2K_SDR_HEVC.mov 37 | -------------------------------------------------------------------------------- /themes/aerial/index.theme: -------------------------------------------------------------------------------- 1 | [General] 2 | Name = Aerial 3 | 4 | [Files] 5 | Layout = layout.hjson 6 | StyleSheet = style.qss 7 | 8 | [Theme] 9 | Background = videobg 10 | BaseColor = ffffffff 11 | TextColor = ffffff 12 | Type = Video 13 | 14 | [videobg] 15 | File = 16 | Playlist = night.m3u 17 | 18 | [cache] 19 | Location = /var/tmp/qtgreet/aerial 20 | -------------------------------------------------------------------------------- /themes/aerial/layout.hjson: -------------------------------------------------------------------------------- 1 | { 2 | Layout: { 3 | Direction: Vertical 4 | Keys: [ "R1", "R2" ] 5 | R1: [ "SessionName", "QLabel-1", "Stretch", "NumLock", "CapsLock" ] 6 | R2: [ "C1" ] 7 | C1: [ "Stretch", "Clock-1", "Clock-2", "QLabel-2", "R3", "R4" ] 8 | R3: [ "QLabel-3", "UserName", "Stretch" ] 9 | R4: [ "QLabel-4", "Password", "LoginButton", "Stretch" ] 10 | } 11 | 12 | Properties: { 13 | R1: { 14 | Height: 24 15 | } 16 | C1: { 17 | Spacing: 10 18 | Margins: 100 19 | Alignment: BL 20 | } 21 | R3: { 22 | Spacing: 0 23 | } 24 | R4: { 25 | Spacing: 0 26 | } 27 | SessionName: { 28 | Height: 24 29 | Type: Combo 30 | MaximumWidth: 270 31 | Font: Dejavu Sans, 12, Normal, Normal 32 | } 33 | QLabel-1: { 34 | Text: en_us 35 | Width: 80 36 | TextAlign: Right 37 | } 38 | NumLock: { 39 | Font: Monospace, 12, Normal, Normal 40 | Width: 15 41 | Height: 24 42 | ToolTip: NumLock status 43 | } 44 | CapsLock: { 45 | Font: Monospace, 12, Normal, Normal 46 | Width: 15 47 | Height: 24 48 | ToolTip: CapsLock status 49 | } 50 | Clock-1: { 51 | Type: Time 52 | Font: Quicksand, 40, Normal, Normal 53 | Format: "HH : mm" 54 | Width: 300 55 | } 56 | Clock-2: { 57 | Type: Date 58 | Font: Quicksand, 14, Normal, Normal 59 | Format: dddd, MMMM dd, yyyy 60 | Width: 300 61 | } 62 | QLabel-2: { 63 | Text: " " 64 | Width: 75 65 | } 66 | QLabel-3: { 67 | Text: "Username" 68 | Width: 75 69 | } 70 | QLabel-4: { 71 | Text: "Password" 72 | Width: 75 73 | Height: 25 74 | } 75 | UserName: { 76 | Type: LineEdit 77 | Width: 225 78 | Height: 25 79 | } 80 | Password: { 81 | Width: 200 82 | Height: 25 83 | } 84 | LoginButton: { 85 | Type: ToolButton 86 | Width: 25 87 | Height: 25 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /themes/aerial/night.m3u: -------------------------------------------------------------------------------- 1 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b5-1.mov 2 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/comp_GL_G010_C006_v08_6Mbps.mov 3 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b6-2.mov 4 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b8-1.mov 5 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b1-2.mov 6 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b3-1.mov 7 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b6-3.mov 8 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b2-3.mov 9 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b4-2.mov 10 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b1-4.mov 11 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b2-4.mov 12 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b3-3.mov 13 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b5-3.mov 14 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b6-4.mov 15 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b7-3.mov 16 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b9-2.mov 17 | http://a1.v2.phobos.apple.com.edgesuite.net/us/r1000/000/Features/atv/AutumnResources/videos/b10-3.mov 18 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D011_C010_2K_SDR_HEVC.mov 19 | http://sylvan.apple.com/Aerials/2x/Videos/DB_D011_C009_2K_SDR_HEVC.mov 20 | http://sylvan.apple.com/Aerials/2x/Videos/HK_B005_C011_2K_SDR_HEVC.mov 21 | http://sylvan.apple.com/Aerials/2x/Videos/HK_H004_C001_2K_SDR_HEVC.mov 22 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT312_162NC_139M_1041_AFRICA_NIGHT_v14_SDR_FINAL_20180706_SDR_2K_HEVC.mov 23 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT306_139NC_139J_3066_CALI_TO_VEGAS_v07_SDR_FINAL_22062018_SDR_4K_HEVC.mov 24 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT329_113NC_396B_1105_CHINA_v04_SDR_FINAL_20180706_F900F2700_SDR_2K_HEVC.mov 25 | http://sylvan.apple.com/Aerials/2x/Videos/comp_A083_C002_1130KZ_v04_SDR_PS_FINAL_20180725_SDR_2K_HEVC.mov 26 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT329_117NC_401C_1037_IRELAND_TO_ASIA_v48_SDR_PS_FINAL_20180725_F0F6300_SDR_2K_HEVC.mov 27 | http://sylvan.apple.com/Aerials/2x/Videos/comp_GMT026_363A_103NC_E1027_KOREA_JAPAN_NIGHT_v17_SDR_FINAL_25062018_SDR_2K_HEVC.mov 28 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A009_C009_2K_SDR_HEVC.mov 29 | http://sylvan.apple.com/Aerials/2x/Videos/comp_LA_A006_C004_v01_SDR_FINAL_PS_20180730_SDR_2K_HEVC.mov 30 | http://sylvan.apple.com/Aerials/2x/Videos/LA_A011_C003_2K_SDR_HEVC.mov 31 | -------------------------------------------------------------------------------- /themes/aerial/style.qss: -------------------------------------------------------------------------------- 1 | QWidget { 2 | color: #ffffff; 3 | } 4 | 5 | #Panel { 6 | background-color: rgba(0, 0, 0, 60); 7 | border-bottom: 1px solid rgba(80, 80, 80, 60); 8 | } 9 | 10 | #Sidebar { 11 | background-color: rgba(0, 0, 0, 30); 12 | border-right: 1px solid rgba(80, 80, 80, 60); 13 | } 14 | 15 | QPushButton:hover { 16 | background-color: rgba(255, 255, 255, 30); 17 | } 18 | 19 | QPushButton:pressed { 20 | background-color: rgba(255, 255, 255, 10); 21 | padding-top: 1px; 22 | padding-left: 1px; 23 | } 24 | 25 | QToolButton { 26 | border: none; 27 | border-radius: 0px; 28 | background-color: rgba(255, 255, 255, 60); 29 | } 30 | 31 | QToolButton:hover { 32 | background-color: rgba(255, 255, 255, 30); 33 | } 34 | 35 | QToolButton:pressed { 36 | background-color: rgba(255, 255, 255, 10); 37 | padding-top: 2px; 38 | padding-left: 2px; 39 | } 40 | 41 | QToolButton#nav { 42 | border: 1px solid gray; 43 | border-radius: 18px; 44 | padding-top: 1px; 45 | padding-left: 1px; 46 | } 47 | 48 | QToolButton#Halt { 49 | border: 1px solid gray; 50 | border-radius: 0px; 51 | border-top-right-radius: 18px; 52 | border-bottom-right-radius: 18px; 53 | padding-top: 1px; 54 | padding-left: 1px; 55 | } 56 | 57 | QToolButton#Reboot { 58 | border: 1px solid gray; 59 | border-radius: 0px; 60 | border-top-left-radius: 18px; 61 | border-bottom-left-radius: 18px; 62 | padding-top: 1px; 63 | padding-left: 1px; 64 | } 65 | 66 | QLineEdit { 67 | background-color: rgba(0, 0, 0, 60); 68 | border: none; 69 | border-radius: 0px; 70 | padding-left: 10px; 71 | padding-right: 10px; 72 | } 73 | 74 | QListWidget { 75 | margin-bottom: 2px; 76 | background-color: rgba(255, 255, 255, 60); 77 | border: none; 78 | } 79 | 80 | QWidget#widget { 81 | border: 2px solid gray; 82 | border-radius: 5px; 83 | } 84 | 85 | QWidget#OverLay { 86 | background-color: rgba(0, 0, 0, 230); 87 | } 88 | 89 | QLabel#UserIcon { 90 | border: 2px solid gray; 91 | border-radius: 6px; 92 | } 93 | 94 | QComboBox { 95 | border: none; 96 | background-color: rgba(0, 0, 0, 0); 97 | } 98 | 99 | QComboBox::drop-down { 100 | subcontrol-origin: padding; 101 | subcontrol-position: top right; 102 | width: 27px; 103 | background-color: rgba(255, 255, 255, 0); 104 | border: none; 105 | } 106 | 107 | QComboBox::down-arrow { 108 | image: url(:/icons/arrow-down.png); 109 | width: 18px; 110 | height: 18px; 111 | } 112 | 113 | QComboBox::down-arrow:on { /* shift the arrow when popup is open */ 114 | top: 1px; 115 | left: 1px; 116 | } 117 | 118 | QComboBox QAbstractItemView { 119 | background-color: rgba(0, 0, 0, 60); 120 | } 121 | 122 | QMessageBox { 123 | background-color: rgba(0, 0, 0, 230); 124 | border: 2px solid gray; 125 | border-radius: 5px; 126 | } 127 | -------------------------------------------------------------------------------- /themes/compact/index.theme: -------------------------------------------------------------------------------- 1 | [General] 2 | Name = Compact 3 | 4 | [Files] 5 | Layout = layout.hjson 6 | StyleSheet = style.qss 7 | 8 | [Theme] 9 | Background = ../../backgrounds/Water.svg 10 | BaseColor = ffffffff 11 | TextColor = ffffff 12 | Type = Image 13 | -------------------------------------------------------------------------------- /themes/compact/layout.hjson: -------------------------------------------------------------------------------- 1 | { 2 | Layout: { 3 | Direction: Vertical 4 | Keys: [ "R1" ] 5 | R1: [ "C1", "C2" ] 6 | C1: [ "Logo", "Stretch", "UserName-1", "Stretch", "Stretch", "R2" ] 7 | C2: [ "R3", "Stretch", "R4", "R5", "R6", "R7", "Stretch", "Stretch", "R8" ] 8 | R2: [ "Stretch", "PowerButton-1", "PowerButton-2", "PowerButton-3", "PowerButton-4", "Stretch" ] 9 | R3: [ "Battery", "Stretch", "Clock-1", "Stretch", "NumLock", "CapsLock" ] 10 | R4: [ "Stretch", "UserIcon", "Stretch" ] 11 | R5: [ "Stretch", "UserName-2", "Stretch" ] 12 | R6: [ "Stretch", "SessionName", "Stretch" ] 13 | R7: [ "Stretch", "Password", "LoginButton", "Stretch" ] 14 | R8: [ "Stretch", "Clock-2", "Stretch" ] 15 | Margins: 0.25 16 | Spacing: 0 17 | } 18 | 19 | Properties: { 20 | R1: { 21 | Height: 0.5 22 | Width: 0.5 23 | } 24 | C1: { 25 | Wdith: 0.15 26 | BGColor: { 27 | Red:0.29 28 | Green: 0.16 29 | Blue: 0.16 30 | Alpha: 0.72 31 | } 32 | Margins: [ 0, 0, 3, 3 ] 33 | } 34 | C2: { 35 | Width: 0.35 36 | BGColor: { 37 | Red:0.4 38 | Green: 0.81 39 | Blue: 0.99 40 | Alpha: 0.72 41 | } 42 | Spacing: 10 43 | Margins: 3 44 | } 45 | R3: { 46 | Height: 24 47 | } 48 | R4: { 49 | Alignment: MM 50 | } 51 | R5: { 52 | Alignment: MM 53 | } 54 | R7: { 55 | Alignment: MM 56 | Spacing: 5 57 | } 58 | Logo: { 59 | Type: Label 60 | FixedWidth: 0.15 61 | FixedHeight: 0.1 62 | IconSize: 72 63 | } 64 | UserName-1: { 65 | Type: List 66 | Width: 0.15 67 | Height: 0.25 68 | IconSize: 24 69 | }, 70 | Battery: { 71 | Width: 22 72 | Height: 22 73 | }, 74 | Clock-1: { 75 | Type: Time 76 | Format: hh:mm:ss AP 77 | Font: Quicksand, 10, Bold, Normal 78 | }, 79 | Clock-2: { 80 | Type: Date 81 | Format: dddd, MMM dd, yyyy 82 | FixedHeight: 27 83 | Font: Quicksand, 10, Bold, Normal 84 | }, 85 | NumLock: { 86 | Font: monospace, 11, Normal, Normal 87 | Width: 15 88 | Height: 36 89 | ToolTip: NumLock status 90 | }, 91 | CapsLock: { 92 | Font: monospace, 11, Normal, Normal 93 | Width: 15 94 | Height: 36 95 | ToolTip: CapsLock status 96 | }, 97 | UserIcon: { 98 | Type: Label 99 | Height: 72 100 | Width: 72 101 | Alignment: Center 102 | }, 103 | UserName-2: { 104 | Type: Label 105 | Width: 0.18 106 | Height: 36 107 | FixedHeight: 27 108 | Font: DejaVu Sans, 12, Bold, Italic 109 | TextAlign: Center 110 | ShowNav: false 111 | }, 112 | Password: { 113 | Width: 0.18 114 | Height: 36 115 | }, 116 | LoginButton: { 117 | Width: 36 118 | Height: 36 119 | Type: ToolButton 120 | TextAlign: Center 121 | IconSize: 16 122 | }, 123 | SessionName: { 124 | Type: Combo 125 | Width: 0.12 126 | Height: 27 127 | TextAlign: Center 128 | IconSize: 24 129 | }, 130 | PowerButton-1: { 131 | Type: Suspend 132 | FixedWidth: 32 133 | FixedHeight: 32 134 | IconSize: 36 135 | }, 136 | PowerButton-2: { 137 | Type: Hibernate 138 | FixedWidth: 32 139 | FixedHeight: 32 140 | }, 141 | PowerButton-3: { 142 | Type: Halt 143 | FixedWidth: 32 144 | FixedHeight: 32 145 | }, 146 | PowerButton-4: { 147 | Type: Reboot 148 | FixedWidth: 32 149 | FixedHeight: 32 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /themes/compact/style.qss: -------------------------------------------------------------------------------- 1 | QWidget { 2 | color: white; 3 | } 4 | 5 | QWidget#OverLay { 6 | background-color: rgba(0, 0, 0, 230); 7 | } 8 | 9 | QToolButton { 10 | border: none; 11 | border-radius: 3px; 12 | } 13 | 14 | QToolButton:hover { 15 | background-color: rgba(60, 60, 60, 90); 16 | border: none; 17 | border-radius: 3px; 18 | } 19 | 20 | QToolButton:focus { 21 | background-color: rgba(60, 60, 60, 120); 22 | border-radius: 3px; 23 | border-left: 2px solid palette(Highlight); 24 | } 25 | 26 | QToolButton:pressed { 27 | background-color: rgba(60, 60, 60, 120); 28 | border-radius: 3px; 29 | padding-top: 1px; 30 | padding-left: 1px; 31 | } 32 | 33 | QToolButton#SessionName { 34 | background-color: rgba(60, 60, 60, 60); 35 | } 36 | 37 | QToolButton#LoginButton { 38 | background-color: rgba(60, 60, 60, 60); 39 | } 40 | 41 | QToolButton#SessionName:pressed { 42 | background-color: rgba(60, 60, 60, 120); 43 | } 44 | 45 | QToolButton#LoginButton:pressed { 46 | background-color: rgba(60, 60, 60, 120); 47 | } 48 | 49 | #Password { 50 | background-color: rgba(60, 60, 60, 60); 51 | border-radius: 3px; 52 | } 53 | 54 | #Password:focus { 55 | background-color: rgba(60, 60, 60, 90); 56 | border-radius: 3px; 57 | border-left: 2px solid palette(Highlight); 58 | } 59 | 60 | #UserList { 61 | background-color: transparent; 62 | border: none; 63 | font-size: 10pt; 64 | } 65 | 66 | #UserList::item:focus { 67 | border-right: 2px solid palette(Highlight); 68 | font-weight: bold; 69 | } 70 | 71 | #UserList::item:selected { 72 | background-color: #904A0404; 73 | color: yellow; 74 | } 75 | 76 | QComboBox { 77 | border: none; 78 | background-color: rgba(60, 60, 60, 60); 79 | } 80 | 81 | QComboBox::drop-down { 82 | subcontrol-origin: padding; 83 | subcontrol-position: top right; 84 | width: 27px; 85 | background-color: rgba(0, 0, 0, 0); 86 | border: none; 87 | } 88 | 89 | QComboBox::down-arrow { 90 | image: url(:/icons/arrow-down.png); 91 | width: 18px; 92 | height: 18px; 93 | } 94 | 95 | QComboBox::down-arrow:on { /* shift the arrow when popup is open */ 96 | top: 1px; 97 | left: 1px; 98 | } 99 | 100 | QComboBox QAbstractItemView { 101 | background-color: rgba(0, 0, 0, 60); 102 | } 103 | 104 | QMessageBox { 105 | background-color: rgba(0, 0, 0, 230); 106 | border: 2px solid gray; 107 | border-radius: 5px; 108 | } 109 | -------------------------------------------------------------------------------- /themes/default/index.theme: -------------------------------------------------------------------------------- 1 | [General] 2 | Name = Default 3 | 4 | [Files] 5 | Layout = layout.hjson 6 | StyleSheet = style.qss 7 | 8 | [Theme] 9 | Background = ../../backgrounds/BlurryBlob.png 10 | BaseColor = ffffffff 11 | TextColor = ffffff 12 | Type = Image 13 | -------------------------------------------------------------------------------- /themes/default/layout.hjson: -------------------------------------------------------------------------------- 1 | { 2 | Layout: { 3 | Direction: Vertical 4 | Keys: [ "C1" ] 5 | C1: [ "R1", "Stretch", "R2", "Stretch", "R3", "R4", "Stretch", "R5", "Stretch", "R6", "R7", "Stretch", "R8" ] 6 | R1: [ "Battery", "Stretch", "Clock", "Stretch", "NumLock", "CapsLock" ] 7 | R2: [ "UserIcon" ] 8 | R3: [ "UserName" ] 9 | R4: [ "Password" ] 10 | R5: [ "LoginButton" ] 11 | R6: [ "SessionName" ] 12 | R7: [ "SessionEdit" ] 13 | R8: [ "VirtualKeyboard", "Stretch", "PowerButton" ] 14 | } 15 | 16 | Properties: { 17 | C1: { 18 | Spacing: 10 19 | } 20 | R1: { 21 | BGColor: { 22 | Red: 0.0 23 | Green: 0.0 24 | Blue: 0.0 25 | Alpha: 0.09 26 | } 27 | Height: 36 28 | } 29 | R2: { 30 | Alignment: MM 31 | } 32 | R3: { 33 | Alignment: MM 34 | Spacing: 10 35 | } 36 | R4: { 37 | Alignment: MM 38 | } 39 | R5: { 40 | Alignment: MM 41 | } 42 | R6: { 43 | Alignment: MM 44 | Spacing: 10 45 | } 46 | Battery: { 47 | Width: 36 48 | Height: 36 49 | }, 50 | Clock: { 51 | Type: Time 52 | Format: hh:mm:ss AP 53 | Width: 75 54 | Height: 36 55 | Alignment: Center 56 | }, 57 | NumLock: { 58 | Font: monospace, 11, Normal, Normal 59 | Width: 15 60 | Height: 36 61 | ToolTip: NumLock status 62 | }, 63 | CapsLock: { 64 | Font: monospace, 11, Normal, Normal 65 | Width: 15 66 | Height: 36 67 | ToolTip: CapsLock status 68 | }, 69 | UserIcon: { 70 | Type: Label 71 | Height: 72 72 | Width: 72 73 | TextAlign: Center 74 | }, 75 | UserName: { 76 | Type: Label 77 | Width: 352 78 | Height: 36 79 | TextAlign: Center 80 | Font: DejaVu Sans, 11, Bold, Normal 81 | NavButtons: true 82 | }, 83 | Password: { 84 | Width: 270 85 | Height: 36 86 | }, 87 | LoginButton: { 88 | Width: 100 89 | Height: 36 90 | Type: PushButton 91 | TextAlign: Center 92 | }, 93 | SessionName: { 94 | Type: Label 95 | Width: 352 96 | Height: 36 97 | TextAlign: Center 98 | NavButtons: true 99 | }, 100 | SessionEdit: { 101 | Width: 270 102 | Height: 36 103 | TextAlign: Center 104 | }, 105 | VirtualKeyboard: { 106 | Width: 36 107 | Height: 36 108 | TextAlign: Center 109 | }, 110 | PowerButton: { 111 | Width: 36 112 | Height: 36 113 | TextAlign: Right 114 | Type: Menu 115 | }, 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /themes/default/style.qss: -------------------------------------------------------------------------------- 1 | QWidget { 2 | color: #ffffff; 3 | } 4 | 5 | QPushButton:hover { 6 | background-color: rgba(255, 255, 255, 30); 7 | border: 1px solid cornflowerblue; 8 | } 9 | 10 | QPushButton:pressed { 11 | background-color: rgba(255, 255, 255, 10); 12 | padding-top: 1px; 13 | padding-left: 1px; 14 | } 15 | 16 | QPushButton:focus { 17 | border: 2px solid cornflowerblue; 18 | } 19 | 20 | QToolButton:focus { 21 | border: 2px solid cornflowerblue; 22 | } 23 | 24 | QToolButton:hover { 25 | background-color: rgba(255, 255, 255, 30); 26 | } 27 | 28 | QToolButton:pressed { 29 | background-color: rgba(255, 255, 255, 10); 30 | padding-top: 2px; 31 | padding-left: 2px; 32 | } 33 | 34 | #LoginButton { 35 | border: 1px solid gray; 36 | border-radius: 18px; 37 | } 38 | 39 | #LoginButton:focus { 40 | border: 1px solid cornflowerblue; 41 | border-radius: 18px; 42 | } 43 | 44 | #UserLabel, #SessionLabel { 45 | border: 1px solid gray; 46 | border-radius: 18px; 47 | } 48 | 49 | #UserNavRight, #UserNavLeft { 50 | border: 1px solid gray; 51 | border-radius: 18px; 52 | padding-top: 1px; 53 | padding-left: 1px; 54 | } 55 | 56 | #BackButton { 57 | border: 1px solid gray; 58 | border-radius: 18px; 59 | padding-top: 1px; 60 | padding-left: 1px; 61 | } 62 | 63 | #SessionNavRight, #SessionNavLeft { 64 | border: 1px solid gray; 65 | border-radius: 18px; 66 | padding-top: 1px; 67 | padding-left: 1px; 68 | } 69 | 70 | #UserNavRight:focus, #UserNavLeft:focus { 71 | border: 1px solid cornflowerblue; 72 | } 73 | 74 | #SessionNavRight:focus, #SessionNavLeft:focus { 75 | border: 1px solid cornflowerblue; 76 | } 77 | 78 | QToolButton#Halt { 79 | border: 1px solid gray; 80 | border-radius: 0px; 81 | border-top-right-radius: 18px; 82 | border-bottom-right-radius: 18px; 83 | padding-top: 1px; 84 | padding-left: 1px; 85 | } 86 | 87 | QToolButton#Reboot { 88 | border: 1px solid gray; 89 | border-radius: 0px; 90 | border-top-left-radius: 18px; 91 | border-bottom-left-radius: 18px; 92 | padding-top: 1px; 93 | padding-left: 1px; 94 | } 95 | 96 | QLineEdit { 97 | background-color: transparent; 98 | border: 1px solid gray; 99 | border-radius: 18px; 100 | padding-left: 10px; 101 | padding-right: 10px; 102 | } 103 | 104 | QLineEdit:focus { 105 | border: 2px solid cornflowerblue; 106 | } 107 | 108 | QLineEdit:edit-focus { 109 | border: 2px solid cornflowerblue; 110 | } 111 | 112 | QListWidget { 113 | background-color: transparent; 114 | border: none; 115 | } 116 | 117 | QWidget#widget { 118 | border: 2px solid gray; 119 | border-radius: 5px; 120 | } 121 | 122 | QWidget#OverLay { 123 | background-color: rgba(0, 0, 0, 230); 124 | } 125 | 126 | QLabel#UserIcon { 127 | border: 2px solid gray; 128 | border-radius: 6px; 129 | } 130 | 131 | QMessageBox { 132 | background-color: rgba(0, 0, 0, 230); 133 | border: 2px solid gray; 134 | border-radius: 5px; 135 | } 136 | -------------------------------------------------------------------------------- /themes/sidebar/index.theme: -------------------------------------------------------------------------------- 1 | [General] 2 | Name = Sidebar 3 | 4 | [Files] 5 | Layout = layout.hjson 6 | StyleSheet = style.qss 7 | 8 | [Theme] 9 | Background = ../../backgrounds/Sailboats.svg 10 | BaseColor = ffffffff 11 | TextColor = ffffff 12 | Type = Image 13 | -------------------------------------------------------------------------------- /themes/sidebar/layout.hjson: -------------------------------------------------------------------------------- 1 | { 2 | Layout: { 3 | Direction: Vertical 4 | Keys: [ "R1", "R2" ] 5 | R1: [ "Battery", "Stretch", "PowerButton" ] 6 | R2: [ "C1", "C2" ] 7 | C1: [ "Stretch", "UserIcon", "QLabel-1", "UserName", "Password", "QLabel-1", "LoginButton", "Stretch", "Stretch", "SessionName" ] 8 | C2: [ "Stretch", "Clock-1", "Clock-2" ] 9 | } 10 | 11 | Properties: { 12 | R1: { 13 | Height: 27 14 | BGColor: { 15 | Red: 0.0 16 | Green: 0.0 17 | Blue: 0.0 18 | Alpha: 0.18 19 | } 20 | } 21 | C1: { 22 | Margins: 20 23 | Width: 0.2 24 | Alignment: MM 25 | BGColor: { 26 | Red: 0.0 27 | Green: 0.0 28 | Blue: 0.0 29 | Alpha: 0.09 30 | } 31 | Spacing: 5 32 | } 33 | C2: { 34 | Width: 0.8 35 | Alignment: BR 36 | Margins: 0.05 37 | } 38 | Battery: { 39 | Type: Label 40 | } 41 | PowerButton: { 42 | Type: Menu 43 | } 44 | UserIcon: { 45 | Type: Icon 46 | Width: 72 47 | Height: 72 48 | } 49 | QLabel-1: { 50 | Text: " " 51 | Width: 0.1 52 | Height: 27 53 | } 54 | UserName: { 55 | Type: Label 56 | Height: 27 57 | Width: 0.18 58 | TextAlign: Center 59 | NavButtons: true 60 | } 61 | Password: { 62 | Type: LineEdit 63 | Height: 27 64 | Width: 0.18 65 | } 66 | LoginButton: { 67 | Type: PushButton 68 | Height: 27 69 | Width: 75 70 | IconSize: 16 71 | } 72 | Clock-1: { 73 | Type: Time 74 | Format: hh:mm AP 75 | FontSize: 3.0 76 | } 77 | Clock-2: { 78 | Type: Date 79 | Format: dddd, MMMM dd, yyyy 80 | FontSize: 1.4 81 | } 82 | SessionName: { 83 | Type: Label 84 | Height: 27 85 | Width: 0.18 86 | TextAlign: Center 87 | NavButtons: true 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /themes/sidebar/style.qss: -------------------------------------------------------------------------------- 1 | QWidget { 2 | color: #ffffff; 3 | } 4 | 5 | #Panel { 6 | background-color: rgba(0, 0, 0, 30); 7 | border-bottom: 1px solid rgba(80, 80, 80, 60); 8 | } 9 | 10 | #Sidebar { 11 | background-color: rgba(0, 0, 0, 30); 12 | border-right: 1px solid rgba(80, 80, 80, 60); 13 | } 14 | 15 | #LoginButton { 16 | border: none; 17 | border-radius: 0px; 18 | background-color: rgba(255, 255, 255, 60); 19 | } 20 | 21 | QPushButton:hover { 22 | background-color: rgba(255, 255, 255, 30); 23 | } 24 | 25 | QPushButton:pressed { 26 | background-color: rgba(255, 255, 255, 10); 27 | padding-top: 1px; 28 | padding-left: 1px; 29 | } 30 | 31 | QToolButton { 32 | border: none; 33 | border-radius: 0px; 34 | background-color: rgba(255, 255, 255, 60); 35 | } 36 | 37 | #UserNavRight, #UserNavLeft { 38 | background-color: transparent; 39 | } 40 | 41 | #SessionNavRight, #SessionNavLeft { 42 | background-color: transparent; 43 | } 44 | 45 | QToolButton#PowerButton { 46 | background-color: rgba(0, 0, 0, 0); 47 | } 48 | 49 | QToolButton:hover { 50 | background-color: rgba(255, 255, 255, 30); 51 | } 52 | 53 | QToolButton:pressed { 54 | background-color: rgba(255, 255, 255, 10); 55 | padding-top: 2px; 56 | padding-left: 2px; 57 | } 58 | 59 | QToolButton#nav { 60 | border: 1px solid gray; 61 | border-radius: 18px; 62 | padding-top: 1px; 63 | padding-left: 1px; 64 | } 65 | 66 | QToolButton#halt { 67 | border: 1px solid gray; 68 | border-radius: 0px; 69 | border-top-right-radius: 18px; 70 | border-bottom-right-radius: 18px; 71 | padding-top: 1px; 72 | padding-left: 1px; 73 | } 74 | 75 | QToolButton#reboot { 76 | border: 1px solid gray; 77 | border-radius: 0px; 78 | border-top-left-radius: 18px; 79 | border-bottom-left-radius: 18px; 80 | padding-top: 1px; 81 | padding-left: 1px; 82 | } 83 | 84 | QLineEdit { 85 | background-color: rgba(255, 255, 255, 60); 86 | border: none; 87 | border-radius: 0px; 88 | padding-left: 10px; 89 | padding-right: 10px; 90 | } 91 | 92 | QListWidget { 93 | margin-bottom: 2px; 94 | background-color: rgba(255, 255, 255, 60); 95 | border: none; 96 | } 97 | 98 | QWidget#widget { 99 | border: 2px solid gray; 100 | border-radius: 5px; 101 | } 102 | 103 | QWidget#OverLay { 104 | background-color: rgba(0, 0, 0, 230); 105 | } 106 | 107 | QWidget#R1 { 108 | background-color: rgba(0, 0, 0, 230); 109 | } 110 | 111 | QWidget#C1 { 112 | background-color: rgba(0, 0, 0, 230); 113 | } 114 | 115 | QMessageBox { 116 | background-color: rgba(0, 0, 0, 230); 117 | border: 2px solid gray; 118 | border-radius: 5px; 119 | } 120 | --------------------------------------------------------------------------------