A Silly and Useless X11 Window Manager
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.9 KiB

import x11/xlib, x11/xutil, x11/x, x11/keysym
import strformat, os, options, tables, random
type XDirection = enum left, right
type YDirection = enum up, down
type Window = ref object of RootObj
x : cint
y : cint
width : cint
height : cint
speed : cint
win : TWindow
xDirection : XDirection
yDirection : YDirection
var root : TWindow
var windowState : Table[TWindow, Window] = initTable[TWindow, Window]()
var invalidWindows : seq[TWindow]
proc getWindowName(display : PDisplay, window : TWindow) : Option[string] =
var name : cstring
if display.XFetchName(window, name.addr) == BadWindow:
return none(string)
some($name)
proc gcWindows(display : PDisplay) =
for xid, window in windowState.pairs:
discard display.getWindowName(xid)
for xid in invalidWindows:
windowState.del(xid)
invalidWindows = @[]
proc ignoreBadWindows(display : PDisplay, ev : PXErrorEvent) : cint {.cdecl.} =
# resourceID maps to the Window's XID
invalidWindows.add(ev.resourceID)
0
proc getDisplay : PDisplay =
result = XOpenDisplay(nil)
if result == nil:
quit("Failed to open display")
iterator getChildren(display : PDisplay, rootHeight : int, rootWidth : int) : Window =
var currentWindow : PWindow
var rootReturn : TWindow
var parentReturn : TWindow
var childrenReturn : PWindow
var nChildrenReturn : cuint
discard XQueryTree(display,
root,
rootReturn.addr,
parentReturn.addr,
childrenReturn.addr,
nChildrenReturn.addr)
for i in 0..(nChildrenReturn.int - 1):
var attr : TXWindowAttributes
currentWindow = cast[PWindow](
cast[uint](childrenReturn) + cast[uint](i * currentWindow[].sizeof)
)
if display.XGetWindowAttributes(currentWindow[], attr.addr) == BadWindow:
windowState.del(currentWindow[])
continue
yield Window(
x: rand(0..rootWidth).cint,
y: rand(0..rootHeight).cint,
xDirection: right,
yDirection: down,
width: attr.width,
height: attr.height,
win: currentWindow[],
speed: rand(1..3).cint
)
discard XFree(childrenReturn)
when isMainModule:
# Seed the RNG
randomize()
var start : TXButtonEvent
var ev : TXEvent
var attr : TXWindowAttributes
let display = getDisplay()
root = DefaultRootWindow(display)
start.subWindow = None
discard XSetErrorHandler(ignoreBadWindows)
while true:
discard display.XGetWindowAttributes(root, attr.addr)
let rootWidth = attr.width
let rootHeight = attr.height
sleep(10)
for window in getChildren(display, rootHeight, rootWidth):
# go through each window, add it to the state
discard windowState.hasKeyOrPut(window.win, window)
display.gcWindows()
# Go through each window and move them, update the state, etc
for window in windowState.values:
if window.xDirection == right:
if window.x >= (rootWidth - window.width):
windowState[window.win].xDirection = left
windowState[window.win].x -= window.speed
else:
windowState[window.win].x += window.speed
else:
if window.x <= 0:
windowState[window.win].xDirection = right
windowState[window.win].x += window.speed
else:
windowState[window.win].x -= window.speed
if window.yDirection == up:
if window.y <= 0:
windowState[window.win].yDirection = down
windowState[window.win].y += window.speed
else:
windowState[window.win].y -= window.speed
else:
if window.y >= (rootHeight - window.height):
windowState[window.win].yDirection = up
windowState[window.win].y -= window.speed
else:
windowState[window.win].y += window.speed
discard display.XMoveWindow(window.win, windowState[window.win].x, windowState[window.win].y)
discard display.XSync(0)