一般确实是在窗口管理器里做。
比如我用的是 xmonad,这是 Haskell 写的一个非常 primitive 的窗口管理器,稍微熟悉 Haskell 的话,一下午就可以看完核心部分的代码(而如果你想学 Haskell,xmonad 又是非常不错的入门项目)。它本身功能很少,但是非常的简单和稳定。它的特点是完全的 hackable——核心代码只提供很少的功能,而配置文件由用户用 Haskell 自己写,这个配置文件也并非通常意义上的“配置”——它就是一个 Haskell 程序,而窗口管理器的 main 函数,是在这个配置文件里面的!
比如说这是我的 xmonad 配置文件中的 main 函数:
> main = do
> xmonad $ ewmh $ defaultConfig {
> workspaces = ["pri", "2", "3", "4", "misc"],
> modMask = mod4Mask,
> terminal = "xfce4-terminal",
> normalBorderColor = "#000000",
> focusedBorderColor = "#e63312",
> focusFollowsMouse = False,
> clickJustFocuses = False,
> borderWidth = 0,
> layoutHook =
> logModifier (gaps [(U, 32)] (
> windowSwitcherDecorationWithButtons shrinkText decorationTheme
> (
> smartBorders (spacingRaw True (Border 0 0 0 0) False (Border 0 0 0 0) False (
> draggingVisualizer (
> boringWindows (
> maximizeWithPadding 0 (
> minimize (
> layoutHook defaultConfig))))))))),
> manageHook = myManageHook,
> handleEventHook = handleEventHook def <+>
> -- fullscreenEventHook <+>
> fullscreenEventHook2 <+>
> minimizeEventHook,
> -- testEventHook,
> keys = myKeys
> }
这里面需要注意的是几个 hook,比如 layoutHook 中,minimize 和 maximizeWithPadding 负责最小化和最大化功能,boringWindows 可以在切换窗口时无视掉最小化的窗口,draggingVisualizer 和 windowSwitcherDecorationWithButtons 添加了窗口拖动和标题栏等 stacking WM 的功能,smartBorders 可以在窗口最大化时禁用边框的绘制(当然我现在把边框整个禁用了)——这些都是 Haskell 函数,而这些函数一个个嵌套组合起来传进 layoutHook 这个配置项,再调用 xmonad 提供的 xmonad 函数,就是 main 函数。
layoutHook 中的这些函数不属于 xmonad 核心,而是外部插件,比如这里的 windowSwitcherDecorationWithButtons 我用的是我自己在官方仓库提供的插件的基础上修改过的版本,改出了这么一个标题栏:
https://i.loli.net/2021/02/10/aUAFmL7DJOHd54C.png注意 Chrome 和 Emacs 的标题栏使用的是不同的背景和字体颜色,实现这个区别的代码就在上面的 Emacs 窗口里。
... 但是本回复的目的并非安利 yet another window manager 。说上面这一大堆只是因为貌似推荐 WM 是本贴的标准格式而已 ... 上面 layoutHook 有一个没提就是 gaps,这个可以禁止 xmonad 使用屏幕边框的区域,比如我这个配置中就保留了屏幕上方 32 像素高的位置放状态栏——这是我看到楼主的问题时的本能反应。但是仔细想来,其他窗口管理器也能处理各种 bar 和 dock 的占位,而它们 99% 没有 xmonad 这么强的定制性,这是什么原理呢?
Gaps 模块的文档(
https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Layout-Gaps.html )给出了线索:Gaps 仅仅是一个 workaround,处理“dock-type applications”的占位推荐使用 ManageDocks 提供的功能,这是因为这类窗口一般都设置了“STRUTS”属性。
xmonad 这个名字中的 X 来自于 X Window,X Window 本身是应用和系统之间通信的一套协议(至于 Monad 嘛,自然是“a monoid in the category of endofunctors”咯)。其中规定窗口和窗口管理器之间通信的主要是 ICCCM (Inter-Client Communication Conventions Manual,
https://www.x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html ) 和 EWMH (Extended Window Manager Hints,
https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html ),这个 STRUTS,以及“dock-type applications”,属于 EWMH 的范畴。
xmonad 的 ManageDocks 模块就是通过检查 EWMH 规定的这些属性来实现保留 dock 空间功能的:
https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/src/XMonad.Hooks.ManageDocks.html类似的处理也出现在 Cinnamon 的默认窗口管理器 muffin 中:
https://github.com/linuxmint/muffin/blob/46b555c27a9abf6b4a05f711770786bf4f6a2361/src/core/constraints.c#L863所以楼主这个问题,可以考虑的标准解决方案是想办法给任务栏窗口设置 EWMH 相关的属性,之后的布局问题,窗口管理器应该会自动处理。