Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
cd8575d
- First draft of locker
trigg Jan 18, 2026
b0b5581
- try adding pam details
trigg Jan 18, 2026
e92f984
- attempt to fix CI
trigg Jan 18, 2026
7b99566
- more
trigg Jan 18, 2026
a17d6d0
- first uncrustify
trigg Jan 18, 2026
2593db0
- include locker.xml in install
trigg Jan 18, 2026
65064c3
- more uncrust
trigg Jan 18, 2026
71307fa
- It should exit if not supported
trigg Jan 18, 2026
d754ad2
- hopefully more graceful fail of fprintd
trigg Jan 18, 2026
36d876d
- even more graceful?
trigg Jan 18, 2026
004310d
- maybe
trigg Jan 18, 2026
4846597
- allow disable internally
trigg Jan 18, 2026
1fc725a
- fix fingerprint again
trigg Jan 18, 2026
33d7349
- more guardrails
trigg Jan 18, 2026
3a05591
- hide fprintd plugin on simple failures
trigg Jan 18, 2026
0a89625
- hide battery in unknown state
trigg Jan 18, 2026
f6cd3c8
- uncrustify
trigg Jan 18, 2026
f425cc5
- Improved (?) dbus error catching
trigg Jan 19, 2026
f812394
- uncrustify
trigg Jan 19, 2026
6349958
- Fix center
trigg Jan 19, 2026
6c2549d
- uncrustify
trigg Jan 19, 2026
a6fe77b
- roll a custom grid widget to skip space wasted by homogenuous.
trigg Jan 19, 2026
5a7cbab
- uncrustify
trigg Jan 19, 2026
0366906
- uncrust
trigg Jan 19, 2026
0a5c156
- uncrust
trigg Jan 19, 2026
10c6c29
- clean includes
trigg Jan 19, 2026
e9efd46
- uncrust
trigg Jan 19, 2026
bea6b60
- Fix fingerprint reader stopping after an extra suspend and resume
trigg Jan 20, 2026
1806b04
- switching from #ifndef to #pragma once include guards
trigg Jan 20, 2026
68a4ecb
- clean up previous debug
trigg Jan 20, 2026
524c9e2
- uncrust
trigg Jan 20, 2026
89d091a
- better clock defaults
trigg Jan 20, 2026
113b328
- add user id widget
trigg Jan 20, 2026
910b12d
- uncrust
trigg Jan 20, 2026
3ca7f22
- closing browser
trigg Jan 20, 2026
ad575f1
- move enable & position into base plugin
trigg Jan 24, 2026
b6517f8
- Reveal/Hide Ui elements on user interaction & timeout
trigg Jan 25, 2026
4e027ee
- sanity check
trigg Jan 25, 2026
6ec57d7
- explicitly override
trigg Jan 25, 2026
bc4bbdd
Merge branch 'master' into lock
trigg Jan 25, 2026
a3d282d
Add weather plugin
soreau Jan 26, 2026
b70a10d
weather: Add default styling to default.css
soreau Jan 26, 2026
05a643f
weather: Update every 10 minutes
soreau Jan 26, 2026
9bf5458
weather: Remove unused code from header
soreau Jan 26, 2026
42d210f
weather: Remove debug output
soreau Jan 26, 2026
73e3dee
weather-fetch: Add debug option
soreau Jan 26, 2026
5e03690
Merge pull request #57 from soreau/weather
trigg Jan 26, 2026
b529407
- Made fade-in early unlock
trigg Jan 26, 2026
fbed635
- Hide Weather if no file exists
trigg Jan 27, 2026
fa796b8
weather: Use wf-json instead of yyjson
soreau Jan 27, 2026
5a9de24
weather: Update default css
soreau Jan 27, 2026
0170876
Merge pull request #58 from soreau/weather-wf-json
trigg Jan 27, 2026
1eea5ee
Merge pull request #59 from soreau/update-weather-css
trigg Jan 27, 2026
4e90cba
weather: Update weather-fetch.py script
soreau Jan 27, 2026
ed6664b
- theoretical fprintd hot unplug support
trigg Jan 27, 2026
dd5ce35
Merge pull request #60 from soreau/update-weather-script
trigg Jan 27, 2026
3876634
- Moved reveal from per-window to per-widget
trigg Jan 27, 2026
cee74a0
weather: Fix icon broken by refactor
soreau Jan 27, 2026
3e0cb6d
Merge pull request #61 from soreau/fix-weather
trigg Jan 27, 2026
6c8713c
- Fix commas in values 1000 and above
trigg Jan 29, 2026
aac88fe
- Split BackgroundGL out as a widget of its own
trigg Jan 30, 2026
adcf751
- locker pin change app
trigg Jan 31, 2026
41974a3
- uncrust
trigg Jan 31, 2026
960fb00
- uncrust
trigg Jan 31, 2026
d6a9a1d
- add network to locker
trigg Jan 31, 2026
c5dfb93
- uncrust
trigg Jan 31, 2026
f6d7632
Merge branch 'master' into lock
trigg Jan 31, 2026
a0265de
- Fix single-image background path
trigg Jan 31, 2026
201c81f
- uncrust
trigg Jan 31, 2026
c17067c
- Draw a rounded box around password input & output
trigg Feb 1, 2026
54e527f
uncrust
trigg Feb 4, 2026
72b2280
locker: fork and end parent process only on lock success or fail
trigg Feb 6, 2026
7527489
locker: pin limit of 20 digits added
trigg Feb 6, 2026
d52822f
locker: change to one password entry updates all
trigg Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
steps:
- run: echo 'http://dl-cdn.alpinelinux.org/alpine/v3.22/community' > /etc/apk/repositories
- run: echo 'http://dl-cdn.alpinelinux.org/alpine/v3.22/main' >> /etc/apk/repositories
- run: apk --no-cache add git g++ binutils pkgconf meson ninja musl-dev gtkmm4-dev vala gobject-introspection gobject-introspection-dev pulseaudio-dev wireplumber-dev libdbusmenu-glib-dev alsa-lib-dev yyjson-dev
- run: apk --no-cache add git g++ binutils pkgconf meson ninja musl-dev gtkmm4-dev vala gobject-introspection gobject-introspection-dev pulseaudio-dev wireplumber-dev libdbusmenu-glib-dev alsa-lib-dev yyjson-dev linux-pam-dev util-linux-login openssl-dev
- run: echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories
- run: echo 'http://dl-cdn.alpinelinux.org/alpine/edge/main' >> /etc/apk/repositories
- run: apk --no-cache add wayland-protocols wayfire-dev gtk4-layer-shell-dev gtk4-layer-shell
Expand Down
33 changes: 33 additions & 0 deletions data/css/default.css
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,39 @@
animation-fill-mode: forwards;
}

