Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
38 changes: 21 additions & 17 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@ go 1.23.0
toolchain go1.24.4

require (
github.com/StackExchange/wmi v1.2.1
github.com/capnspacehook/taskmaster v0.0.0-20210519235353-1629df7c85e9
github.com/go-ole/go-ole v1.3.0
github.com/google/deck v1.1.0
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.3.0
github.com/google/winops v0.0.0-20210803215038-c8511b84de2b
github.com/iamacarpet/go-win64api v0.0.0-20240507095429-873e84e85847
github.com/pkg/errors v0.9.1
github.com/scjalliance/comshim v0.0.0-20250111221056-b2ef9d8d7e0f
golang.org/x/sys v0.34.0
github.com/StackExchange/wmi v1.2.1
github.com/capnspacehook/taskmaster v0.0.0-20210519235353-1629df7c85e9
github.com/fogleman/gg v1.3.0
github.com/go-ole/go-ole v1.3.0
github.com/google/deck v1.1.0
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.3.0
github.com/google/winops v0.0.0-20210803215038-c8511b84de2b
github.com/iamacarpet/go-win64api v0.0.0-20240507095429-873e84e85847
github.com/pkg/errors v0.9.1
github.com/scjalliance/comshim v0.0.0-20250111221056-b2ef9d8d7e0f
golang.org/x/sys v0.34.0
)

require (
github.com/google/cabbie v1.0.5 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/rickb777/date v1.21.1 // indirect
github.com/rickb777/plural v1.4.4 // indirect
gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 // indirect
)
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/cabbie v1.0.5 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/rickb777/date v1.21.1 // indirect
github.com/rickb777/plural v1.4.4 // indirect
golang.org/x/image v0.21.0 // indirect
golang.org/x/net v0.27.0 // indirect
gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 // indirect
)
8 changes: 7 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9
github.com/capnspacehook/taskmaster v0.0.0-20210519235353-1629df7c85e9 h1:5jmtWADt5DzD8NnPxcqd1FzbFNZNfbJGNeDb+WKjoJ0=
github.com/capnspacehook/taskmaster v0.0.0-20210519235353-1629df7c85e9/go.mod h1:257CYs3Wd/CTlLQ3c72jKv+fFE2MV3WPNnV5jiroYUU=
github.com/creachadair/staticfile v0.1.3/go.mod h1:a3qySzCIXEprDGxk6tSxSI+dBBdLzqeBOMhZ+o2d3pM=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
Expand All @@ -14,6 +16,8 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
Expand Down Expand Up @@ -72,6 +76,8 @@ github.com/scjalliance/comshim v0.0.0-20250111221056-b2ef9d8d7e0f h1:v+bqkkvZj6O
github.com/scjalliance/comshim v0.0.0-20250111221056-b2ef9d8d7e0f/go.mod h1:Zt2M6t3i/fnWviIZkuw9wGn2E185P/rWZTqJkIrViGY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
Expand Down Expand Up @@ -122,4 +128,4 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
131 changes: 131 additions & 0 deletions go/lockscreenui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Glazier Lock Screen UI Manager

<!--* freshness: { owner: '@mjoliver' reviewed: '2026-06-11' } *-->

`lockscreenui` is a robust, reusable Go library for displaying provisioning,
installation, or configuration progress directly on the Windows lock screen
(`LogonUI.exe`).

It is fully configurable, supporting custom background images, solid background
colors, tailored title prefixes, and custom footer messages.

## Features

* **Seamless Lock Screen Integration**: Dynamically generates progress
wallpaper frames and applies them via Windows Group Policy registry keys
(`SOFTWARE\Policies\Microsoft\Windows\Personalization\LockScreenImage`).
* **Instant Visual Updates**: Safely refreshes the Windows logon screen
(`taskkill /F /IM LogonUI.exe`) to force immediate redraws without requiring
a reboot.
* **Reboot Resilient**: Because Group Policy registry keys persist across
restarts, Windows Winlogon automatically displays the latest progress screen
immediately upon bootup.
* **Flexible Overlay Positioning**: Supports placing the progress box in the
`center`, `top`, or `bottom` of the screen to avoid overlapping with active
Windows login credential tiles.
* **Distinct Error Alerting**: Provides a dedicated `UpdateLockScreenError`
API that renders a striking translucent dark red alert box to notify users
of failures and guide them on recovery steps.
* **Automatic Footprint Cleanup**: Includes a clean `Cleanup()` method to
remove Group Policy overrides and purge temporary image files once
provisioning is complete.

## Usage Example

```go
package main

import (
"context"
"image/color"
"log"

"github.com/google/glazier/go/lockscreenui"
)

func main() {
ctx := context.Background()

// 1. Define configuration
cfg := lockscreenui.Config{
TempDir: `C:\Provisioning\TempScreens`,
BgColor: color.RGBA{0, 120, 215, 255}, // Solid Windows Blue
TitlePrefix: "System Setup: ",
FooterText: "Please do not turn off your computer",
ErrorTitle: "Setup Error (Step Failed)",
ErrorFooterText: "Please reboot the machine to retry setup",
OverlayPosition: lockscreenui.PositionBottom, // Position at the bottom to avoid credential tiles
}

// 2. Initialize UI Manager
ui, err := lockscreenui.NewProvisioningUI(ctx, cfg)
if err != nil {
log.Fatalf("Failed to initialize UI: %v", err)
}
defer ui.Cleanup(ctx) // Ensures policies and temp files are removed upon exit

// 3. Update Progress
if err := ui.UpdateLockScreen(ctx, 1, "Step 1 of 3: Installing system packages..."); err != nil {
log.Printf("Progress update failed: %v", err)
}

// 4. Report Error (if a step fails)
// ui.UpdateLockScreenError(ctx, 1, "Package download failed: network timeout")
}
```

## Embedding a Custom Background Image

You can bake a custom background image (JPEG or PNG) directly into your compiled
Go binary using Go's native `//go:embed` directive. This ensures your tool
remains a single standalone executable without relying on external asset files
on the host machine.

```go
package main

import (
"bytes"
"context"
"embed"
"image"
"log"

"github.com/google/glazier/go/lockscreenui"

_ "image/jpeg" // Essential for decoding embedded JPEG images
)

//go:embed assets/wallpaper.jpeg
var embeddedFS embed.FS

func main() {
ctx := context.Background()

// 1. Read and decode the embedded image
data, err := embeddedFS.ReadFile("assets/wallpaper.jpeg")
if err != nil {
log.Fatalf("Failed to read embedded image: %v", err)
}
img, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
log.Fatalf("Failed to decode embedded image: %v", err)
}

// 2. Pass the decoded image to the configuration
cfg := lockscreenui.Config{
TempDir: `C:\Provisioning\TempScreens`,
BaseImage: img,
TitlePrefix: "Setup: ",
OverlayPosition: lockscreenui.PositionBottom,
}

ui, err := lockscreenui.NewProvisioningUI(ctx, cfg)
if err != nil {
log.Fatalf("Failed to initialize UI: %v", err)
}
defer ui.Cleanup(ctx)

ui.UpdateLockScreen(ctx, 1, "Applying embedded background...")
}
```
Loading
Loading