You are not logged in.
Two modular Conky widgets built with Cairo and full Plasma color integration.
Both widgets follow the system locale (no hardcoded language), so month names and weekday labels automatically match the user’s environment.
The Clock and Calendar modules are finished and fully functional, using a shared common.lua framework for background rendering, theme updates, and Cairo helpers.
The goal is to build a complete, consistent Conky widget pack for Plasma, with additional modules (CPU, RAM, Disk, Network, GPU, Weather) currently in development.
Feedback, ideas, and suggestions from the community are very welcome.

common.lua
-- PLASMA COLORS & AUTO-UPDATE LOGIC
PLASMA = PLASMA or {}
local last_color_update = 0
local color_update_interval = 5 -- 5 másodpercenként frissít
local function parse_rgb_to_table(str, alpha)
local r, g, b = str:match("(%d+),(%d+),(%d+)")
if not r then return { 1, 1, 1, alpha or 1 } end
return { tonumber(r) / 255, tonumber(g) / 255, tonumber(b) / 255, alpha or 1 }
end
local function load_kdeglobals()
local path = os.getenv("HOME") .. "/.config/kdeglobals"
local f = io.open(path, "r")
if not f then return end
local section = nil
-- Meglévő táblát frissítünk, nem töröljük le az egészet
for line in f:lines() do
local s = line:match("^%[(.+)%]$")
if s then
section = s
else
local key, val = line:match("^([^=]+)=([%d,]+)")
if not key or not val then goto continue end
-- WINDOW COLORS (Ablakkeret/Sávok)
if section == "Colors:Window" then
if key == "BackgroundNormal" then
PLASMA.bg_panel = parse_rgb_to_table(val, 1.0)
elseif key == "ForegroundNormal" then
PLASMA.text_main = parse_rgb_to_table(val, 1.0)
elseif key == "ForegroundInactive" then
PLASMA.text_dim = parse_rgb_to_table(val, 0.7)
end
-- VIEW COLORS (Dolphin háttér - ez a nyerő!)
elseif section == "Colors:View" then
if key == "BackgroundNormal" then
PLASMA.bg_widget = parse_rgb_to_table(val, 1.0)
elseif key == "BackgroundAlternate" then
PLASMA.bg_alt = parse_rgb_to_table(val, 1.0)
end
-- SELECTION (Accent)
elseif section == "Colors:Selection" then
if key == "BackgroundNormal" then
PLASMA.accent = parse_rgb_to_table(val, 1.0)
end
-- BUTTON (Pozitív/Negatív)
elseif section == "Colors:Button" then
if key == "ForegroundPositive" then
PLASMA.positive = parse_rgb_to_table(val, 1.0)
elseif key == "ForegroundNegative" then
PLASMA.negative = parse_rgb_to_table(val, 1.0)
end
end
::continue::
end
end
f:close()
PLASMA.bg_panel = PLASMA.bg_panel or { 0.15, 0.17, 0.19, 1.0 }
PLASMA.bg_widget = PLASMA.bg_widget or { 0.12, 0.14, 0.16, 1.0 }
PLASMA.text_main = PLASMA.text_main or { 1.0, 1.0, 1.0, 1.0 }
PLASMA.text_dim = PLASMA.text_dim or { 0.7, 0.7, 0.7, 1.0 }
PLASMA.accent = PLASMA.accent or { 0.24, 0.6, 0.95, 1.0 }
end
function check_theme_update()
local now = os.time()
if now - last_color_update >= color_update_interval then
load_kdeglobals()
last_color_update = now
end
end
load_kdeglobals()
-- COMMON TOOLS
--{{{
require 'cairo'
local ok, cairo_xlib = pcall(require, 'cairo_xlib')
if not ok then
cairo_xlib = setmetatable({}, {
__index = function(_, k) return _G[k] end
})
end
function conky_ready()
local u = tonumber(conky_parse("${updates}")) or 0
if u < 5 then return false end
if conky_window == nil then return false end
if conky_window.width == 0 or conky_window.height == 0 then return false end
return true
end
-- CACHE
cache = cache or {}
function cached(key, interval, func)
local now = os.time()
local entry = cache[key]
if entry and (now - entry.time < interval) then
return entry.value
end
local value = func()
cache[key] = { time = now, value = value }
return value
end
function pread(cmd)
local f = io.popen(cmd)
if not f then
return ""
end
local out = f:read("*a") or ""
f:close()
return out:gsub("%s+$", "")
end
function read_file(path)
local f = io.open(path, "r")
if not f then
return ""
end
local out = f:read("*a") or ""
f:close()
return out:gsub("%s+$", "")
end
function has_cmd(cmd)
local ok = os.execute("command -v " .. cmd .. " >/dev/null 2>&1")
return ok ~= nil and ok ~= false
end
function normalize_number(v)
if not v then return 0 end
v = tostring(v):gsub(",", ".")
v = v:match("([%d%.]+)")
return tonumber(v) or 0
end
function normalize_with_suffix(raw)
if not raw then return 0 end
raw = tostring(raw):lower():gsub("%s+", "")
raw = raw:gsub("b$", "")
local num = raw:match("([%d%.]+)")
if not num then return 0 end
local base = normalize_number(num)
local suf = raw:match("([kmg])$")
if suf == "k" then return base * 1024 end
if suf == "m" then return base * 1024 * 1024 end
if suf == "g" then return base * 1024 * 1024 * 1024 end
return base
end
function draw_allowed(flag)
if flag == nil or flag == true then return true end
return conky_parse(tostring(flag)) == "1"
end
local function parse_rgb(str)
local r, g, b = str:match("(%d+),(%d+),(%d+)")
return tonumber(r) / 255, tonumber(g) / 255, tonumber(b) / 255
end
--}}}
-- BACKGROUND
backgrounds = backgrounds or {}
-- Alap háttér preset (minden widget ezt használja, ha nem adsz mást)
backgrounds.default = {
draw_me = true, -- rajzoljuk-e
x = 0, -- bal felső sarok X
y = 0, -- bal felső sarok Y
w = 0, -- 0 = automatikus (conky_window.width)
h = 0, -- 0 = automatikus (conky_window.height)
radius = 10, -- lekerekítés sugara
border_width = 1, -- keret vastagsága
-- Színek:
-- nil → automatikusan PLASMA.bg_widget / PLASMA.text_dim
bg_color = nil,
border_color = nil,
}
-- Ha valaha több stílust akarsz:
-- backgrounds.rounded = { ... }
-- backgrounds.flat = { ... }
-- backgrounds.panel = { ... }
BACKGROUND_DEFAULT = {
x = 0,
y = 0,
radius = 10,
border_width = 1,
}
function draw_background(cr, cfg)
-- 1. Alapértelmezett értékek betöltése (DE a színeket nem mentjük el a cfg-be, ha nil-ek!)
local x = cfg.x or BACKGROUND_DEFAULT.x
local y = cfg.y or BACKGROUND_DEFAULT.y
local r = cfg.radius or BACKGROUND_DEFAULT.radius
local border_w = cfg.border_width or BACKGROUND_DEFAULT.border_width
if not draw_allowed(cfg.draw_me) then return end
local bg = cfg.bg_color or PLASMA.bg_widget
local bc = cfg.border_color or PLASMA.text_dim
local w = (cfg.w == 0 or cfg.w == nil) and conky_window.width or cfg.w
local h = (cfg.h == 0 or cfg.h == nil) and conky_window.height or cfg.h
cairo_new_sub_path(cr)
cairo_arc(cr, x + w - r, y + r, r, -math.pi / 2, 0)
cairo_arc(cr, x + w - r, y + h - r, r, 0, math.pi / 2)
cairo_arc(cr, x + r, y + h - r, r, math.pi / 2, math.pi)
cairo_arc(cr, x + r, y + r, r, math.pi, 3 * math.pi / 2)
cairo_close_path(cr)
cairo_set_source_rgba(cr, bg[1], bg[2], bg[3], bg[4] or 1)
cairo_fill_preserve(cr)
cairo_set_line_width(cr, border_w)
cairo_set_source_rgba(cr, bc[1], bc[2], bc[3], bc[4] or 1)
cairo_stroke(cr)
end
-- BARS
--{{{
local BAR_DEFAULT = {
draw_me = true,
x = 0,
y = 0,
w = 200,
h = 10,
max = 100,
fg_color = nil, -- ha nil → PLASMA.accent
bg_color = nil, -- ha nil → PLASMA.bg_widget
}
function draw_flat_bar(cr, m)
-- Merge defaults
for k, v in pairs(BAR_DEFAULT) do
if m[k] == nil then m[k] = v end
end
if not draw_allowed(m.draw_me) then return end
local fg = m.fg_color or PLASMA.accent
local bg = m.bg_color or PLASMA.bg_widget
local raw
if type(m.name) == "number" then
raw = m.name
else
raw = normalize_with_suffix(conky_parse(string.format("${%s %s}", m.name, m.arg or "")))
end
local pct = math.max(0, math.min(1, raw / m.max))
cairo_set_source_rgba(cr, bg[1], bg[2], bg[3], bg[4] or 1)
cairo_rectangle(cr, m.x, m.y, m.w, m.h)
cairo_fill(cr)
if pct > 0 then
cairo_set_source_rgba(cr, fg[1], fg[2], fg[3], fg[4] or 1)
cairo_rectangle(cr, m.x, m.y, m.w * pct, m.h)
cairo_fill(cr)
end
end
--}}}
-- GRAPS
--{{{
local GRAPH_DEFAULT = {
draw_me = true,
x = 0,
y = 0,
w = 200,
h = 50,
overlay = false,
background = true,
bg_color = nil, -- ha nil → PLASMA.bg_widget
border = true,
border_color = nil, -- ha nil → PLASMA.text_dim
border_width = 1,
line = true,
line_color = nil, -- ha nil → PLASMA.accent
grid = true,
grid_color = nil, -- ha nil → PLASMA.text_main (0.10 alpha)
autoscale = true,
max = 100,
}
graph_history = graph_history or {}
function draw_plasma_graph(cr, g)
-- Defaults
for k, v in pairs(GRAPH_DEFAULT) do
if g[k] == nil then g[k] = v end
end
if not draw_allowed(g.draw_me) then return end
local bg = g.bg_color or PLASMA.bg_panel
local bc = g.border_color or PLASMA.text_dim
local lc = g.line_color or PLASMA.accent
local gc = g.grid_color or { PLASMA.text_main[1], PLASMA.text_main[2], PLASMA.text_main[3], 0.08 }
if g.overlay then
g.background = false
g.border = false
g.grid = false
end
------------------------------------------------------------
local key = tostring(g.name) .. (g.arg or "")
if not graph_history[key] then
graph_history[key] = {}
for i = 1, g.w do graph_history[key][i] = 0 end
end
local raw
if type(g.name) == "number" then
raw = g.name
else
raw = normalize_with_suffix(conky_parse(string.format("${%s %s}", g.name, g.arg or "")))
end
table.remove(graph_history[key], 1)
table.insert(graph_history[key], raw)
-- Autoscale
local max_val = g.max
if g.autoscale then
max_val = 0
for _, v in ipairs(graph_history[key]) do
if v > max_val then max_val = v end
end
max_val = max_val * 1.1
end
if max_val <= 0 then max_val = 1 end
if g.background then
cairo_set_source_rgba(cr, bg[1], bg[2], bg[3], bg[4] or 1)
cairo_rectangle(cr, g.x, g.y, g.w, g.h)
cairo_fill(cr)
end
if g.grid then
cairo_set_source_rgba(cr, gc[1], gc[2], gc[3], gc[4] or 1)
cairo_set_line_width(cr, 1)
local steps = 4
for i = 1, steps - 1 do
local gy = g.y + (g.h / steps) * i
cairo_move_to(cr, g.x, gy)
cairo_line_to(cr, g.x + g.w, gy)
cairo_stroke(cr)
end
end
if g.border then
cairo_set_source_rgba(cr, bc[1], bc[2], bc[3], bc[4] or 1)
cairo_set_line_width(cr, g.border_width)
cairo_rectangle(cr, g.x, g.y, g.w, g.h)
cairo_stroke(cr)
end
if g.line then
cairo_set_source_rgba(cr, lc[1], lc[2], lc[3], lc[4] or 1)
cairo_set_line_width(cr, 1)
for i = 2, g.w do
local v1 = graph_history[key][i - 1] / max_val
local v2 = graph_history[key][i] / max_val
cairo_move_to(cr, g.x + i - 2, g.y + g.h - (v1 * g.h))
cairo_line_to(cr, g.x + i - 1, g.y + g.h - (v2 * g.h))
cairo_stroke(cr)
end
end
end
--}}}
-- TEXT
--{{{
TEXT_DEFAULT = {
text = "",
draw_me = true,
x = 0,
y = 0,
font = "Ubuntu",
size = 11,
slant = "normal",
weight = "normal",
align = "left",
color = nil, -- ha nil → PLASMA.text_main
}
local function normalize_text(opts)
if not opts or not opts.text then return nil end
local txt = tostring(opts.text)
return (opts.conky ~= false) and conky_parse(txt) or txt
end
function draw_text(cr, opts)
if not opts or not draw_allowed(opts.draw_me) then return end
-- defaults merge
local cfg = {}
for k, v in pairs(TEXT_DEFAULT) do cfg[k] = v end
for k, v in pairs(opts) do cfg[k] = v end
-- Plasma fallback
local col = cfg.color or PLASMA.text_main
local txt = normalize_text(cfg)
if not txt or txt == "" then return end
local slant = (cfg.slant == "italic") and CAIRO_FONT_SLANT_ITALIC or CAIRO_FONT_SLANT_NORMAL
local weight = (cfg.weight == "bold") and CAIRO_FONT_WEIGHT_BOLD or CAIRO_FONT_WEIGHT_NORMAL
cairo_select_font_face(cr, cfg.font, slant, weight)
cairo_set_font_size(cr, cfg.size)
local ext = cairo_text_extents_t:create()
cairo_text_extents(cr, txt, ext)
local x, y = cfg.x, cfg.y
-- center handling
if x == "center" then x = conky_window.width / 2 end
if y == "center" then y = conky_window.height / 2 end
-- alignment
if cfg.align == "center" then
x = x - ext.width / 2
elseif cfg.align == "right" then
x = x - ext.width
end
-- baseline correction
y = y - ext.y_bearing
-- Plasma RGBA
cairo_set_source_rgba(cr, col[1], col[2], col[3], col[4] or 1)
cairo_move_to(cr, x, y)
cairo_show_text(cr, txt)
cairo_stroke(cr)
end
--}}}
-- LINES
--{{{
local LINE_DEFAULT = {
draw_me = true,
x1 = 0,
y1 = 0,
x2 = 100,
y2 = 0,
style = "solid", -- solid | dashed | dotted
cell_size = 6,
dash_on = 0.6,
thickness = 2,
-- új: RGBA, nem hex
color = nil, -- ha nil → PLASMA.text_main
}
function draw_line(cr, opts)
-- defaults merge
local cfg = {}
for k, v in pairs(LINE_DEFAULT) do cfg[k] = v end
for k, v in pairs(opts) do cfg[k] = v end
if not draw_allowed(cfg.draw_me) then return end
-- Plasma fallback
local col = cfg.color or PLASMA.text_main
local x1, y1, x2, y2 = cfg.x1, cfg.y1, cfg.x2, cfg.y2
local dx, dy = x2 - x1, y2 - y1
local L = math.sqrt(dx * dx + dy * dy)
if L < 1 then return end
local cs = cfg.cell_size
local count = math.floor(L / cs)
if count < 1 then return end
local gap = (L - (count * cs)) / (count - 1)
local nx, ny = dx / L, dy / L
cairo_set_source_rgba(cr, col[1], col[2], col[3], col[4] or 1)
cairo_set_line_width(cr, cfg.thickness)
for i = 0, count - 1 do
local base_dist = i * (cs + gap)
local cx1 = x1 + nx * base_dist
local cy1 = y1 + ny * base_dist
if cfg.style == "solid" then
local cx2 = x1 + nx * (base_dist + cs)
local cy2 = y1 + ny * (base_dist + cs)
cairo_move_to(cr, cx1, cy1)
cairo_line_to(cr, cx2, cy2)
cairo_stroke(cr)
elseif cfg.style == "dashed" then
local on_len = cs * cfg.dash_on
local ex = x1 + nx * (base_dist + on_len)
local ey = y1 + ny * (base_dist + on_len)
cairo_move_to(cr, cx1, cy1)
cairo_line_to(cr, ex, ey)
cairo_stroke(cr)
elseif cfg.style == "dotted" then
local mid = base_dist + cs / 2
local px = x1 + nx * mid
local py = y1 + ny * mid
cairo_arc(cr, px, py, cfg.thickness / 2, 0, 2 * math.pi)
cairo_fill(cr)
end
end
end
--}}}
-- IMAGES
--{{{
local PNG_DEFAULT = {
draw_me = true,
path = nil,
x = 0,
y = 0,
w = nil,
h = nil,
}
function draw_png(cr, opts)
-- Merge defaults
local cfg = {}
for k, v in pairs(PNG_DEFAULT) do cfg[k] = v end
for k, v in pairs(opts) do cfg[k] = v end
if not draw_allowed(cfg.draw_me) or not cfg.path then return end
-- File existence check
local f = io.open(cfg.path, "rb")
if not f then return end
f:close()
-- Create surface from PNG
local img = cairo_image_surface_create_from_png(cfg.path)
if cairo_surface_status(img) ~= 0 then
cairo_surface_destroy(img)
return
end
local iw = cairo_image_surface_get_width(img)
local ih = cairo_image_surface_get_height(img)
-- Scaling logic
local sx = cfg.w and (cfg.w / iw) or 1
local sy = cfg.h and (cfg.h / ih) or 1
-- If only one dimension is provided, preserve aspect ratio
if cfg.w and not cfg.h then sy = sx end
if cfg.h and not cfg.w then sx = sy end
cairo_save(cr)
cairo_translate(cr, cfg.x, cfg.y)
cairo_scale(cr, sx, sy)
cairo_set_source_surface(cr, img, 0, 0)
cairo_paint(cr)
cairo_restore(cr)
cairo_surface_destroy(img)
end
--}}}
-- CLOCK
--{{{
function draw_clock(cr, cfg)
if not draw_allowed(cfg.draw_me) then return end
if conky_window == nil then return end
local x = cfg.x
local y = cfg.y
local r = cfg.radius
-- Plasma színek
local bg = PLASMA.bg_widget
local border = PLASMA.text_dim
local tick = PLASMA.text_main
local number = PLASMA.text_main
local hour_c = PLASMA.text_main
local min_c = PLASMA.text_main
local sec_c = PLASMA.accent
local center = PLASMA.text_main
local hours = tonumber(os.date("%I"))
local minutes = tonumber(os.date("%M"))
local seconds = tonumber(os.date("%S"))
local sec_angle = (seconds / 60) * 2 * math.pi
local min_angle = (minutes / 60) * 2 * math.pi
local hour_angle = ((hours % 12) / 12 + minutes / 720) * 2 * math.pi
cairo_set_source_rgba(cr, bg[1], bg[2], bg[3], bg[4])
cairo_arc(cr, x, y, r, 0, 2 * math.pi)
cairo_fill(cr)
cairo_set_source_rgba(cr, border[1], border[2], border[3], border[4])
cairo_set_line_width(cr, 2)
cairo_arc(cr, x, y, r, 0, 2 * math.pi)
cairo_stroke(cr)
--------------------------------------------------------
-- TICKS
--------------------------------------------------------
if cfg.show_ticks then
for i = 0, 59 do
local angle = (i / 60) * 2 * math.pi
local sin_a = math.sin(angle)
local cos_a = math.cos(angle)
local is_hour = (i % 5 == 0)
local tick_len = is_hour and 10 or 5
local tick_w = is_hour and cfg.tick_width_hour or cfg.tick_width_minute
cairo_set_source_rgba(cr, tick[1], tick[2], tick[3], tick[4])
cairo_set_line_width(cr, tick_w)
cairo_move_to(cr, x + sin_a * (r - tick_len), y - cos_a * (r - tick_len))
cairo_line_to(cr, x + sin_a * r, y - cos_a * r)
cairo_stroke(cr)
end
end
if cfg.show_numbers then
cairo_select_font_face(cr, "Ubuntu", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD)
cairo_set_font_size(cr, cfg.number_size)
for i = 1, 12 do
local angle = (i / 12) * 2 * math.pi
local sin_a = math.sin(angle)
local cos_a = math.cos(angle)
local nx = x + sin_a * (r * cfg.number_radius)
local ny = y - cos_a * (r * cfg.number_radius)
cairo_set_source_rgba(cr, number[1], number[2], number[3], number[4])
local text = tostring(i)
local ext = cairo_text_extents_t:create()
cairo_text_extents(cr, text, ext)
cairo_move_to(cr, nx - ext.width / 2, ny + ext.height / 2)
cairo_show_text(cr, text)
end
end
local function draw_hand(angle, length, width, col)
cairo_set_source_rgba(cr, col[1], col[2], col[3], col[4])
cairo_set_line_width(cr, width)
cairo_move_to(cr, x, y)
cairo_line_to(cr, x + math.sin(angle) * length, y - math.cos(angle) * length)
cairo_stroke(cr)
end
draw_hand(hour_angle, r * 0.5, cfg.hour_hand_width, hour_c)
draw_hand(min_angle, r * 0.75, cfg.minute_hand_width, min_c)
if cfg.show_seconds then
draw_hand(sec_angle, r * 0.9, cfg.second_hand_width, sec_c)
end
cairo_set_source_rgba(cr, center[1], center[2], center[3], center[4])
cairo_arc(cr, x, y, cfg.center_radius, 0, 2 * math.pi)
cairo_fill(cr)
end
--}}}
-- CALENDAR
--{{{
function get_cal_monthname()
return pread("date +%B' '%Y")
end
function get_cal_weekdays()
-- A cal -m (hétfővel kezdődő) kimenetének 2. sora a napok nevei
local raw = pread("cal -m | head -n2 | tail -n1")
local days = {}
for day in raw:gmatch("%S+") do
table.insert(days, day)
end
return days
end
function draw_calendar(cr, cfg)
if not draw_allowed(cfg.draw_me) then return end
if conky_window == nil then return end
local x, y, cw, rh = cfg.x, cfg.y, cfg.cell_w, cfg.row_h
-- Plasma színek
local col_month = PLASMA.text_main
local col_weekdays = PLASMA.text_dim
local col_days = PLASMA.text_main
local col_today = PLASMA.accent
local col_outside = PLASMA.text_dim
local col_weeknums = PLASMA.text_dim
local col_sep = PLASMA.text_dim
local now = os.date("*t")
local year, month, today = now.year, now.month, now.day
local first_t = os.time { year = year, month = month, day = 1 }
local wday_num = tonumber(os.date("%u", first_t))
local start_col = wday_num - 1
local days_in_month = os.date("*t", os.time { year = year, month = month + 1, day = 0 }).day
local prev_days_max = os.date("*t", os.time { year = year, month = month, day = 0 }).day
local month_raw = get_cal_monthname()
local fmt = cfg.month_format or "year_month"
local month_display = ""
if fmt == "month_year" then
month_display = month_raw
else
local ystr = tostring(year)
local m_only = month_raw:gsub("%s*" .. ystr .. "%s*", "")
month_display = ystr .. ". " .. m_only
end
draw_text(cr, {
text = month_display,
x = 160, -- A 320 fele, így ha align="center", pont középen lesz
y = y + 3,
align = "center", -- Ez a kulcs!
font = cfg.font,
size = cfg.size + 8,
weight = "bold",
color = col_month,
})
draw_line(cr, {
x1 = x,
y1 = y + rh * 1,
x2 = x + cw * (cfg.show_weeknums and 8 or 7),
y2 = y + rh * 1,
style = "solid",
thickness = 1,
color = col_sep
})
--------------------------------------------------------
-- WEEKDAY LABELS
--------------------------------------------------------
local WEEKDAYS = get_cal_weekdays()
for i = 1, 7 do
if WEEKDAYS[i] then
draw_text(cr, {
text = WEEKDAYS[i],
x = x + (cfg.show_weeknums and cw or 0) + (i - 1) * cw + cw / 2,
y = y + rh * 2.2,
align = "center",
font = cfg.font,
size = cfg.size ,
color = col_weekdays,
})
end
end
--------------------------------------------------------
-- DAYS GRID
--------------------------------------------------------
local row, col = 0, start_col
for i = start_col - 1, 0, -1 do
draw_text(cr, {
text = tostring(prev_days_max - i),
x = x + (cfg.show_weeknums and cw or 0) + (start_col - 1 - i) * cw + cw / 2,
y = y + rh * 3.5,
align = "center",
font = cfg.font,
size = cfg.size,
color = col_outside,
})
end
for d = 1, days_in_month do
if col == 7 then
col = 0; row = row + 1
end
if cfg.show_weeknums and col == 0 then
local t = os.time { year = year, month = month, day = d }
draw_text(cr, {
text = os.date("%V", t),
x = x + cw / 2,
y = y + rh * (row + 3.5),
align = "center",
font = cfg.font,
size = cfg.size - 4,
color = col_weeknums,
})
end
draw_text(cr, {
text = tostring(d),
x = x + (cfg.show_weeknums and cw or 0) + col * cw + cw / 2,
y = y + rh * (row + 3.5),
align = "center",
font = cfg.font,
size = cfg.size,
color = (d == today) and col_today or col_days,
weight = (d == today) and "bold" or "normal",
})
col = col + 1
end
local next_d = 1
while (row * 7 + col) < 42 do
if col == 7 then
col = 0; row = row + 1
end
if row > 5 then break end
draw_text(cr, {
text = tostring(next_d),
x = x + (cfg.show_weeknums and cw or 0) + col * cw + cw / 2,
y = y + rh * (row + 3.5),
align = "center",
font = cfg.font,
size = cfg.size,
color = col_outside,
})
next_d = next_d + 1
col = col + 1
end
end
--}}}calendar.lua
local script_path = debug.getinfo(1).source:match("@(.*/)")
package.path = package.path .. ";" .. script_path .. "../common/?.lua"
require "common"
calendar_cfg = {
draw_me = true,
month_format = "year_month",
x = 0,
y = 5,
cell_w = 40,
row_h = 32,
font = "Ubuntu",
size = 16,
show_weeknums = true,
}
function conky_calendar_main()
if not conky_ready() then return end
check_theme_update()
local cs = cairo_xlib_surface_create(
conky_window.display,
conky_window.drawable,
conky_window.visual,
conky_window.width,
conky_window.height
)
local cr = cairo_create(cs)
draw_background(cr, backgrounds.default)
draw_calendar(cr, calendar_cfg)
cairo_destroy(cr)
cairo_surface_destroy(cs)
endcolck.lua
local script_path = debug.getinfo(1).source:match("@(.*/)")
package.path = package.path .. ";" .. script_path .. "../common/?.lua"
require 'common'
local my_clock_cfg = {
draw_me = true,
x = 150,
y = 150,
radius = 150,
show_ticks = true,
tick_width_hour = 3,
tick_width_minute = 1,
hour_hand_width = 4,
minute_hand_width = 2,
second_hand_width = 1,
show_seconds = true,
show_numbers = true,
number_size = 16,
number_radius = 0.8,
center_radius = 5
}
function conky_main_clock()
if not conky_ready() then return end
check_theme_update()
local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable,
conky_window.visual, conky_window.width, conky_window.height)
local cr = cairo_create(cs)
draw_clock(cr, my_clock_cfg)
cairo_destroy(cr)
cairo_surface_destroy(cs)
endclock.conf
conky.config = {
-- -- Belső működés
update_interval = 1.0,
cpu_avg_samples = 2,
net_avg_samples = 2,
double_buffer = true,
out_to_console = false,
out_to_stderr = false,
extra_newline = false,
own_window = true,
own_window_class = 'Conky',
own_window_type = 'normal',
own_window_transparent = true,
own_window_argb_visual = true,
own_window_argb_value = 255,
own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
alignment = 'top_right',
gap_x = 10,
gap_y = 10,
minimum_width = 300,
minimum_height = 300,
fixed_size = true,
draw_shades = false,
draw_outline = false,
draw_borders = false,
draw_graph_borders = false,
use_xft = true,
font = 'Ubuntu:size=10',
text_buffer_size = 2048,
border_inner_margin = 0,
border_outer_margin = 0,
border_width = 0,
-- -- Lua Script betöltése
lua_load = 'clock.lua',
lua_draw_hook_pre = 'main_clock',
};
conky.text = [[
]];calendar.conf
conky.config = {
use_xft = true,
font = 'DejaVu Sans:size=10',
xftalpha = 1,
background = true,
double_buffer = true,
no_buffers = true,
text_buffer_size = 2048,
update_interval = 1,
cpu_avg_samples = 2,
net_avg_samples = 2,
alignment = 'top_right',
gap_x = 10,
gap_y = 320,
minimum_width = 320,
maximum_width = 320,
minimum_height = 310,
own_window = true,
own_window_type = 'normal',
own_window_title = 'Conky',
own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
own_window_transparent = true,
own_window_argb_visual = true,
border_inner_margin = 0,
border_outer_margin = 0,
border_width = 0,
default_color = '#ededed',
pad_percents = 0,
extra_newline = false,
-- -- Lua
lua_load = 'calendar.lua',
lua_draw_hook_pre = 'calendar_main',
};
conky.text = [[]];File structure
~/conky pwd ✔
/home/molnar/conky
~/conky tree . ✔
.
├── calendar
│ ├── calendar.conf
│ └── calendar.lua
├── clock
│ ├── clock.conf
│ └── clock.lua
└── common
└── common.lua
4 directories, 5 files
~/conky ✔ This is just the beginning — more Plasma‑integrated widgets are on the way — feedback and contributions are welcome.
Offline
Update: I've finished the modular rewrite.
Features:
Automatic KDE Plasma color integration (via kdeglobals parsing).
Full i18n support
Clean Disk I/O graphs with autoscale.

I've posted all the source files (Gists) on Reddit here:
https://www.reddit.com/r/Conkyporn/comm … with_full/
Offline