diff --git a/docs/wormc.md b/docs/wormc.md index 1c75bd6..2542db6 100644 --- a/docs/wormc.md +++ b/docs/wormc.md @@ -76,15 +76,25 @@ Describes the layout of the frame *on the left side*. This is a comma separated - C for close button - M for maximize button - I for iconify/minimize button -eg: `wormc frame-left 'T;C;M' +eg: `wormc frame-left 'T;C;M'` ### `frame-center(string)` / `frame-right(string)` same as frame-left, but for the center and right parts of a frame window. ### `button-size(int)` The size (both width and height) of all window buttons. The window buttons don't have to nessecarily be perfect squares. You can use the larger dimension and the rest of the window will just not render. Eg: `wormc button-size 14` ### `button-offset(x, y)` The offset at both the x and y positions at which buttons on the titlebar (M, C) are located, for example `wormc button-offset 10 10`. -### `maximize-path / close-path (string)` -Full path to the maximize and close buttons, respectively. If this is unspecified or the value is invalid, then that part will skip rendering. Eg `wormc maximize-path ~/.config/worm/max.png`. +### `close-active-path(string) / close-inactive-path(string)` +Full path to the active and inactive maximize buttons, respectively. If unspecified or invalid the button simply won't render in that state. + +Ex. `wormc close-active-path ~/.config/worm/close-active.png`. +### `maximize-active-path(string) / maximize-inactive-path(string)` +Full path to the active and inactive maximize buttons, respectively. See [close-active-path](#close-active-pathstring--close-inactive-pathstring). + +Ex.`wormc maximize-inactive-path ~/.config/worm/max-inactive.png`. +### `minimize-active-path(string) / minimize-inactive-path(string)` +Full path to the active and inactive minimize buttons, respectively. See [close-active-path](#close-active-pathstring--close-inactive-pathstring). + +Ex. `wormc minimize-active-path ~/.config/worm/min-active.png`. ### `root-menu(string)` Sets path to the root menu. If this file is valid, upon right-clicking the root window it's executed (assumed to be an executable file). Eg `wormc root-menu ~/worm/examples/jgmenu_run`. ### `decoration-disable(string)` diff --git a/src/atoms.nim b/src/atoms.nim index dc06fca..ff13067 100644 --- a/src/atoms.nim +++ b/src/atoms.nim @@ -72,9 +72,12 @@ type IpcButtonOffset = "WORM_IPC_BUTTON_OFFSET", IpcButtonSize = "WORM_IPC_BUTTON_SIZE", IpcRootMenu = "WORM_IPC_ROOT_MENU", - IpcClosePath = "WORM_IPC_CLOSE_PATH", - IpcMaximizePath = "WORM_IPC_MAXIMIZE_PATH", - IpcMinimizePath = "WORM_IPC_MINIMIZE_PATH", + IpcCloseActivePath = "WORM_IPC_CLOSE_ACTIVE_PATH", + IpcCloseInactivePath = "WORM_IPC_CLOSE_INACTIVE PATH", + IpcMaximizeActivePath = "WORM_IPC_MAXIMIZE_ACTIVE_PATH", + IpcMaximizeInactivePath = "WORM_IPC_MAXIMIZE_INACTIVE_PATH", + IpcMinimizeACtivePath = "WORM_IPC_MINIMIZE_ACTIVE_PATH", + IpcMinimizeInactivePath = "WORM_IPC_MINIMIZE_INACTIVE_PATH", IpcMaximizeClient = "WORM_IPC_MAXIMIZE_CLIENT", IpcMinimizeClient = "WORM_IPC_MINIMIZE_CLIENT", IpcDecorationDisable = "WORM_IPC_DECORATION_DISABLE" diff --git a/src/events/clientmessage.nim b/src/events/clientmessage.nim index 9509427..8a6348d 100644 --- a/src/events/clientmessage.nim +++ b/src/events/clientmessage.nim @@ -440,42 +440,81 @@ proc handleClientMessage*(self: var Wm; ev: XClientMessageEvent) = if err >= Success and n > 0 and fontList != nil and fontList[0] != nil: XFreeStringList cast[ptr cstring](fontList) discard XFree fontProp.value - elif ev.data.l[0] == clong self.ipcAtoms[IpcClosePath]: + elif ev.data.l[0] == clong self.ipcAtoms[IpcCloseActivePath]: var fontProp: XTextProperty var fontList: ptr UncheckedArray[cstring] var n: cint discard self.dpy.XGetTextProperty(self.root, addr fontProp, self.ipcAtoms[ - IpcClosePath]) + IpcCloseActivePath]) let err = self.dpy.XmbTextPropertyToTextList(addr fontProp, cast[ ptr ptr cstring](addr fontList), addr n) - log "Changing close path to " & $fontList[0] - self.config.closePath = $fontList[0] + log "Changing active close path to " & $fontList[0] + self.config.closePaths[bsActive] = $fontList[0] if err >= Success and n > 0 and fontList != nil and fontList[0] != nil: XFreeStringList cast[ptr cstring](fontList) discard XFree fontProp.value - elif ev.data.l[0] == clong self.ipcAtoms[IpcMaximizePath]: + elif ev.data.l[0] == clong self.ipcAtoms[IpcCloseInactivePath]: var fontProp: XTextProperty var fontList: ptr UncheckedArray[cstring] var n: cint discard self.dpy.XGetTextProperty(self.root, addr fontProp, self.ipcAtoms[ - IpcMaximizePath]) + IpcCloseInactivePath]) let err = self.dpy.XmbTextPropertyToTextList(addr fontProp, cast[ ptr ptr cstring](addr fontList), addr n) - log "Changing maximize path to " & $fontList[0] - self.config.maximizePath = $fontList[0] + log "Changing inactive close path to " & $fontList[0] + self.config.closePaths[bsInactive] = $fontList[0] if err >= Success and n > 0 and fontList != nil and fontList[0] != nil: XFreeStringList cast[ptr cstring](fontList) discard XFree fontProp.value - elif ev.data.l[0] == clong self.ipcAtoms[IpcMinimizePath]: + elif ev.data.l[0] == clong self.ipcAtoms[IpcMaximizeActivePath]: var fontProp: XTextProperty var fontList: ptr UncheckedArray[cstring] var n: cint discard self.dpy.XGetTextProperty(self.root, addr fontProp, self.ipcAtoms[ - IpcMinimizePath]) + IpcMaximizeActivePath]) let err = self.dpy.XmbTextPropertyToTextList(addr fontProp, cast[ ptr ptr cstring](addr fontList), addr n) - log "Changing minimize path to " & $fontList[0] - self.config.minimizePath = $fontList[0] + log "Changing active maximize path to " & $fontList[0] + self.config.maximizePaths[bsActive] = $fontList[0] + if err >= Success and n > 0 and fontList != nil and fontList[0] != nil: + XFreeStringList cast[ptr cstring](fontList) + discard XFree fontProp.value + elif ev.data.l[0] == clong self.ipcAtoms[IpcMaximizeInactivePath]: + var fontProp: XTextProperty + var fontList: ptr UncheckedArray[cstring] + var n: cint + discard self.dpy.XGetTextProperty(self.root, addr fontProp, self.ipcAtoms[ + IpcMaximizeInactivePath]) + let err = self.dpy.XmbTextPropertyToTextList(addr fontProp, cast[ + ptr ptr cstring](addr fontList), addr n) + log "Changing inactive maximize path to " & $fontList[0] + self.config.maximizePaths[bsInactive] = $fontList[0] + if err >= Success and n > 0 and fontList != nil and fontList[0] != nil: + XFreeStringList cast[ptr cstring](fontList) + discard XFree fontProp.value + elif ev.data.l[0] == clong self.ipcAtoms[IpcMinimizeActivePath]: + var fontProp: XTextProperty + var fontList: ptr UncheckedArray[cstring] + var n: cint + discard self.dpy.XGetTextProperty(self.root, addr fontProp, self.ipcAtoms[ + IpcMinimizeActivePath]) + let err = self.dpy.XmbTextPropertyToTextList(addr fontProp, cast[ + ptr ptr cstring](addr fontList), addr n) + log "Changing active minimize path to " & $fontList[0] + self.config.minimizePaths[bsActive] = $fontList[0] + if err >= Success and n > 0 and fontList != nil and fontList[0] != nil: + XFreeStringList cast[ptr cstring](fontList) + discard XFree fontProp.value + elif ev.data.l[0] == clong self.ipcAtoms[IpcMinimizeInactivePath]: + var fontProp: XTextProperty + var fontList: ptr UncheckedArray[cstring] + var n: cint + discard self.dpy.XGetTextProperty(self.root, addr fontProp, self.ipcAtoms[ + IpcMinimizeInactivePath]) + let err = self.dpy.XmbTextPropertyToTextList(addr fontProp, cast[ + ptr ptr cstring](addr fontList), addr n) + log "Changing inactive minimize path to " & $fontList[0] + self.config.minimizePaths[bsInactive] = $fontList[0] if err >= Success and n > 0 and fontList != nil and fontList[0] != nil: XFreeStringList cast[ptr cstring](fontList) discard XFree fontProp.value diff --git a/src/types.nim b/src/types.nim index 8538720..82017dc 100644 --- a/src/types.nim +++ b/src/types.nim @@ -6,6 +6,8 @@ type lyFloating, lyTiling FramePart* = enum fpTitle, fpClose, fpMaximize, fpMinimize + ButtonState* = enum + bsActive, bsInactive Geometry* = object x*, y*: int width*, height*: uint @@ -42,7 +44,9 @@ type frameParts*: tuple[left, center, right: seq[FramePart]] buttonSize*: uint # always square FOR NOW rootMenu*: string - closePath*, maximizePath*, minimizePath*: string + closePaths*: array[ButtonState, string] + maximizePaths*: array[ButtonState, string] + minimizePaths*: array[ButtonState, string] TagSet* = array[9, bool] # distinct proc defaultTagSet*: TagSet = [true, false, false, false, false, false, false, diff --git a/src/wm.nim b/src/wm.nim index 840ebe1..f05f81c 100644 --- a/src/wm.nim +++ b/src/wm.nim @@ -247,11 +247,18 @@ proc renderTop*(self: var Wm; client: var Client) = gc = self.dpy.XCreateGC(client.frame.close, 0, addr gcVal) # discard self.dpy.XSetForeground(gc, self.config.textActivePixel) - let fp = - if self.focused.isSome and client == self.clients[self.focused.get]: - self.config.frameActivePixel - else: - self.config.frameInactivePixel + let + isFocused = self.focused.isSome and client == self.clients[self.focused.get] + fp = + if isFocused: + self.config.frameActivePixel + else: + self.config.frameInactivePixel + buttonState = + if isFocused: + bsActive + else: + bsInactive # draw the 3 'regions' of the titlebar; left, center, right var @@ -304,7 +311,7 @@ proc renderTop*(self: var Wm; client: var Client) = closeExists = true - if not fileExists self.config.closePath: + if not fileExists self.config.closePaths[buttonState]: continue discard self.dpy.XMapWindow client.frame.close @@ -336,7 +343,7 @@ proc renderTop*(self: var Wm; client: var Client) = buttonYOffset ) - let image = self.XCreateImage(self.config.closePath, fp, attr) + let image = self.XCreateImage(self.config.closePaths[buttonState], fp, attr) self.XPutImage(image, client.frame.close, gc) @@ -344,7 +351,7 @@ proc renderTop*(self: var Wm; client: var Client) = maximizeExists = true - if not fileExists self.config.maximizePath: + if not fileExists self.config.maximizePaths[buttonState]: continue discard self.dpy.XMapWindow client.frame.maximize @@ -376,13 +383,13 @@ proc renderTop*(self: var Wm; client: var Client) = self.config.buttonOffset.y.cint ) - let image = self.XCreateImage(self.config.maximizePath, fp, attr) + let image = self.XCreateImage(self.config.maximizePaths[buttonState], fp, attr) self.XPutImage(image, client.frame.maximize, gc) of fpMinimize: minimizeExists = true - if not fileExists self.config.minimizePath: + if not fileExists self.config.minimizePaths[buttonState]: continue discard self.dpy.XMapWindow client.frame.minimize @@ -414,7 +421,7 @@ proc renderTop*(self: var Wm; client: var Client) = self.config.buttonOffset.y.cint ) - let image = self.XCreateImage(self.config.minimizePath, fp, attr) + let image = self.XCreateImage(self.config.minimizePaths[buttonState], fp, attr) self.XPutImage(image, client.frame.minimize, gc) for i, part in self.config.frameParts.center: @@ -444,10 +451,10 @@ proc renderTop*(self: var Wm; client: var Client) = closeExists = true - if not fileExists self.config.closePath: + if not fileExists self.config.closePaths[buttonState]: continue - let image = self.XCreateImage(self.config.closePath, fp, attr) + let image = self.XCreateImage(self.config.closePaths[buttonState], fp, attr) let btnSize = self.config.buttonSize.cint @@ -497,7 +504,7 @@ proc renderTop*(self: var Wm; client: var Client) = maximizeExists = true - if not fileExists self.config.maximizePath: + if not fileExists self.config.maximizePaths[buttonState]: continue discard self.dpy.XMapWindow client.frame.maximize @@ -534,16 +541,16 @@ proc renderTop*(self: var Wm; client: var Client) = btnYOffset ) - let image = self.XCreateImage(self.config.maximizePath, fp, attr) + let image = self.XCreateImage(self.config.maximizePaths[buttonState], fp, attr) self.XPutImage(image, client.frame.maximize, gc) of fpMinimize: minimizeExists = true - if not fileExists self.config.minimizePath: + if not fileExists self.config.minimizePaths[buttonState]: continue - let image = self.XCreateImage(self.config.minimizePath, fp, attr) + let image = self.XCreateImage(self.config.minimizePaths[buttonState], fp, attr) let btnSize = self.config.buttonSize.cint @@ -633,10 +640,10 @@ proc renderTop*(self: var Wm; client: var Client) = closeExists = true - if not fileExists self.config.closePath: + if not fileExists self.config.closePaths[buttonState]: continue - let image = self.XCreateImage(self.config.closePath, fp, attr) + let image = self.XCreateImage(self.config.closePaths[buttonState], fp, attr) let btnXOffset = self.config.buttonOffset.x.cint @@ -682,7 +689,7 @@ proc renderTop*(self: var Wm; client: var Client) = maximizeExists = true - if not fileExists self.config.maximizePath: + if not fileExists self.config.maximizePaths[buttonState]: continue discard self.dpy.XMapWindow client.frame.maximize @@ -727,13 +734,13 @@ proc renderTop*(self: var Wm; client: var Client) = self.config.buttonOffset.y.cint ) - let image = self.XCreateImage(self.config.maximizePath, fp, attr) + let image = self.XCreateImage(self.config.maximizePaths[buttonState], fp, attr) self.XPutImage(image, client.frame.maximize, gc) of fpMinimize: minimizeExists = true - if not fileExists self.config.minimizePath: + if not fileExists self.config.minimizePaths[buttonState]: continue discard self.dpy.XMapWindow client.frame.minimize @@ -778,7 +785,7 @@ proc renderTop*(self: var Wm; client: var Client) = self.config.buttonOffset.y.cint ) - let image = self.XCreateImage(self.config.minimizePath, fp, attr) + let image = self.XCreateImage(self.config.minimizePaths[buttonState], fp, attr) self.XPutImage(image, client.frame.minimize, gc) diff --git a/src/wormc.nim b/src/wormc.nim index 8b50f99..09c9d82 100644 --- a/src/wormc.nim +++ b/src/wormc.nim @@ -93,15 +93,24 @@ proc main() = of "root-menu": dpy.sendStrPrep(ipcAtoms[IpcRootMenu], params[i+1]) data = formatMess ipcAtoms[IpcRootMenu] - of "close-path": - dpy.sendStrPrep(ipcAtoms[IpcClosePath], params[i+1]) - data = ipcAtoms[IpcClosePath].formatMess() - of "maximize-path": - dpy.sendStrPrep(ipcAtoms[IpcMaximizePath], params[i+1]) - data = ipcAtoms[IpcMaximizePath].formatMess() - of "minimize-path": - dpy.sendStrPrep(ipcAtoms[IpcMinimizePath], params[i+1]) - data = ipcAtoms[IpcMinimizePath].formatMess() + of "close-active-path": + dpy.sendStrPrep(ipcAtoms[IpcCloseActivePath], params[i+1]) + data = ipcAtoms[IpcCloseActivePath].formatMess() + of "close-inactive-path": + dpy.sendStrPrep(ipcAtoms[IpcCloseInactivePath], params[i+1]) + data = ipcAtoms[IpcCloseInactivePath].formatMess() + of "maximize-active-path": + dpy.sendStrPrep(ipcAtoms[IpcMaximizeActivePath], params[i+1]) + data = ipcAtoms[IpcMaximizeActivePath].formatMess() + of "maximize-inactive-path": + dpy.sendStrPrep(ipcAtoms[IpcMaximizeInactivePath], params[i+1]) + data = ipcAtoms[IpcMaximizeInactivePath].formatMess() + of "minimize-active-path": + dpy.sendStrPrep(ipcAtoms[IpcMinimizeActivePath], params[i+1]) + data = ipcAtoms[IpcMinimizeActivePath].formatMess() + of "minimize-inactive-path": + dpy.sendStrPrep(ipcAtoms[IpcMinimizeInactivePath], params[i+1]) + data = ipcAtoms[IpcMinimizeInactivePath].formatMess() of "decoration-disable": dpy.sendStrPrep(ipcAtoms[IpcDecorationDisable], params[i+1]) data = ipcAtoms[IpcDecorationDisable].formatMess()