What makes us different from other similar websites? › Forums › Tech › Tiled Display Script [Xubuntu]
Tagged: Grid Display, Linux, Tiled Windows, Titled, Xubuntu
- This topic has 2 replies, 1 voice, and was last updated 1 month, 2 weeks ago by
thumbtak.
-
AuthorPosts
-
June 2, 2025 at 11:56 am #8064
thumbtakModeratorIf you want apps to be easily placed into sections on your monitor that seems to fit nicely and will help you be more productive, then this could work for you.
It will work like this, in the end, but this only works if you have one monitor.
Install these files:
$ sudo apt install xdotool wmctrlBash Script (make sure to correct the width and height):
#!/bin/bash # --- Configuration --- # IMPORTANT: Set these accurately for your monitor! MONITOR_WIDTH=5120 MONITOR_HEIGHT=1440 # --- Calculations (DO NOT MODIFY) --- GRID_COLS=3 GRID_ROWS=2 CELL_WIDTH=$((MONITOR_WIDTH / GRID_COLS)) CELL_HEIGHT=$((MONITOR_HEIGHT / GRID_ROWS)) # --- Helper Function for Tiling --- tile_window() { local target_x=$1 local target_y=$2 WIN_ID=$(xdotool getactivewindow) if [ -z "$WIN_ID" ]; then # No active window found, exit quietly exit 1 fi # Unmaximize window if it's maximized, crucial for resizing. wmctrl -i -r "$WIN_ID" -b remove,maximized_vert,maximized_horz # Move and Resize Window xdotool windowmove "$WIN_ID" "$target_x" "$target_y" xdotool windowsize "$WIN_ID" "$CELL_WIDTH" "$CELL_HEIGHT" } # --- Specific Tiling Functions for Each Cell --- tile_top_left() { tile_window 0 0 } tile_top_middle() { tile_window "$CELL_WIDTH" 0 } tile_top_right() { tile_window $((2 * CELL_WIDTH)) 0 } tile_bottom_left() { tile_window 0 "$CELL_HEIGHT" } tile_bottom_middle() { tile_window "$CELL_WIDTH" "$CELL_HEIGHT" } tile_bottom_right() { tile_window $((2 * CELL_WIDTH)) "$CELL_HEIGHT" } # --- Main Script Logic --- # This part executes the correct function based on the argument passed to the script. case "$1" in "top_left") tile_top_left ;; "top_middle") tile_top_middle ;; "top_right") tile_top_right ;; "bottom_left") tile_bottom_left ;; "bottom_middle") tile_bottom_middle ;; "bottom_right") tile_bottom_right ;; *) echo "Usage: $0 {top_left|top_middle|top_right|bottom_left|bottom_middle|bottom_right}" exit 1 ;; esacSave the script in your home folder (called “tile_grid_master.sh”) and into a folder called script.
Now make the keyboard shortcuts.
Go to:
Applications => Settings => Keyboard => Application ShortcutsAdd the following commands, and shortcuts. Make sure to change HOME, to your logged in home folder name.
/home/HOME/scripts/tile_grid_master.sh bottom_left
Super+1/home/HOME/scripts/tile_grid_master.sh bottom_middle
Super +2/home/HOME/scripts/tile_grid_master.sh bottom_right
Super+3/home/HOME/scripts/tile_grid_master.sh top_left
Super+4/home/HOME/scripts/tile_grid_master.sh top_middle
Super+5/home/HOME/scripts/tile_grid_master.sh top_right
Super+6May 15, 2026 at 8:03 pm #8478
thumbtakModeratorIf you have two monitors and want to use it for both, this is the script for two.
#!/bin/bash # --- Configuration --- # Single monitor dimensions (3440 x 1440 Ultrawide) MONITOR_WIDTH=3440 MONITOR_HEIGHT=1440 # --- Calculations --- # 3 columns and 2 rows = 6 sections PER MONITOR (12 total across both) GRID_COLS_PER_MONITOR=3 GRID_ROWS=2 # Exact pixel math per section (3440 / 3 = 1146 pixels wide) CELL_WIDTH=$((MONITOR_WIDTH / GRID_COLS_PER_MONITOR)) CELL_HEIGHT=$((MONITOR_HEIGHT / GRID_ROWS)) # --- Helper Function for Tiling --- tile_window() { local target_x=$1 local target_y=$2 # Get active window WIN_ID=$(xdotool getactivewindow) if [ -z "$WIN_ID" ]; then exit 1 fi # Unmaximize window wmctrl -i -r "$WIN_ID" -b remove,maximized_vert,maximized_horz # Move and Resize Window (Gravity 1 forces the exact width) wmctrl -i -r "$WIN_ID" -e 1,"$target_x","$target_y","$CELL_WIDTH","$CELL_HEIGHT" } # --- Main Script Logic --- case "$1" in # ================= MONITOR 1 (Left Screen) ================= "m1_top_left") tile_window 0 0 ;; "m1_top_middle") tile_window "$CELL_WIDTH" 0 ;; "m1_top_right") tile_window $((2 * CELL_WIDTH)) 0 ;; "m1_bottom_left") tile_window 0 "$CELL_HEIGHT" ;; "m1_bottom_middle") tile_window "$CELL_WIDTH" "$CELL_HEIGHT" ;; "m1_bottom_right") tile_window $((2 * CELL_WIDTH)) "$CELL_HEIGHT" ;; # ================= MONITOR 2 (Right Screen) ================= "m2_top_left") tile_window "$MONITOR_WIDTH" 0 ;; "m2_top_middle") tile_window $((MONITOR_WIDTH + CELL_WIDTH)) 0 ;; "m2_top_right") tile_window $((MONITOR_WIDTH + (2 * CELL_WIDTH))) 0 ;; "m2_bottom_left") tile_window "$MONITOR_WIDTH" "$CELL_HEIGHT" ;; "m2_bottom_middle") tile_window $((MONITOR_WIDTH + CELL_WIDTH)) "$CELL_HEIGHT" ;; "m2_bottom_right") tile_window $((MONITOR_WIDTH + (2 * CELL_WIDTH))) "$CELL_HEIGHT" ;; *) echo "Usage: $0 {m1_top_left|m1_top_middle|m1_top_right|m1_bottom_left... or m2_...}" exit 1 ;; esac===================================================================
MONITOR 1 (LEFT SCREEN) – KEYBOARD KEYS: ` THROUGH 5
===================================================================[Top Left]
Shortcut: Super + `
Command: /home/tak/Scripts/dual-tile.sh m1_top_left[Top Middle]
Shortcut: Super + 1
Command: /home/tak/Scripts/dual-tile.sh m1_top_middle[Top Right]
Shortcut: Super + 2
Command: /home/tak/Scripts/dual-tile.sh m1_top_right[Bottom Left]
Shortcut: Super + 3
Command: /home/tak/Scripts/dual-tile.sh m1_bottom_left[Bottom Middle]
Shortcut: Super + 4
Command: /home/tak/Scripts/dual-tile.sh m1_bottom_middle[Bottom Right]
Shortcut: Super + 5
Command: /home/tak/Scripts/dual-tile.sh m1_bottom_right===================================================================
MONITOR 2 (RIGHT SCREEN) – KEYBOARD KEYS: 6 THROUGH –
===================================================================[Top Left]
Shortcut: Super + 6
Command: /home/tak/Scripts/dual-tile.sh m2_top_left[Top Middle]
Shortcut: Super + 7
Command: /home/tak/Scripts/dual-tile.sh m2_top_middle[Top Right]
Shortcut: Super + 8
Command: /home/tak/Scripts/dual-tile.sh m2_top_right[Bottom Left]
Shortcut: Super + 9
Command: /home/tak/Scripts/dual-tile.sh m2_bottom_left[Bottom Middle]
Shortcut: Super + 0
Command: /home/tak/Scripts/dual-tile.sh m2_bottom_middle[Bottom Right]
Shortcut: Super + –
Command: /home/tak/Scripts/dual-tile.sh m2_bottom_rightMay 31, 2026 at 12:58 pm #8489
thumbtakModeratorHere is the most up to date version I use and with all the comments in the script that you will need to make it work for you. Make sure to save it as
dual-tile.sh#!/bin/bash # ============================================================================= # dual-tile.sh — Dual-Monitor 3×2 Window Tiling Script # ============================================================================= # # SYSTEM DETAILS: # OS: Xubuntu (Linux 7.0) # Desktop: Xfce # Window Manager: XFWM4 # WM Theme: Win11-round-Dark-compact # Terminal: kitty # # HARDWARE: # Monitors: 2× Ultrawide (3440 × 1440 each) # Left Monitor: HDMI-0, 3440×1440, positioned at +0+0 # Right Monitor: HDMI-1, 3440×1440, positioned at +3567+0 # Note: There is a 127px invisible gap between monitors # in the desktop coordinate space. # # PANEL: # Left Monitor: 24px top panel (Xfce panel) # Right Monitor: No panel # # GRID LAYOUT: # 3 columns × 2 rows per monitor (6 cells per monitor, 12 total) # # DEPENDENCIES & INSTALLATION: # On Ubuntu/Xubuntu (apt): # sudo apt install wmctrl xdotool # # On Fedora (dnf): # sudo dnf install wmctrl xdotool # # On Arch (pacman): # sudo pacman -S wmctrl xdotool # # Package purposes: # wmctrl — window management (unmaximize, move, resize) # xdotool — detect active window # xprop — (not currently used, but available for frame detection) # # KEYBOARD SHORTCUT EXAMPLE (Xfce Settings → Keyboard → Shortcuts): # super + 1 → /path/to/dual-tile.sh m1_top_left # super + 2 → /path/to/dual-tile.sh m1_top_middle # super + 3 → /path/to/dual-tile.sh m1_top_right # super + 4 → /path/to/dual-tile.sh m1_bottom_left # super + 5 → /path/to/dual-tile.sh m1_bottom_middle # super + 6 → /path/to/dual-tile.sh m1_bottom_right # super + 7 → /path/to/dual-tile.sh m2_top_left # super + 8 → /path/to/dual-tile.sh m2_top_middle # super + 9 → /path/to/dual-tile.sh m2_top_right # ... etc. # # HOW TO ADAPT FOR YOUR SYSTEM: # 1. Run: xrandr | grep " connected" # — Note your monitor positions (the +X+Y values) # 2. Manually arrange 12 windows in a 3×2 grid on each monitor # 3. For each window, run: # xwininfo -id $(xdotool getactivewindow) | grep "Absolute upper-left" # — This gives the FRAME position (what wmctrl needs) # 4. Then run: # xdotool getactive window getwindowgeometry --shell # — This gives the CLIENT width/height (what wmctrl uses for w,h) # 5. Replace the coordinates below with your captured values # 6. Subtract the panel height from all Y values (wmctrl uses workarea coords) # # IMPORTANT NOTES: # - wmctrl -e positions relative to the WORKAREA (below panel/dock), # NOT the absolute screen position. You must subtract the panel # height from coordinates captured with xwininfo. # - xdotool getwindowgeometry returns CLIENT (content) coordinates. # - xwininfo "Absolute upper-left" returns FRAME coordinates. # - wmctrl -e uses FRAME x,y but CLIENT width,height. # - Frame coordinates = Client coordinates − decoration offsets # (title bar height for Y, left border width for X) # # ============================================================================= # --- Helper Function for Tiling --- tile_window() { local target_x=$1 local target_y=$2 local target_w=$3 local target_h=$4 WIN_ID=$(xdotool getactivewindow) if [ -z "$WIN_ID" ]; then exit 1 fi wmctrl -i -r "$WIN_ID" -b remove,maximized_vert,maximized_horz wmctrl -i -r "$WIN_ID" -e 1,"$target_x","$target_y","$target_w","$target_h" } # --- Panel Configuration --- # Height of the top panel in pixels. Subtract this from all Y coordinates # because wmctrl positions relative to the workarea (below panel/dock). # Set to 0 if no panel exists. PANEL=24 # --- Main Script Logic --- # Coordinates are FRAME position (x, y) and CLIENT size (w, h). # Y values have already been adjusted by subtracting PANEL (24px) # to convert from absolute screen coords to wmctrl workarea coords. case "$1" in # ================= MONITOR 1 (Left Screen: HDMI-0 at +0+0) ================= # Top row: flush below panel (Y=0 in workarea coords) "m1_top_left") tile_window 2 0 1146 690 ;; "m1_top_middle") tile_window 1152 0 1146 690 ;; "m1_top_right") tile_window 2302 0 1148 690 ;; # Bottom row: Y=746 in workarea coords "m1_bottom_left") tile_window 2 746 1146 659 ;; "m1_bottom_middle") tile_window 1152 746 1146 659 ;; "m1_bottom_right") tile_window 2302 746 1136 659 ;; # ================= MONITOR 2 (Right Screen: HDMI-1 at +3567+0) ================= # Top row: Y=3 in workarea coords (no panel on this monitor) "m2_top_left") tile_window 3569 3 1136 690 ;; "m2_top_middle") tile_window 4709 3 1136 690 ;; "m2_top_right") tile_window 5849 3 1156 690 ;; # Bottom row: Y=729 in workarea coords "m2_bottom_left") tile_window 3569 729 1136 678 ;; "m2_bottom_middle") tile_window 4709 729 1136 678 ;; "m2_bottom_right") tile_window 5849 729 1146 678 ;; *) echo "Usage: $0 {m1_top_left|m1_top_middle|m1_top_right|m1_bottom_left|m1_bottom_middle|m1_bottom_right|m2_top_left|m2_top_middle|m2_top_right|m2_bottom_left|m2_bottom_middle|m2_bottom_right}" exit 1 ;; esac -
AuthorPosts
- You must be logged in to reply to this topic.
