Conversation with Gemini

You said

Is fvwm2 still broken? fvwm3 doesn't work for me.

Gemini said

If you are asking because fvwm2 completely fell over or refused to compile/run a while back, that was likely due to a breaking API change introduced in libX11 (around version 1.8).

Upstream fvwm2 is strictly in maintenance mode and never received an official patch for that specific Xlib issue, effectively leaving it broken on modern rolling distributions and newer OS releases unless downstreams carried independent patches. Upstream's answer to this was fvwm3, which received a full xthread_fix and multi-threading overhaul to handle modern X11 environments.

However, if you can't get fvwm3 to behave, you aren't stuck. Depending on your platform and how much time you want to spend massaging syntax, you have a few practical options.

Option 1: Backporting or Patching fvwm2

If your underlying OS ports or package management tree still carries fvwm2 (often just packaged as fvwm), it may include downstream patches that fix the libX11 thread crashes.

  • If compiling from source: You can manually pull the fvwm2-stable branch from GitHub, but you will likely need to inject the Xlib threading workarounds or compile against an older libX11 environment to ensure stability.

Option 2: Fixing what broke your config in fvwm3

If fvwm3 "doesn't work" because it drops your windows, ignores monitors, or throws syntax errors, it is usually due to three aggressive deprecations upstream made when cleaning up the code base. You can often make your old fvwm2rc compatible with fvwm3 by targeting these specific areas:

  • Colorsets are Mandatory: fvwm3 completely dropped old-style direct color definitions (e.g., setting raw hex or color names inline on menus or window borders). Everything must use Colorset definitions now. If your configuration relies on old explicit color commands, it will render invisibly or break basic layout parsing.

  • Xinerama vs. RandR: fvwm3 dropped the old Xinerama code path in favor of native RandR support. If you have multi-monitor geometry rules using the old @0 or @1 screen targeting syntax, fvwm3 will reject them. You must update them to target explicit RandR display names (like @DisplayPort-0) or use the primary pointer @p.

  • Deprecated Modules & Syntax: * FvwmForm is dead; it was entirely replaced by FvwmScript.

    • Moving windows relative to screens via Move screen w has been tightened up to require modern evaluation syntax: Move screen $[w.screen].

    • FvwmConsole is deprecated in favor of FvwmPrompt (which requires starting FvwmMFL in your StartFunction).

A Quick Diagnostic Trick

If you want to debug the two side-by-side without completely breaking your workflow, you can add explicit restart paths to your menu structure to easily drop back and forth while working out configuration bugs:

Code snippet
+ "Restart Fvwm2" Restart fvwm2
+ "Restart Fvwm3" Restart

What specific errors or behavior are you running into when you try to bring your environment up?

You said

It doesn't understand multiple displays as configured.

Gemini said

That is the smoking gun. fvwm3 completely stripped out the old Xinerama extension code path and replaced it with a modern RandR (Resize and Rotate) core.

Because Xinerama treated all screens as a single, hard-coded geometry mesh, fvwm2 config files used explicit coordinates or a flat @0, @1 syntax to position windows, panels, and views. fvwm3 doesn't know what those mean anymore; it wants the actual hardware or location identifier provided by RandR.

To make fvwm3 respect your display layout, check these three areas in your configuration file:

1. Change the Virtual Desktop Behavior

