I used to be able to get Picture In Picture with Chrome by maximizing the video, Alt+F3+M+F to exit fullscreen but stay in Chrome’s “fullscreen mode” with the addressbar and window frame hidden. I would then hit Alt+F3+M+A to make the window stay on top. Finally I would use Alt+RightClick to resize the window to be smaller, and Alt+LeftClick to move the window into the bottom right of the screen. This worked for the most part, but was cumbersome to setup.

Unfortunately, I cannot do the same procedure for Firefox, as when we use Alt+F3+M+F to exit fullscreen, Firefox does not say in the “fullscreen mode” and the addressbar reappears.

After playing around with Firefox’s userChrome.css, when exploring Firefox’s browser toolbox I noticed you can easily display: none; to hide the CSD titlebar + addressbar.

If you haven’t already made a userChrome.css file, then navigate to ~/.mozilla/firefox/abcde124.default/ or whatever your profile’s folder name is. Then create the .../abcde124.default/chrome/userChrome.css directory and file. Open up userChrome.css then add the following:

/* Picture in Picture */
#main-window[sizemode="normal"][width="565"][height="318"] #titlebar,
#main-window[sizemode="normal"][width="565"][height="318"] #navigator-toolbox {
	display: none;
}

Restart firefox.

Next up lets create a KWin Script that will resize the firefox window to 565 x 318 when snapped to the bottom right corner of the screen.

Navigate to ~/.local/share/ then create any missing folders in the path ~/.local/share/kwin/scripts/FirefoxPictureInPicture/contents/code/. Then make 2 new files FirefoxPictureInPicture/metadata.desktop and FirefoxPictureInPicture/contents/code/main.js.

mkdir -p ~/.local/share/kwin/scripts/FirefoxPictureInPicture/contents/code/
touch ~/.local/share/kwin/scripts/FirefoxPictureInPicture/metadata.desktop
touch ~/.local/share/kwin/scripts/FirefoxPictureInPicture/contents/code/main.js

In metadata.desktop put the following:

[Desktop Entry]
Name=Firefox Picture in Picture
Comment=
Icon=preferences-system-windows-script-test

Type=Service

X-Plasma-API=javascript
X-Plasma-MainScript=code/main.js
X-KDE-PluginInfo-Author=
X-KDE-PluginInfo-Email=
X-KDE-PluginInfo-Name=FirefoxPictureInPicture
X-KDE-PluginInfo-Version=2

X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-ServiceTypes=KWin/Script

Next in contents/code/main.js put:

// Breeze Gtk3 [Kubuntu/KDE Neon] has windowBorderWidth=0
// Breath Gtk3 [Manjaro] has windowBorderWidth=1
var windowBorderWidth = 0
var popupWidth = windowBorderWidth + 565 + windowBorderWidth
var popupHeight = windowBorderWidth + 318 + windowBorderWidth
var scrollbarAreaWidth = 20

function isFirefox(client) {
	return client.resourceClass == "firefox"
}

function withinThreshold(x, targetX, threshold) {
	return targetX - threshold <= x && x <= targetX + threshold
}

var applyCheck = function(client) {
	var rect = client.geometry

	var area = workspace.clientArea(KWin.WorkArea, workspace.activeScreen, workspace.currentDesktop)
	var halfX = area.width / 2
	var halfY = area.height / 2

	var screenX = rect.x - area.x
	var screenY = rect.y - area.y

	var isPosCenter = withinThreshold(screenX, halfX, 10) && withinThreshold(screenY, halfY, 10)
	var isHalfSize = withinThreshold(rect.width, halfX, 10) && withinThreshold(rect.height, halfY, 10)
	var isLargerSize = rect.width > halfX || rect.height > halfY

	if (!client.keepAbove && isPosCenter && isHalfSize) {
		rect.x = area.x + area.width - popupWidth - scrollbarAreaWidth
		rect.y = area.y + area.height - popupHeight
		rect.width = popupWidth
		rect.height = popupHeight
		client.geometry = rect
		client.keepAbove = true
		client.onAllDesktops = true
		client.skipTaskbar = true
		client.skipPager = true
	} else if (client.keepAbove && isLargerSize) {
		client.keepAbove = false
		client.onAllDesktops = false
		client.skipTaskbar = false
		client.skipPager = false

		// focus the window so it remains on top
		workspace.activeClient = client
	}

}

function onClientFinishUserMovedResized(client) {
	applyCheck(client)
}

function onClientAdded(client) {
	if (isFirefox(client)) {
		client.clientFinishUserMovedResized.connect(onClientFinishUserMovedResized)
	}
}

workspace.clientAdded.connect(onClientAdded)

var clients = workspace.clientList()
for (var i = 0; i < clients.length; i++) {
	var client = clients[i]
	onClientAdded(client)
}

Open System Settings > Window Management > KWin Scripts.

To reload the script, uncheck to disable our new script, click Apply, then enable our script, and click Apply.

Lets focus on the variables at the top.

// Breeze Gtk3 [Kubuntu/KDE Neon] has windowBorderWidth=0
// Breath Gtk3 [Manjaro] has windowBorderWidth=1
var windowBorderWidth = 0
var popupWidth = windowBorderWidth + 565 + windowBorderWidth
var popupHeight = windowBorderWidth + 318 + windowBorderWidth
var scrollbarAreaWidth = 20

In Kubuntu, which uses the Breeze Gtk3 theme, you’ll notice that the windows don’t have any border/outline around the windows. So leaving it at 0 should be fine. The window will resize to 565 x 318.

However, in Manjaro, the Gtk3 theme in Breath and has a 1px border around the window. This border means we need to resize the window to 567 x 320. So we need to set windowBorderWidth=1.

The scrollbarAreaWidth=20 adjusts how far away from the right side of the screen you wish the popup to appear. If you wish the popup to appear further from the bottom, it should be rather simple to modify the script to do so by using this variable as an example.