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
53 changes: 53 additions & 0 deletions imagemagick-clock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# ImageMagick Clock

ImageMagick Clock draws a custom clock using ImageMagick (or any other CLI image drawing tool).

## Plugin

| Field | Value |
| --- | --- |
| ID | `jinliu/imagemagick-clock` |
| Entries | Bar widget: `clock` |

## Requirements

* `magick` from `ImageMagick`.
* `mv` from `coreutils`.
* (Optional) [7-Segment font](https://www.dafont.com/seven-segment.font) for a classic digital clock look.

## Usage

Add `ImageMagick Clock` from the Add-widget picker. The widget displays a
custom clock image generated by ImageMagick (or any other CLI image drawing tool).

The default command line is:

```bash
magick -size 270x100 canvas:black -transparent black -pointsize 128 -fill '#FF2400' -draw 'text 0,100 \"%H\"' -fill white -pointsize 84 -draw 'text 120,100 \":%M\"' -fill '#FF2400' -stroke '#FF2400' -strokewidth 5 -draw 'line 225,0 225,100' -strokewidth 0 -stroke white -fill white -pointsize 32 -draw 'text 235, 25 \"%m\"' -draw 'text 235, 60 \"%d\"' -draw 'text 235, 95 \"%a\"' '%output_file'
```

You can customize the command line in the widget's configuration to change how the clock looks. The "%output_file" placeholder will be replaced with the path to the file where the clock image should be saved. Other placeholders like "%H", "%M", "%a" will be replaced with the hour, minute, and day of the week, etc. See `man strftime` for the complete list of placeholders.

You might want to install the `7-Segment` font to get a classic digital clock look. Add `-font '7-Segment'` to the command line after `magick` to use it. The command line would then look like this:

```bash
magick -font '7-Segment' -size 270x100 canvas:black -transparent black -pointsize 128 -fill '#FF2400' -draw 'text 0,100 \"%H\"' -fill white -pointsize 84 -draw 'text 120,100 \":%M\"' -fill '#FF2400' -stroke '#FF2400' -strokewidth 5 -draw 'line 225,0 225,100' -strokewidth 0 -stroke white -fill white -pointsize 32 -draw 'text 235, 25 \"%m\"' -draw 'text 235, 60 \"%d\"' -draw 'text 235, 95 \"%a\"' '%output_file'
```

If your locale uses characters that are not supported by the `7-Segment` font (e.g., Chinese), you might want to set a different font before the last `-draw` command. For example:

```bash
magick -font '7-Segment' -size 270x100 canvas:black -transparent black -pointsize 128 -fill '#FF2400' -draw 'text 0,100 \"%H\"' -fill white -pointsize 84 -draw 'text 120,100 \":%M\"' -fill '#FF2400' -stroke '#FF2400' -strokewidth 5 -draw 'line 225,0 225,100' -strokewidth 0 -stroke white -fill white -pointsize 32 -draw 'text 235, 25 \"%m\"' -draw 'text 235, 60 \"%d\"' -stroke none -font Noto-Sans-CJK-SC-Bold -draw 'text 235, 95 \"%a\"' '%output_file'
```

(Note: You can list all available fonts on your system by running `magick -list font`.)

You can use any command-line drawing tool, not just ImageMagick, as long as it generates an image file at the specified output path. The plugin will call the command at the beginning of every minute to generate a new clock image for the next minute. Therefore, your command can take up to a full minute to generate one image, though I wouldn't recommend something that heavy.

## Settings

| Setting | Type | Default | Description |
| --- | --- | --- | --- |
| `command_line` | `string` | (too long, omitted) | The command line to draw the clock |
| `image_width` | `int` | 54 | The width of the clock image |
| `image_height` | `int` | 20 | The height of the clock image |
39 changes: 39 additions & 0 deletions imagemagick-clock/plugin.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
id = "jinliu/imagemagick-clock"
name = "ImageMagick Clock"
version = "1.0.0"
plugin_api = 3
author = "Jin Liu"
tags = ["clock"]
Comment thread
jinliu marked this conversation as resolved.
icon = "clock"
description = "A custom clock drawn with ImageMagick."
dependencies = ["magick", "mv"]
license = "MIT"

[[widget]]
id = "clock"
entry = "widget.luau"

[[widget.setting]]
key = "command_line"
type = "string"
label_key = "settings.cmdline.label"
description_key = "settings.cmdline.description"
default = "magick -size 270x100 canvas:black -transparent black -pointsize 128 -fill '#FF2400' -draw 'text 0,100 \"%H\"' -fill white -pointsize 84 -draw 'text 120,100 \":%M\"' -fill '#FF2400' -stroke '#FF2400' -strokewidth 5 -draw 'line 225,0 225,100' -strokewidth 0 -stroke white -fill white -pointsize 32 -draw 'text 235, 25 \"%m\"' -draw 'text 235, 60 \"%d\"' -draw 'text 235, 95 \"%a\"' '%output_file'"

[[widget.setting]]
key = "image_width"
type = "int"
label_key = "settings.image_width.label"
Comment thread
Copilot marked this conversation as resolved.
description_key = "settings.image_width.description"
default = 54
min = 1
max = 1000

[[widget.setting]]
key = "image_height"
type = "int"
label_key = "settings.image_height.label"
Comment thread
Copilot marked this conversation as resolved.
description_key = "settings.image_height.description"
default = 20
min = 1
max = 1000
Binary file added imagemagick-clock/thumbnail.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions imagemagick-clock/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"settings": {
"cmdline": {
"label": "Command line",
"description": "The command should generate an image file to be displayed as the clock. `%output_file` will be replaced with the path to the output file. Then `%H`, `%M`, etc. will be replaced with the current time values. See `man strftime` for more formatting options."
},
"image_width": {
"label": "Image width",
"description": "The display width of the clock image in logical pixels. (Not the width of the generated image file.)"
},
"image_height": {
"label": "Image height",
"description": "The display height of the clock image in logical pixels. (Not the height of the generated image file.)"
}
}
}
91 changes: 91 additions & 0 deletions imagemagick-clock/widget.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
local CMDLINE_TEMPLATE = noctalia.getConfig("command_line")
local IMAGE_WIDTH = noctalia.getConfig("image_width")
local IMAGE_HEIGHT = noctalia.getConfig("image_height")