.wf-locker .password{
padding: 10px;
border-radius: 10px;
background: #0004;
}
.wf-locker .fingerprint-overlay-image {
-gtk-icon-size: 64px;
}
.wf-locker .fingerprint-overlay-image.good {
color: #0f0;
}
.wf-locker .fingerprint-overlay-image.bad {
color: #f00;
}
.wf-locker .fingerprint-overlay-image.info {
color: #88f;
}
.wf-locker .mpris image.albumart {
-gtk-icon-size:96px;
}
.wf-locker .user image{
-gtk-icon-size:96px;
}
.wf-locker image.weather {
-gtk-icon-size:80px;
padding-left: 25px;
padding-right: 25px;
padding-bottom: 25px;
}
.wf-locker label.weather {
padding-left: 25px;
}

@keyframes embiggen {
to {
-gtk-icon-size: 64px;
Expand Down
3 changes: 3 additions & 0 deletions data/meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
install_data('wayfire.png', install_dir: icon_dir)
install_data('wallpaper.jpg', install_dir: resource_dir)
install_data('wf-locker-pin.desktop', install_dir: join_paths(get_option('prefix'), 'share', 'applications'))

install_data(join_paths('icons', '48x48', 'wayfire.png'), install_dir: join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', '48x48', 'apps'))
install_data(join_paths('icons', '64x64', 'wayfire.png'), install_dir: join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', '64x64', 'apps'))
Expand All @@ -12,4 +13,6 @@ install_data(join_paths('icons', '256x256', 'wayfire.png'), install_dir: join_pa
install_data(join_paths('icons', '512x512', 'wayfire.png'), install_dir: join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', '512x512', 'apps'))
install_data(join_paths('icons', 'scalable', 'wayfire.svg'), install_dir: join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', 'scalable', 'apps'))

install_data('wf-locker-password', install_dir:'/etc/pam.d/')

subdir('css')
207 changes: 207 additions & 0 deletions data/weather-fetch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2026 Scott Moreau <oreaus@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#

#
# OpenWeatherMap Free API Key Signup
#
# 1) Navigate to https://home.openweathermap.org/users/sign_up
#
# 2) Fill out the form
#
# 3) Complete the captcha
#
# 4) Click Create Account button
#
# 5) Check email and verify account
#
# 6) Wait about 2 hours for the key to become active
#
# 7) Navigate to https://home.openweathermap.org/api_keys
#
# 8) Copy the Default API key for use
#
# 9) Run this script with your API key and location
#
#
# Examples:
#
# $ python weather.py --help
#
# usage: Weather [-h] [-l LOCATION] [-k APIKEY] [-m]
#
# Get weather data with icon.
#
# options:
# -h, --help show this help message and exit
# -l, --location LOCATION
# -k, --apikey APIKEY
# -c, --classic-icons
# -m, --metric
# -d, --debug
#
# Copyright (c) 2026 Scott Moreau <oreaus@gmail.com>
#
# $ python weather.py -k 8b0017275348eaf1a674045c86dadd32 -l 80918
#
# Weather information for Pikeview, US: 15°F - light snow
#
# $ python weather.py -k 8b0017275348eaf1a674045c86dadd32 -l London -m
#
# Weather information for London, GB: 5°C - overcast clouds
#
# Writes ~/.local/share/weather/data/data.json in the following format:
#
# {
# "temp": "5\u00b0C",
# "conditions": "Clouds",
# "icon": "/home/user/.local/share/weather/icons/04n@2x.png"
# }
#
# Applications can then read this file to get the current weather and icon
#
# This script is intended to be run periodically in the background:
#
# while true; do python weather.py [options]; sleep 10m; done
#


from datetime import datetime
from pathlib import Path
import requests
import argparse
import json
import sys
import os

icon_map = {
"01d": "1", # clear sky day
"01n": "33", # clear sky night
"02d": "2", # few clouds day
"02n": "34", # few clouds night
"03d": "3", # scattered clouds day
"03n": "35", # scattered clouds night
"04d": "4", # broken clouds day
"04n": "36", # broken clouds night
"09d": "14", # shower rain day
"09n": "39", # shower rain night
"10d": "13", # rain day
"10n": "40", # rain night
"11d": "16", # thunderstorm day
"11n": "42", # thunderstorm night
"13d": "23", # snow day
"13n": "44", # snow night
"50d": "5", # mist day
"50n": "37", # mist night
}

weather = {}

def get_weather_info():
if weather["api_key"] is None:
print("Set OpenWeatherMap api key to enable weather updates.")
return
if weather["location_key"] is None:
print("Set OpenWeatherMap location to get localized weather updates.")
return

current_time = datetime.now().time()
formatted_time = current_time.strftime("%l:%M:%S")
print(formatted_time, "- Retrieving weather information..")

try:
if weather["metric_units"] is True:
units = "metric"
else:
units = "imperial"
weather_data_url = "http://api.openweathermap.org/data/2.5/weather?q=" + str(weather["location_key"]) + "&units=" + units + "&appid=" + str(weather["api_key"])
weather_data = json.loads(requests.get(weather_data_url).content)
if weather["debug"]:
print(weather_data)
if weather["metric_units"] is True:
weather["temperature"] = str(int(weather_data["main"]["temp"])) + "°C"
else:
weather["temperature"] = str(int(weather_data["main"]["temp"])) + "°F"
weather_icon_code = weather_data["weather"][0]["icon"]
if weather["classic-icons"]:
weather_icon_name = weather_icon_code + "@2x.png"
weather_icon_url = "https://openweathermap.org/img/wn/" + weather_icon_name
else:
weather_icon_name = icon_map[weather_icon_code] + ".svg"
weather_icon_url = "https://www.accuweather.com/assets/images/weather-icons/v2a/" + weather_icon_name
weather_icon_path = weather["icon_directory"] + "/" + weather_icon_name
print(f"Checking for icon {weather_icon_path}")
if not os.path.exists(weather_icon_path):
img_data = requests.get(weather_icon_url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}).content
with open(weather_icon_path, 'wb') as weather_icon:
weather_icon.write(img_data)
print(f"Weather information for {weather_data["name"]}, {weather_data["sys"]["country"]}: {weather["temperature"]} - {weather_data["weather"][0]["description"]}")
data = {
"temp": weather["temperature"],
"conditions": weather_data["weather"][0]["main"],
"icon": weather_icon_path
}
with open(weather["data_directory"] + "/" + "data.json", "w") as file:
json.dump(data, file, indent=4)

except Exception as e:
print("Failed to update weather:", e)
exit(-1)

def main():
parser = argparse.ArgumentParser(
prog="Weather",
description="Get weather data with icon.",
epilog="Copyright (c) 2026 Scott Moreau <oreaus@gmail.com>")
parser.add_argument("-l", "--location")
parser.add_argument("-k", "--apikey")
parser.add_argument("-c", "--classic-icons", action="store_true")
parser.add_argument("-m", "--metric", action="store_true")
parser.add_argument("-d", "--debug", action="store_true")
args = parser.parse_args()
if args.apikey is None:
print("Provide OpenWeatherMap APIKEY with -k or --apikey")
exit(-1)
if args.location is None:
print("Provide OpenWeatherMap location with -l or --location")
exit(-1)
weather["location_key"] = args.location
weather["api_key"] = args.apikey
weather["classic-icons"] = args.classic_icons
weather["metric_units"] = args.metric
weather["debug"] = args.debug

weather["icon_directory"] = os.getenv("HOME") + "/.local/share/weather/icons"
icon_dir = Path(weather["icon_directory"])
if not icon_dir.exists():
icon_dir.mkdir(parents=True, exist_ok=True)

weather["data_directory"] = os.getenv("HOME") + "/.local/share/weather/data"
data_dir = Path(weather["data_directory"])
if not data_dir.exists():
data_dir.mkdir(parents=True, exist_ok=True)

get_weather_info()

if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions data/wf-locker-password
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
auth include login
9 changes: 9 additions & 0 deletions data/wf-locker-pin.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[Desktop Entry]
Version=1.0
Type=Application
Exec=wf-locker-pin
Icon=lock-symbolic
Terminal=false
Name=Wf Shell Change PIN
Categories=Utility;Settings;DesktopSettings;
NotShowIn=GNOME;KDE;
2 changes: 2 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ project(
)

wayfire = dependency('wayfire')
pam = dependency('pam')
wayland_client = dependency('wayland-client')
wayland_protos = dependency('wayland-protocols')
gtkmm = dependency('gtkmm-4.0', version: '>=4.12')
Expand All @@ -26,6 +27,7 @@ dbusmenu_gtk = dependency('dbusmenu-glib-0.4')
libgvc = subproject('gvc', default_options: ['static=true'], required: get_option('pulse'))
xkbregistry = dependency('xkbregistry')
json = subproject('wf-json').get_variable('wfjson')
openssl = dependency('openssl')

if get_option('wayland-logout') == true
wayland_logout = subproject('wayland-logout')
Expand Down
4 changes: 4 additions & 0 deletions metadata/background.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<_short>Randomize</_short>
<default>false</default>
</option>
<option name="blank" type="bool">
<_short>Blank screen on startup</_short>
<default>true</default>
</option>
<option name="fill_mode" type="string">
<_short>Fill mode</_short>
<default>stretch</default>
Expand Down
Loading
Loading