#!/bin/sh ####################################################################### # # Set up application windows the way I like, across my 9 Gnome workspaces. # I use http://svn.red-bean.com/repos/kfogel/trunk/.local/share/\ # gnome-shell/extensions/kfogel-desktop-setup@kfogel.red-bean.com/ to # launch this script from an icon on my Gnome title bar (which I think # is the name for the bar along the top of the screen that shows the # date, the network connection status, battery power, etc, and at its # right has that dropdown menu with, you know, the stuff). # # https://unix.stackexchange.com/questions/27050/\ # how-to-start-an-application-on-a-different-workspace # ####################################################################### # # Copyright (C) 2018, 2019 Karl Fogel # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ####################################################################### # 2025-04-17: https://kfogel.org/notice/AtC6LXJXyfHF0K7076 asks about: # # A bug has appeared recently, in which the xterms show up tiny and # not in their specified positions. Various sources (e.g. # https://bugs.launchpad.net/ubuntu/+source/gnome-terminal/+bug/1925732) # claim that under Wayland one cannot specify a window's position, or # at least cannot do so on window launch. If true, this boggles the # mind. I don't yet know if it's actually true. I would think it # can't be, since clearly GNOME Shell can position them -- I can drag # a window with the mouse, after all! But I tested with... # # gnome-terminal --geometry 80x24+115+100 # # ...and indeed that doesn't work. But maybe some kind of dconf magic # will do the trick? I was researching how to set GNOME terminal # colors by default, and ran across these posts: # # https://askubuntu.com/questions/1456938/how-do-i-script-changing-the-color-scheme-in-gnome-terminal # # https://stackoverflow.com/questions/263892/change-the-background-color-in-gnome-terminal-through-a-command # # Also, there's this suggestion of XWayland: # # https://askubuntu.com/questions/1104827/how-can-i-get-the-geometry-option-working-with-the-gnome-terminal-command-in-a-t # # If any of that stuff works, maybe I can get the life I used to have # back? # # Life got harder under Wayland, that's for sure. # # For now, I'm still launching xterms below. But at the very least # I'll need to figure out how to make them non-tiny the way they used # to be, and it'd sure be nice to have positioning working again too. XTERM=/usr/bin/xterm DRY_RUN="no" # Pass "b" argument to launch browser only, or "--dry-run" for info only. BROWSER_ONLY="no" if [ "${1}" = "b" ]; then BROWSER_ONLY="yes" elif [ "${1}" = "--dry-run" ]; then DRY_RUN="yes" elif [ "${1}x" != "x" ]; then echo "WARNING: '${1}' unrecognized (use 'b' for browser-only)" >&2 exit 1 fi # Th default is enough seconds for most machines; on some # particularly slow machines ones we increase it. BROWSER_STARTUP_INTERVAL=3 HOSTNAME=`hostname -s` if [ ${HOSTNAME} = "klib" ]; then BROWSER_STARTUP_INTERVAL=6 elif [ ${HOSTNAME} = "klen" ]; then BROWSER_STARTUP_INTERVAL=5 fi # Add one level of indirection for wmctrl because there are divergent # forks (https://github.com/Conservatory/wmctrl lists a couple of them # in its README) and we might want to experiment with some of them some # day. That would involve using a locally-built wmctrl instead of the # one in the Debian package repository, hence this indirection step. WMCTRL=/usr/bin/wmctrl cd ${HOME} ${HOME}/bin/xfix ${WMCTRL} -n 9 # Gnome names workspaces starting from 0, but I name them starting # from 1 so they match the function keys I bind them to. To avoid # off-by-one confusion, the symbolic names below match my naming, # while the values match Gnome's (we pass the value as the parameter # to the '-t' option of 'wmctrl'). WKSPC_1="0" WKSPC_2="1" WKSPC_3="2" WKSPC_4="3" WKSPC_5="4" WKSPC_6="5" WKSPC_7="6" WKSPC_8="7" WKSPC_9="8" # Parameters that control window dimensions and placements. SXW="80" # My xterms have the same width on all machines. SXH="24" # Standard xterm height is the same on all machines. TXH="UNINITIALIZED" # Tall xterm height varies by machine. O_X="UNINITIALIZED" # Other left X (b/c workspace 7 has tall xterm too) R_X="UNINITIALIZED" # Right X coordinate (workspaces 1, 2) L_X="UNINITIALIZED" # Left X coordinate (workspace 2) B_Y="UNINITIALIZED" # Bottom Y coordinate (workspaces 1, 2) T_Y="UNINITIALIZED" # Top Y coordinate (workspace 2) C_X="UNINITIALIZED" # Center X coordinate (workspaces 3, 8, 9) C_Y="UNINITIALIZED" # Center Y coordinate (workspaces 3, 8, 9) FFOX_W="UNINITIALIZED" # Firefox width FFOX_H="UNINITIALIZED" # Firefox height # Initialize all the uninitialized parameters. I determined the first # few of these by experimentation, but eventually (starting with the # "mused" entry) had enough information to calculate the parameters # arithmetically. So all the entries could now be done arithmetically # with dynamic code, based on the output of 'xwininfo -root'. Doing # so would future-proof the code for whatever new machines might get # added, and maybe I'll get around to it some day, but right now the # hardcoded numbers work for all the machines I currently own anyway. # # And even before having a closed form, one can just use the # dimensions as keys to know which monitor we're on. ROOT_W=`xwininfo -root | grep -E "^ +Width: " | cut -d " " -f 4` ROOT_H=`xwininfo -root | grep -E "^ +Height: " | cut -d " " -f 4` WALLPAPER_IMG="${HOME}/x/abstract-tiled-kluge-${ROOT_W}x${ROOT_H}.png" if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "Wallpaper image would be: '${WALLPAPER_IMG}'" elif [ -f ${WALLPAPER_IMG} ]; then gsettings set org.gnome.desktop.background picture-uri "file://${WALLPAPER_IMG}" fi if [ "${ROOT_W}x${ROOT_H}" = "1280x1024" ]; then if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "In former kwork external monitor case: ${ROOT_W}x${ROOT_H}" fi TXH="072" O_X="200" R_X="788" L_X="010" B_Y="664" T_Y="035" C_X="397" C_Y="374" FFOX_W="1261" FFOX_H="0944" elif [ "${ROOT_W}x${ROOT_H}" = "1920x1080" \ -o "${ROOT_W}x${ROOT_H}" = "3286x1080" ]; then if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "In home large monitor (floss) / libq / tcd / tcs case: ${ROOT_W}x${ROOT_H}" fi # The tiny DS-13302 travel monitor (that I got based on Jason Owen's # recommendation) officially has a resolution of 2560x1600, and yet # it seems to match the 1920x1080 entry here, just as the larger 17" # ViewSonic travel monitor also does. I'm not sure what's going on # with that smaller monitor, so I'm just making a note of it here. # So far, they both seem to use this entry with no problems. # TODO (2021-10-25): File a GNOME 41.0 bug about the 3286x1080 case # above; see explanation below. TL;DR: display width is incorrect. # # When you first start up you may get 3200x1080 or 3286x1080 or some # similarly ridiculously wide width. This is because it's creating # one desktop that connects across the external monitor and the home # monitor of the laptop (it was klib that I discovered this with, # but probably it'd happen with klen or anything else too). Once # you switch into external-only mode, presumably 'xwininfo -root' # will give a new result, and the first option above will match. # In the meantime, see x/abstract-tiled-kluge-3200x1080.png & r6186. TXH="076" O_X="200" R_X="1424" L_X="012" B_Y="717" T_Y="039" C_X="757" C_Y="404" # Normally these are unset and we'd fall back to L_X and T_Y, # but there seems to be some wonkiness going on these days. # I used to think it was only on klen, but now I'm seeing it on tcd # with an external monitor. [ref:0a39f8f8] FFOX_X="-013" FFOX_Y="016" FFOX_W="1555" # updated 2024-10-17 for Wayland-only purgatory # The large large monitor at home (floss) and the large monitor at # work (kwork) have the same dimensions, but somehow firefox's # vertical dimension behaves differently on them. if [ "${HOSTNAME}" = "kwork" ]; then FFOX_H="1031" # updated 2024-10-17 for Wayland-only purgatory else # Default to the floss height, for no particular reason. FFOX_H="1031" # updated 2024-10-17 for Wayland-only purgatory fi elif [ "${ROOT_W}x${ROOT_H}" = "1680x1050" ]; then if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "In large Dell monitor from Peter Sperling: ${ROOT_W}x${ROOT_H}" fi TXH="074" O_X="250" R_X="1189" L_X="010" B_Y="688" T_Y="038" C_X="555" C_Y="404" # Normally these are unset and we'd fall back to L_X and T_Y, # but there seems to be some wonkiness going on these days. # See ref:0a39f8f8. FFOX_X="-16" FFOX_Y="15" FFOX_W="1714" FFOX_H="1055" elif [ "${ROOT_W}x${ROOT_H}" = "1366x768" ]; then if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "In klen native screen case: ${ROOT_W}x${ROOT_H}" fi TXH="053" O_X="200" R_X="876" L_X="006" B_Y="409" T_Y="033" C_X="438" C_Y="230" if [ "${HOSTNAME}" = "klen" ]; then # See ref:0a39f8f8. FFOX_X="-018" FFOX_Y="015" fi FFOX_W="1403" FFOX_H="0773" elif [ "${ROOT_W}x${ROOT_H}" = "2160x1440" ]; then if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "In khip native screen case: ${ROOT_W}x${ROOT_H}" fi TXH="052" # TBD O_X="24" # TBD R_X="532" # TBD L_X="010" # TBD B_Y="408" # TBD T_Y="035" # TBD C_X="269" # TBD C_Y="246" # TBD FFOX_W="1005" # TBD FFOX_H="0688" # TBD elif [ "${ROOT_W}x${ROOT_H}" = "1280x800" ]; then if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "In klib native screen case: ${ROOT_W}x${ROOT_H}" fi TXH="055" O_X="200" R_X="788" L_X="010" B_Y="440" T_Y="035" C_X="397" C_Y="262" FFOX_W="1261" FFOX_H="0720" elif [ "${ROOT_W}x${ROOT_H}" = "1024x768" ]; then if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "In home small monitor (mused et al) case: ${ROOT_W}x${ROOT_H}" fi TXH="052" O_X="24" R_X="532" L_X="010" B_Y="408" T_Y="035" C_X="269" C_Y="246" FFOX_W="1005" FFOX_H="0688" fi ### Set up all the xterms, unless browser-only. ### if [ "${BROWSER_ONLY}" = "no" -a "${DRY_RUN}" = "no" ]; then # Launch the xterms. ${XTERM} -geometry ${SXW}x${SXH}+${R_X}+${B_Y} -n w1-br & ${XTERM} -geometry ${SXW}x${SXH}+${R_X}+${B_Y} -n w2-br & ${XTERM} -geometry ${SXW}x${SXH}+${L_X}+${B_Y} -n w2-bl & ${XTERM} -geometry ${SXW}x${SXH}+${L_X}+${T_Y} -n w2-ul & ${XTERM} -geometry ${SXW}x${SXH}+${R_X}+${T_Y} -n w2-ur & ${XTERM} -geometry ${SXW}x${SXH}+${C_X}+${C_Y} -n w3-center & ${XTERM} -geometry ${SXW}x${SXH}+${O_X}+${C_Y} -n w7-center & ${XTERM} -geometry ${SXW}x${TXH}+${R_X}+${T_Y} -n w7-right & ${XTERM} -geometry ${SXW}x${SXH}+${C_X}+${C_Y} -n w8-center & ${XTERM} -geometry ${SXW}x${SXH}+${C_X}+${C_Y} -n w9-center & # Send them to the right workspaces. sleep 1 ${WMCTRL} -r w1-br -t ${WKSPC_1} sleep 1 ${WMCTRL} -r w2-br -t ${WKSPC_2} sleep 1 ${WMCTRL} -r w2-bl -t ${WKSPC_2} sleep 1 ${WMCTRL} -r w2-ul -t ${WKSPC_2} sleep 1 ${WMCTRL} -r w2-ur -t ${WKSPC_2} sleep 1 ${WMCTRL} -r w3-center -t ${WKSPC_3} sleep 1 ${WMCTRL} -r w7-center -t ${WKSPC_7} sleep 1 ${WMCTRL} -r w7-right -t ${WKSPC_7} sleep 1 ${WMCTRL} -r w8-center -t ${WKSPC_8} sleep 1 ${WMCTRL} -r w9-center -t ${WKSPC_9} sleep 1 fi ### Set up Firefox. ### # # Firefox doesn't take standard X Windows options -geometry and -n. # Also, if you ask the Internet how to open Firefoxen on specified # workspaces at a specified position with specified width and height, # you will quickly disappear into a maze of rumor, speculation, and # half-tested solutions. However, the recipe below seems to work. # # (Another solution I played with was preserving a particular session # store -- see r7870 in private repository -- and manually slipping it # into place just before starting Firefox: # # FFOX_SESS_DIR=.mozilla/firefox/erbg2usa.default # cp ${HOME}/${FFOX_SESS_DIR}/sessionstore.js \ # ${HOME}/${FFOX_SESS_DIR}/sessionstore-backups/orig-sessionstore.js # cp ${HOME}/private/${FFOX_SESS_DIR}/`hostname -s`-sessionstore.js \ # ${HOME}/${FFOX_SESS_DIR}/sessionstore.js # # Maybe it would work, but it feels brittle and I'd rather not go there.) if [ "${DRY_RUN}" = "yes" ]; then echo "" echo "Window manager Firefox placement command would be:" echo "" echo " ${WMCTRL} -r 'FFox ' -e '0,${L_X},${T_Y},${FFOX_W},${FFOX_H}'" else # Normally we don't set special values for the Firefox coordinates. # However, on some machines+display combinations (cough klen cough) # something's wonky, and the X,Y values that work for the xterms # don't work for Emacs and vice versa. So in that situation we set # separate values just for Firefox. (And I doubt we'd ever set X # without setting Y, but I see no reason to code that assumption in; # it costs nothing to test each parameter individually.) if [ "${FFOX_X}" = "" ]; then FFOX_X="${L_X}" fi if [ "${FFOX_Y}" = "" ]; then FFOX_Y="${T_Y}" fi for num in 1 2 3; do # Start small enough to avoid triggering full-screen behavior, # from which wmctrl apparently is unable to pull Firefox back. # # Status as of 2024-10-17: # # Eventually I hope to figure out a way to control the position # and size of Firefox windows under mutter, the default GNOME # Wayland compositor, the way I used to be able to with wmctrl. # The big Debian upgrade of Firefox ESR from 115.15 to 128.3.1 # seems also to have gotten rid of any X Windows support in the # Firefox build, which means the old method -- which worked so, # *so* beautifully, oh my goodness, a lost Eden -- of starting up # my Firefox windows and then positioning them in exactly the # places I wanted, at exactly the size I wanted, on exactly the # virtual desktops I wanted, no longer works. # # So for now I'm reduced to at least placing them on one desktop, # with at least one dimension correct; I can't seem to get both # dimensions because, for some reason, beyond a certain width the # Firefox window just automatically maximizes and covers the whole # desktop, which is not what I want. All I can do is get some of # the sizing and positioning done automatically, then take it the # rest of the way manually, and then manually move them to the # right virtual desktops. What a huge regression. Sigh. # The -height and -width options seem to work, although as of # 2018-09-08 the only documentation of them I could find was at # https://www-archive.mozilla.org/docs/command-line-args.html, # not at any of Mozilla's more official-looking sites. firefox -width "${FFOX_W}" -height "${FFOX_H}" & ### All this wmctrl stuff stopped working when Debian's Firefox ### went Wayland-only and stopped including X Windows support. ### (See above comment "Status as of 2024-10-17" for details.) ## ## Wait long enough for Firefox to do its morning toilette: # # sleep ${BROWSER_STARTUP_INTERVAL} # ## Rename the Firefox window according to its destination workspace: ## (By default, Firefox seems to always launch with the window name ## "Mozilla Firefox". If that ever changes, this code will break. ## See https://unix.stackexchange.com/questions/43106/\ ## how-to-set-window-size-and-location-of-an-application-on-screen-\ ## via-command-line for some ideas on how to deal with that.) # # ${WMCTRL} -T "FFox ${num}" -r "Mozilla Firefox"; # sleep 2; # ## Send it to the right workspace: # # ${WMCTRL} -t `dc -e "${num} 2 + p"` -r "FFox ${num}"; # sleep 1; # ## Resize it there: # # ${WMCTRL} -r "FFox ${num}" -e "0,${FFOX_X},${FFOX_Y},${FFOX_W},${FFOX_H}" done fi