local OUTPUT_DIR = noctalia.pluginDataDir()
local CURRENT_CLOCK_FACE_PATH = OUTPUT_DIR .. "/current.png"
local NEXT_CLOCK_FACE_PATH = OUTPUT_DIR .. "/next.png"

local generatingClockFace = false
local movingClockFace = false
local nextClockFaceReady = false
local nextClockFaceTimestamp = nil

local function drawClockFace(timestamp)
if generatingClockFace then
return
end

generatingClockFace = true

local cmdline = string.gsub(CMDLINE_TEMPLATE, "%%output_file", NEXT_CLOCK_FACE_PATH)
cmdline = os.date(cmdline, timestamp)
-- print("Running command: " .. cmdline)

noctalia.runAsync(cmdline, function(result)
generatingClockFace = false
nextClockFaceTimestamp = timestamp
if result.exitCode == 0 then
nextClockFaceReady = true
else
print("Error generating clock face: " .. result.stderr .. " (command: " .. cmdline .. ") " .. "output: " .. result.stdout)
nextClockFaceReady = false
end
end)
end

local function drawCurrentClockFace()
local timestamp = os.time()
local time = os.date("*t", timestamp)
local currentTimestamp = timestamp - time.sec
-- print("Drawing current clock face at " .. os.date("%H:%M:%S", nextTimestamp))
drawClockFace(currentTimestamp)
end

local function drawNextClockFace()
local timestamp = os.time()
local time = os.date("*t", timestamp)
local nextTimestamp = timestamp - time.sec + 60
-- print("Drawing next clock face at " .. os.date("%H:%M:%S", nextTimestamp))
drawClockFace(nextTimestamp)
end

function update()
local timestamp = os.time()
if generatingClockFace or movingClockFace or (nextClockFaceTimestamp and timestamp < nextClockFaceTimestamp and timestamp >= nextClockFaceTimestamp - 60) then
return
end

if not nextClockFaceTimestamp or timestamp >= nextClockFaceTimestamp + 60 or timestamp < nextClockFaceTimestamp - 60 then
-- Next clock face unavailable (startup), or doesn't match current time (resume from sleep, or system clock changed).
-- Either case, draw the current clock face immediately.
drawCurrentClockFace()
return
end

if nextClockFaceReady then
nextClockFaceReady = false
movingClockFace = true
noctalia.runAsync("mv -f '" .. NEXT_CLOCK_FACE_PATH .. "' '" .. CURRENT_CLOCK_FACE_PATH .. "'", function(result)
movingClockFace = false
if result.exitCode == 0 then
barWidget.setImage(CURRENT_CLOCK_FACE_PATH, true, IMAGE_WIDTH, IMAGE_HEIGHT)
else
print("Error moving new clock face: " .. result.stderr .. " (command: mv -f " .. NEXT_CLOCK_FACE_PATH .. " " .. CURRENT_CLOCK_FACE_PATH .. ") " .. "output: " .. result.stdout)
end
drawNextClockFace()
end)
else
drawNextClockFace()
end
end

function onClick()
noctalia.runAsync("noctalia msg panel-toggle control-center calendar", function(result)
if result.exitCode ~= 0 then
print("Error toggling calendar panel: " .. result.stderr .. " (command: noctalia msg panel-toggle control-center calendar) " .. "output: " .. result.stdout)
end
end)
end

noctalia.setUpdateInterval(1000)