Guest User

Untitled

a guest
Aug 2nd, 2026
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Nim 8.53 KB | None | 0 0
  1. # cover_x11.nim
  2. {.passL: "-lX11".}
  3.  
  4. type
  5.   Display = distinct pointer
  6.   Window = culong
  7.   Atom = culong
  8.   XSetWindowAttributes = object
  9.     background_pixmap: culong
  10.     background_pixel: culong
  11.     border_pixmap: culong
  12.     border_pixel: culong
  13.     bit_gravity: cint
  14.     win_gravity: cint
  15.     backing_store: cint
  16.     backing_planes: culong
  17.     backing_pixel: culong
  18.     save_under: cint
  19.     event_mask: clong
  20.     do_not_propagate_mask: clong
  21.     override_redirect: cint
  22.     colormap: culong
  23.     cursor: culong
  24.   XClientMessageEvent = object
  25.     theType: cint
  26.     serial: culong
  27.     send_event: cint
  28.     display: Display
  29.     window: Window
  30.     message_type: Atom
  31.     format: cint
  32.     data: array[5, clong]
  33.   XButtonEvent = object
  34.     theType: cint
  35.     serial: culong
  36.     send_event: cint
  37.     display: Display
  38.     window: Window
  39.     root: Window
  40.     subwindow: Window
  41.     time: culong
  42.     x, y: cint
  43.     x_root, y_root: cint
  44.     state: cuint
  45.     button: cuint
  46.     same_screen: cint
  47.   XEvent = array[24, clong]
  48.   MwmHints = object
  49.     flags: culong
  50.     functions: culong
  51.     decorations: culong
  52.     inputMode: clong
  53.     status: culong
  54.  
  55. const
  56.   InputOutput = 1
  57.   CWBackPixel = 0x0002
  58.   ExposureMask = 1 shl 15
  59.   ButtonPressMask = 1 shl 2
  60.   StructureNotifyMask = 1 shl 17
  61.   Expose = 12
  62.   ButtonPress = 4
  63.   ClientMessage = 33
  64.   ConfigureNotify = 22
  65.   SubstructureRedirectMask = 1 shl 20
  66.   SubstructureNotifyMask = 1 shl 19
  67.   NET_WM_STATE_ADD = 1
  68.   PropModeReplace = 0
  69.   MWM_HINTS_DECORATIONS = 1 shl 1
  70.   Button1 = 1'u32
  71.   DoubleClickThresholdMs: culong = 400
  72.   WindowSize: cuint = 200
  73.   InitialX: cint = 100
  74.   InitialY: cint = 100
  75.   TopPartHeight: cuint = 25  # set this to match your WM's title bar height
  76.   RightPartWidth: cuint = 2   # extra width to reclaim on the right in borderless mode
  77.   BottomPartHeight: cuint = 2 # extra height to reclaim on the bottom in borderless mode
  78.   LeftPartWidth: cuint = 2   # extra width to reclaim on the left in borderless mode
  79.   StaticGravity = 10
  80.   NetMoveResizeX = 1 shl 8
  81.   NetMoveResizeY = 1 shl 9
  82.   NetMoveResizeWidth = 1 shl 10
  83.   NetMoveResizeHeight = 1 shl 11
  84.   NetMoveResizeSourceApp = 1 shl 12
  85.  
  86. proc XOpenDisplay(name: cstring): Display {.importc, cdecl.}
  87. proc XCloseDisplay(d: Display) {.importc, cdecl.}
  88. proc XDefaultScreen(d: Display): cint {.importc, cdecl.}
  89. proc XBlackPixel(d: Display, screen: cint): culong {.importc, cdecl.}
  90. proc XRootWindow(d: Display, screen: cint): Window {.importc, cdecl.}
  91. proc XCreateWindow(d: Display, parent: Window, x, y: cint,
  92.                     width, height, borderWidth: cuint, depth: cint,
  93.                     class: cuint, visual: pointer,
  94.                     valuemask: culong, attrs: ptr XSetWindowAttributes): Window {.importc, cdecl.}
  95. proc XDestroyWindow(d: Display, w: Window) {.importc, cdecl.}
  96. proc XStoreName(d: Display, w: Window, name: cstring) {.importc, cdecl.}
  97. proc XMapWindow(d: Display, w: Window) {.importc, cdecl.}
  98. proc XNextEvent(d: Display, event: ptr XEvent) {.importc, cdecl.}
  99. proc XSelectInput(d: Display, w: Window, mask: clong) {.importc, cdecl.}
  100. proc XInternAtom(d: Display, atomName: cstring, onlyIfExists: cint): Atom {.importc, cdecl.}
  101. proc XSetWMProtocols(d: Display, w: Window, protocols: ptr Atom, count: cint): cint {.importc, cdecl.}
  102. proc XSendEvent(d: Display, w: Window, propagate: cint, eventMask: clong,
  103.                 event: ptr XEvent): cint {.importc, cdecl.}
  104. proc XSync(d: Display, discardEvents: cint): cint {.importc, cdecl.}
  105. proc XChangeProperty(d: Display, w: Window, property: Atom, typ: Atom,
  106.                       format: cint, mode: cint, data: pointer, nelements: cint): cint {.importc, cdecl.}
  107. proc XFlush(d: Display): cint {.importc, cdecl.}
  108. proc XTranslateCoordinates(d: Display, srcW, destW: Window, srcX, srcY: cint,
  109.                             destXReturn, destYReturn: ptr cint, childReturn: ptr Window): cint {.importc, cdecl.}
  110.  
  111. proc sendRootClientMessage(display: Display, win: Window, root: Window,
  112.                             messageType: Atom, d0, d1, d2, d3, d4: clong) =
  113.   var msg: XClientMessageEvent
  114.   msg.theType = ClientMessage
  115.   msg.send_event = 1
  116.   msg.display = display
  117.   msg.window = win
  118.   msg.message_type = messageType
  119.   msg.format = 32
  120.   msg.data[0] = d0
  121.   msg.data[1] = d1
  122.   msg.data[2] = d2
  123.   msg.data[3] = d3
  124.   msg.data[4] = d4
  125.  
  126.   discard XSendEvent(display, root, 0,
  127.     (SubstructureRedirectMask or SubstructureNotifyMask).clong,
  128.     cast[ptr XEvent](addr msg))
  129.  
  130. proc setAlwaysOnTop(display: Display, win: Window, root: Window) =
  131.   let netWmState = XInternAtom(display, "_NET_WM_STATE", 0)
  132.   let netWmStateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", 0)
  133.   sendRootClientMessage(display, win, root, netWmState,
  134.     NET_WM_STATE_ADD.clong, netWmStateAbove.clong, 0, 1, 0)
  135.  
  136. proc moveResizeAbsolute(display: Display, win: Window, root: Window,
  137.                          x, y: cint, width, height: cuint) =
  138.   # Uses the EWMH _NET_MOVERESIZE_WINDOW request, which the window manager
  139.   # interprets in true absolute screen coordinates -- unlike XMoveResizeWindow,
  140.   # which operates relative to the window's immediate parent (the WM's own
  141.   # decoration frame, once reparented), causing drift if used directly here.
  142.   let atom = XInternAtom(display, "_NET_MOVERESIZE_WINDOW", 0)
  143.   let flags = (StaticGravity or NetMoveResizeX or NetMoveResizeY or
  144.                NetMoveResizeWidth or NetMoveResizeHeight or NetMoveResizeSourceApp).clong
  145.   sendRootClientMessage(display, win, root, atom,
  146.     flags, x.clong, y.clong, width.clong, height.clong)
  147.  
  148. proc getRootPosition(display: Display, win: Window, root: Window): (cint, cint) =
  149.   var x, y: cint
  150.   var child: Window
  151.   discard XTranslateCoordinates(display, win, root, 0, 0, addr x, addr y, addr child)
  152.   (x, y)
  153.  
  154. proc setDecorations(display: Display, win: Window, root: Window, motifHints: Atom,
  155.                      visible: bool, curX, curY: cint) =
  156.   var hints: MwmHints
  157.   hints.flags = MWM_HINTS_DECORATIONS.culong
  158.   hints.decorations = (if visible: 1.culong else: 0.culong)
  159.   discard XChangeProperty(display, win, motifHints, motifHints, 32,
  160.     PropModeReplace, addr hints, 5)
  161.   discard XFlush(display)
  162.  
  163.   if visible:
  164.     moveResizeAbsolute(display, win, root, curX + LeftPartWidth.cint, curY + TopPartHeight.cint,
  165.       WindowSize, WindowSize)
  166.   else:
  167.     moveResizeAbsolute(display, win, root, curX - LeftPartWidth.cint, curY - TopPartHeight.cint,
  168.       WindowSize + LeftPartWidth + RightPartWidth,
  169.       WindowSize + TopPartHeight + BottomPartHeight)
  170.  
  171. proc main() =
  172.   let display = XOpenDisplay(nil)
  173.   if cast[pointer](display) == nil:
  174.     quit("Cannot open X display")
  175.  
  176.   let screen = XDefaultScreen(display)
  177.   let black = XBlackPixel(display, screen)
  178.   let root = XRootWindow(display, screen)
  179.  
  180.   var attrs: XSetWindowAttributes
  181.   attrs.background_pixel = black
  182.  
  183.   let win = XCreateWindow(
  184.     display, root,
  185.     InitialX, InitialY,
  186.     WindowSize, WindowSize,
  187.     1,
  188.     24,
  189.     InputOutput.cuint,
  190.     nil,
  191.     CWBackPixel.culong,
  192.     addr attrs
  193.   )
  194.  
  195.   XStoreName(display, win, "Distraction Cover")
  196.   XSelectInput(display, win, (ExposureMask or ButtonPressMask or StructureNotifyMask).clong)
  197.  
  198.   var wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", 0)
  199.   discard XSetWMProtocols(display, win, addr wmDeleteMessage, 1)
  200.  
  201.   let motifHints = XInternAtom(display, "_MOTIF_WM_HINTS", 0)
  202.  
  203.   XMapWindow(display, win)
  204.   discard XSync(display, 0)
  205.  
  206.   setAlwaysOnTop(display, win, root)
  207.  
  208.   var trackedX: cint = InitialX
  209.   var trackedY: cint = InitialY
  210.  
  211.   var decorationsVisible = true
  212.   var lastClickTime: culong = 0
  213.  
  214.   var event: XEvent
  215.   var running = true
  216.   while running:
  217.     XNextEvent(display, addr event)
  218.     let eventType = cast[ptr cint](addr event)[]
  219.  
  220.     if eventType == ConfigureNotify:
  221.       let (x, y) = getRootPosition(display, win, root)
  222.       trackedX = x
  223.       trackedY = y
  224.  
  225.     elif eventType == ButtonPress:
  226.       let be = cast[ptr XButtonEvent](addr event)
  227.       if be.button == Button1:
  228.         let delta = be.time - lastClickTime
  229.         if lastClickTime != 0 and delta < DoubleClickThresholdMs:
  230.           decorationsVisible = not decorationsVisible
  231.           setDecorations(display, win, root, motifHints, decorationsVisible, trackedX, trackedY)
  232.           lastClickTime = 0
  233.         else:
  234.           lastClickTime = be.time
  235.  
  236.     elif eventType == ClientMessage:
  237.       let cm = cast[ptr XClientMessageEvent](addr event)
  238.       if Atom(cm.data[0]) == wmDeleteMessage:
  239.         running = false
  240.  
  241.   XDestroyWindow(display, win)
  242.   XCloseDisplay(display)
  243.  
  244. main()
  245.  
Advertisement
Add Comment
Please, Sign In to add comment