Moving from I3 to macOS with Minimum Pain

I was a long time Linux user, most recently using I3 (Ubuntu/Regolith). The moment Apple released M1-based laptop, though, I wanted one. Because it’s fast and deservedly so.

The article linked above talks about the M1 architecture and it’s hardware accelerators, which explains why any Linux kernel that would use that hardware platform to full potential is very far away, so it looks like the only way to enjoy it today is to live with macOS.

Moving to macOS from I3? Dock? Ugh. Poking with a mouse moving and resizing windows? Thanks, no thanks.

Can macOS be made to work more like I3? Yabai, Amethyst – not slick. Rectangle? Way too much bother. Could a third solution be found, satisfying the requirements, simple and easy to use, setup and maintain?

The Requirements

I want maximized windows, easy keyboard-based app switch, keyboard shortcut to send to another screen, split screen occasionally.

The solution

  • Hide Dock
  • Launch apps via Command + Space
  • Maximize all windows
  • Send to another screen button
  • Split screen vertically

Hide dock / Launch apps via Command + Space

Hiding the dock is very easy – just hit Option-Command-D.

Switch between apps using Alt-Tab (and Shift-Alt-Tab).

Command+space for launching apps? It usually opens spotlight search. This could be changed in Settings: Keyboard -> Shortcuts -> Show Launch Pad: Command+Space. You might have to remove spotlight search shortcut by unchecking “Show Spotlight search” first. Note that the “3-rectangle/F3” keyboard button opens Launch Pad too, but we will use this button for more important things in the next section.

Maximize all Windows / Send to another screen button

Use Hammerspoon script to make the “3-rectangle/F3” button move the selected app to another screen (if such screen is present) and maximize it (always). At some point all of the apps are maximized and hitting Alt-Tab simply replaces one with another.

Why not use macOS-native maximized “full screen” workspaces, similar to I3? There are some issues with that and no benefits. First, the number and order of these workspaces change when the app windows open and close, so they can’t be precisely addressed with I3-like workspace shortcuts. Second, switching these workspaces triggers heavy animation. And it does not give you much extra real estate either: the “full screen” maximization does not include the top line with the camera notch on newer MacBooks – the area just becomes black and is not being used by the app window.

Split screen vertically

A small addition to the above Hammerspoon script lets us park a selected window to the left or right side of the screen using Control-Option-Command+Left or Right arrow button.

The Hammerspoon Script

function moveToNextScreen()
	hs.window.animationDuration = 0
    local win = hs.window.focusedWindow()
	screens = hs.screen.allScreens()
	local max_screen_index = 1
	local this_screen_index = 1
	for i, screen in pairs(screens) do
		max_screen_index = i
		if screen:name() == win:screen():name() then
			this_screen_index = i
		end
	end
	local next_screen_index = this_screen_index+1
	if next_screen_index == max_screen_index+1 then next_screen_index = 1 end
	local next_screen = screens[next_screen_index]
	win:moveToScreen(next_screen)
	win:maximize()
end
hs.hotkey.bind({"cmd","alt","shift"}, "S", moveToNextScreen)

hs.hotkey.bind({"cmd", "alt", "ctrl"}, "Left", function()
	local win = hs.window.focusedWindow()
	local f = win:frame()
	local screen = win:screen()
	local max = screen:frame() 
	f.x = max.x
	f.y = max.y
	f.w = max.w / 2
	f.h = max.h
	win:setFrame(f)
end)

hs.hotkey.bind({"cmd", "alt", "ctrl"}, "Right", function()
	local win = hs.window.focusedWindow()
	local f = win:frame()
	local screen = win:screen()
	local max = screen:frame() 
	f.x = max.x + (max.w / 2)
	f.y = max.y
	f.w = max.w / 2
	f.h = max.h
	win:setFrame(f)
end)

local keyboardHandler = function(event)
	local keyCode = event:getKeyCode()
	if keyCode == 160 then
		moveToNextScreen()
		return true
	end
end

keyboardEventListener = hs.eventtap.new({
	hs.eventtap.event.types.keyDown
}, keyboardHandler)
keyboardEventListener:start()

What else? Unrelated to I3: using Forklift gave me SSH mounts, something dearly missed from Linux otherwise.

Fix EC2 Windows logon issue by moving the AWS image to desktop and back

After installing a Windows Remote Desktop client access licenses, commonly known as CALs, on an AWS EC2-based Windows machine, I made a mistake of not specifying my RD license server in the terminal server settings. Once the demo licenses ran out, the CALs did not take, and I ended up with a valuable machine, used by 4 people daily, locked out and impossible to login into.

Continue reading

Coffee with crema from an Aeropress – a howto

What makes crema?

Crema is a foam comprising coffee oils, carbon dioxide created during coffee roasting and air trapped in coffee grounds. There are several exhaustive Coffeegeek articles in the subject. (I  also think electric-pump-based coffee/espresso machines increase crema by aerating brewing water.)

Why there is little crema in coffee from Aeropress?

Oils and bubbles, being lighter than water, travel up when brewing. When Aeropress is used as described in the manual, crema is filtered last and gets absorbed in the grounds and paper filter.

crema in inverted aeropress

Continue reading

Video Stabilization with Deshaker in Blender

Action video is often lacking clear persistent references to stabilize video with – they either are not present in the frame for very long, or often compressed out of frame as the codec is trying to spend most of its bandwidth on moving objects in the shot.

Deshaker, a plugin for Windows program VirtualDub, with its capability to find and track multiple visual references (literally hundreds of them) automatically from frame to frame is the king of action video stabilization. (It works on Linux, too, see below).

Deshaker scanning a file

Continue reading