By default, fvwm3 might be trying to manage your monitors independently (meaning a workspace change on monitor A doesn't move monitor B). If you want the classic fvwm2 style where moving a page scrolls both screens together, you need to explicitly tell it to track globally.

Add or modify this command early in your config:

Code snippet
DesktopConfiguration global
  • global: Replicates the old behavior (screens move together as one giant display area).

  • per-monitor: Each display handles its own pages/desks independently.

2. Fix the Window Geometries (@0 vs @name)

If you have applications or modules configured to launch on a specific monitor using old geometry tails like xterm -geometry +0+0@1, it will fail or default to your main screen.

You must update these strings to use either the dynamic monitor expansions or the strict RandR names. Drop to a terminal and run xrandr --listmonitors to get your exact names (e.g., DP-1, HDMI-A-0).

Then update your config syntax:

Code snippet
# Old fvwm2 Xinerama syntax (Broken)
Style "FvwmButtons" StartsOnScreen 1
Exec exec xterm -geometry +0+0@1

# New fvwm3 RandR syntax (Fixed)
Style "FvwmButtons" StartsOnScreen DP-1
Exec exec xterm -geometry +0+0@DP-1

3. Leverage Dynamic Monitor Tokens

If you share your configuration file between different machines (like a laptop and a desktop) and don't want to hardcode names like DP-1, fvwm3 introduced dynamic variables. You can swap out your static monitor numbers for these string expansions:

  • $[monitor.primary]: Automatically targets whichever display is flagged as primary.

  • $[monitor.current]: Targets the monitor containing your mouse cursor.

  • $[monitor.0.name]: Targets the first monitor chronologically from top-left, regardless of its hardware name.

For example, to make a window or panel move safely to your secondary monitor based strictly on its location layout rather than its hardware port:

Code snippet
# Moves the target window to your second monitor dynamically
Move screen $[monitor.1.name]
You said

Give me a sample fvwm3rc for a multi-monitor system with 2 1920x1080 monitors and 2 3840x2160 monitors.

Gemini said

Managing four monitors across mixed DPI scaling (two 1080p and two 4K screens) is exactly where fvwm3 shines, provided you drop the hardcoded geometry values and use the new dynamic monitor tokens.

Here is a minimal, clean boilerplate ~/.fvwm/fvwm3rc tailored for a modern 4-monitor setup. It strips out the old Xinerama syntax and ensures things like menus, window placement, and panels respect your mixed-resolution screen boundaries instead of flying off-screen.

Code snippet
# =====================================================================
# MINIMAL MULTI-MONITOR FVWM3RC CONFIGURATION
# =====================================================================

# 1. MONITOR MANAGEMENT & WORKSPACE TYPE
# ---------------------------------------------------------------------
# 'global' makes all 4 screens scroll pages together when you hit an edge.
# Swap to 'per-monitor' if you want each screen to change virtual pages independently.
DesktopConfiguration global

# Define a 3x3 grid of virtual pages across your combined monitor space
DesktopSize 3x3

# EdgeScroll determines how fluidly windows move across display links (100 = full page jump)
EdgeScroll 100 100
EdgeResistance 250 10

# 2. MODERN COLORSSETS (Mandatory in fvwm3 - old hex styling breaks parsing)
# ---------------------------------------------------------------------
CleanupColorsets
Colorset 0 Background "#1A1A24", Foreground "#A0A0B8" # Inactive windows
Colorset 1 Background "#2E3440", Foreground "#E5E9F0" # Active titlebars
Colorset 2 Background "#1F232B", Foreground "#88C0D0" # Menu backgrounds

# 3. GLOBAL STYLE RULES
# ---------------------------------------------------------------------
Style * Colorset 0, BorderColorset 0
Style * HilightColorset 1, HilightBorderColorset 1
Style * Font "xft:Sans:size=10:antialias=true"
Style * HandleWidth 4, BorderWidth 4
Style * MwmDecor, HintOverride

# 4. WINDOW PLACEMENT LOGIC FOR MIXED RESOLUTIONS (1080p + 4K)
# ---------------------------------------------------------------------
# TileCascadePlacement ensures windows don't get lost or pinned to the tiny 1080p corners
Style * TileCascadePlacement
Style * MinOverlapPlacement

# Pin certain utility apps to open strictly on your high-res or low-res panels
# Note: $[monitor.0.name] relies on your xrandr ordering. 
# You can also use exact physical ports like 'Style "Gimp" StartsOnScreen DP-1'
Style "Firefox"       StartsOnScreen $[monitor.0.name]  # Usually primary 4K screen
Style "Gimp"          StartsOnScreen $[monitor.1.name]
Style "Conky"         StartsOnScreen $[monitor.2.name]  # Send system monitors to a 1080p panel

# 5. MOUSE AND KEY BINDINGS (Using Monitor Tokens)
# ---------------------------------------------------------------------
# Global Window Controls (Alt + F4 to Close, etc)
Key F4      A   M   Delete
Key Tab     A   M   WindowList RootMenu

# Move focus or toss windows across your 4 screens fluidly using cursor context
# Key [Key] [Context] [Modifier] [Function]
Key Left    A   M   MoveToPage -1p +0p
Key Right   A   M   MoveToPage +1p +0p
Key Up      A   M   MoveToPage +0p -1p
Key Down    A   M   MoveToPage +0p +1p

# Move windows to adjacent monitors using Alt+Shift+Arrow Keys
Key Left    A   MS  Move screen $[monitor.current] -1p
Key Right   A   MS  Move screen $[monitor.current] +1p

# 6. SYSTEM MENUS (Respects Mouse Position Across Displays)
# ---------------------------------------------------------------------
DestroyMenu RootMenu
AddToMenu RootMenu "System Controls" Title
+ "Terminal"             Exec exec xterm
+ "Web Browser"          Exec exec firefox
+ ""                     Nop
+ "Restart FVWM3"        Restart
+ "Exit Window Manager"  Quit

# Bind right-click on the empty root background to open menu at mouse coordinates
Mouse 3     R   A   Menu RootMenu

# 7. INITIAL STARTUP FUNCTION
# ---------------------------------------------------------------------
DestroyFunc StartFunction
AddToFunc StartFunction
+ I Module FvwmPager 0 0

# Spawn specific apps onto dedicated monitors at startup
# Fvwm3 safely calculates geometric offsets relative to target screen boundaries
+ I Exec exec xterm -geometry +50+50@$[monitor.0.name]
+ I Exec exec xterm -geometry +50+50@$[monitor.2.name]

# 8. PAGER DECORATION (Visual layout tracker)
# ---------------------------------------------------------------------
DestroyModuleConfig FvwmPager:*
*FvwmPager: Colorset * 0
*FvwmPager: HilightColorset * 1
*FvwmPager: Font "xft:Sans:size=8"
*FvwmPager: Geometry 240x80-0-0

Why This Setup Works Across Mixed DPI Displays

  1. TileCascadePlacement avoids the "black hole" trap: In an environment with two 4K screens () and two 1080p screens (), your virtual X11 mesh creates vast "empty spaces" depending on how they are tiled in your layout tool. Old window placements could launch windows outside the viewable canvas of the smaller monitors. Modern placement algorithms safely calculate boundaries.

  2. Dynamic Variables ($[monitor.x.name]) vs. Hardcoding: Instead of breaking your setup whenever you plug or unplug a display port or change graphics drivers, using $[monitor.0.name] up to $[monitor.3.name] will map systematically across your active RandR monitor array from left to right.

  3. Mandatory Colorsets: Notice that the title bars, inactive elements, and menus are defined via Colorset blocks rather than old Style * ForeColor Black, BackColor Gray rules. fvwm3 immediately drops execution of blocks that still rely on old 90s-era color strings.

You said

How do I get menus on the other displays?

Gemini said

To get menus to appear on your other displays, you don't actually need to change how the menus are built—you just need to change how they are invoked.

In fvwm3, the Menu command accepts dynamic screen placement arguments. By default, if you just call Menu RootMenu, it will open the menu on whichever screen contains your mouse pointer. However, if you are calling menus via keybindings, panel buttons, or script modules, you can force them to appear on specific displays, or contextually snap to the monitor active in the RandR topology.

Here is how to configure your fvwm3rc so menus behave exactly how you want across all four screens.

Method 1: The Contextual Approach (Highly Recommended)

If you want to ensure that hitting a key or mouse button always pops the menu open on the specific display where you are currently looking or working, use the screen positional arguments:

Code snippet
# Context: Open the menu exactly on the monitor containing the mouse pointer
Mouse 3  R  A  Menu RootMenu Context

# Shortcut: Bind a key (e.g., Super/Win key) to pop up the menu on the current active monitor
Key Super_L  A  A  Menu RootMenu Context

Using the Context parameter forces fvwm3 to poll RandR for the boundary maps of the display containing the cursor right at that millisecond, ensuring the menu draws cleanly inside that screen's 1080p or 4K box rather than splitting across the physical bezel.

Method 2: Assigning Menus to Explicit Monitors

If you are building custom top-bars, panels, or side docks (using FvwmButtons or FvwmScript) for each display, you can force a menu button to send its pop-up to a designated monitor by name or port number:

Code snippet
# Force the menu to open on your first display (Monitor 0)
Key F1  A  A  Menu RootMenu screen $[monitor.0.name]

# Force the menu to open on your third display (Monitor 2)
Key F2  A  A  Menu RootMenu screen $[monitor.2.name]

Method 3: Fixing Menu "Warping" (The Multi-Monitor Gotcha)

If you notice that when you open a menu on a 1080p screen it suddenly flies over or "warps" your mouse cursor to a 4K screen, it is because of an old 90s default setting designed for single small CRT monitors.

To stop this erratic multi-monitor jumping, add these configuration lines to the top of your menu definition section to tell fvwm3 to stop trying to auto-center or warp across displays:

Code snippet
# Prevents the mouse from jumping across screens when a menu opens
MenuParameters * DoubleClickTime 300, PopupAsRootMenu, Position Mouse

# Ensures long menus stay constrained strictly within the single monitor's resolution bounds
Style * MenuOnScreen

Quick Verification

If your menu logic is bound to the Root window (clicking the blank wallpaper), check that your wallpaper tool isn't eating your mouse clicks on the other three screens. If you use a tool like feh or xwallpaper to set backgrounds across all four displays, ensure your mouse binding targets the root mask globally:

Code snippet
# Mouse [Button] [Context] [Modifiers] [Function]
# 'R' means Root window (the desktop background) on ALL connected displays
Mouse 3  R  A  Menu RootMenu Context
profile picture


Gemini is AI and can make mistakes.