summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorEwout van Mansom2024-01-09 20:33:32 +0100
committerEwout van Mansom2024-01-09 20:33:32 +0100
commit06412def98aff916f9977f2f6bd9f7fdeb114eb8 (patch)
treece2eee346c658ffb34d0bafab2bf5ed31fb0de70
parenta595f56b6f9815773f7b00dfe4ae633b8d132813 (diff)
downloadaur-06412def98aff916f9977f2f6bd9f7fdeb114eb8.tar.gz
add wayland proxy
-rw-r--r--.SRCINFO12
-rw-r--r--0001-wayland-proxy.patch841
-rw-r--r--0002-wayland-proxy.patch88
-rw-r--r--0003-enable-vaapi.patch (renamed from 0001-enable-vaapi.patch)0
-rw-r--r--0004-remove-nvidia-blocklist.patch (renamed from 0002-remove-nvidia-blocklist.patch)0
-rw-r--r--PKGBUILD28
6 files changed, 959 insertions, 10 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 87a6e9a57c7b..28fb33c0f01f 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,7 +1,7 @@
pkgbase = firefox-vaapi
pkgdesc = Standalone web browser from mozilla.org (with VA-API patches)
pkgver = 121.0
- pkgrel = 1
+ pkgrel = 2
url = https://www.mozilla.org/firefox/
arch = x86_64
license = GPL
@@ -55,19 +55,25 @@ pkgbase = firefox-vaapi
source = https://archive.mozilla.org/pub/firefox/releases/121.0/source/firefox-121.0.source.tar.xz.asc
source = firefox.desktop
source = identity-icons-brand.svg
- source = 0001-enable-vaapi.patch
- source = 0002-remove-nvidia-blocklist.patch
+ source = 0001-wayland-proxy.patch
+ source = 0002-wayland-proxy.patch
+ source = 0003-enable-vaapi.patch
+ source = 0004-remove-nvidia-blocklist.patch
validpgpkeys = 14F26682D0916CDD81E37B6D61B7B526D98F0353
sha256sums = edc7a5159d23ff2a23e22bf5abe22231658cee2902b93b5889ee73958aa06aa4
sha256sums = SKIP
sha256sums = 1f241fdc619f92a914c75aece7c7c717401d7467c9a306458e106b05f34e5044
sha256sums = a9b8b4a0a1f4a7b4af77d5fc70c2686d624038909263c795ecc81e0aec7711e9
+ sha256sums = bbec9e3ed1fe1372f587383e8ca86bb28e4dd90874dc146450e6ecdc8d30f387
+ sha256sums = 2b439551262f6b1f341ff8156ad447b5196d5d5d1bf1d8f3a9f9910895d6c1de
sha256sums = 00c449422246283cd7e0bdc65d216fce4a42f755ad881106a08fb7d97eab1679
sha256sums = 75d3c213f3717cfc3f72acd4e3b6d029d373916f9ff9a1e8a3e2d7b0958760ed
b2sums = 80905caeb208ef5dce7b62e248c86598ca786eb7032e114ad5d10812623bfceb688832f646dfbe220ef2fcecacf11cefae2afb0f1cdc0f7952647b71c58c9602
b2sums = SKIP
b2sums = d07557840097dd48a60c51cc5111950781e1c6ce255557693bd11306c7a9258b2a82548329762148f117b2295145f9e66e0483a18e2fe09c5afcffed2e4b8628
b2sums = 63a8dd9d8910f9efb353bed452d8b4b2a2da435857ccee083fc0c557f8c4c1339ca593b463db320f70387a1b63f1a79e709e9d12c69520993e26d85a3d742e34
+ b2sums = 4daf6c7d670f94d782408cd6f7fa7c6a96e109d6d368f5e41b0353e6f81f9a12f0f32b72efb734814652df42e63941312edc54446e874ce84e82862fbdee8a33
+ b2sums = 896de88f76d37ad35d34084706c70170883e8b27630714ce326e00e327257c19e5ebee84cec45f3ab5db66becb6a7b5fb925f3b37b17f5b636d3517da07b914d
b2sums = f84752e04c7e69b69158b9514a5227a2b71b60ccbbe5acb437d9830bfa2e725fe6784e1603890722a114abda424f9cafc007e9934310f21483b6540bc19da905
b2sums = 87ecd8a3891a9a171173a97cf3b2b5f978be9ec876bb257d9f5e037f21dc5bd91167eabeb1c3cc181260b82cb2774c7b38ad73e1d807cc49b6d95617e2fb5d55
diff --git a/0001-wayland-proxy.patch b/0001-wayland-proxy.patch
new file mode 100644
index 000000000000..2202e710962b
--- /dev/null
+++ b/0001-wayland-proxy.patch
@@ -0,0 +1,841 @@
+diff --color --unified --recursive --text --new-file firefox-121.0.orig/third_party/wayland-proxy/moz.build firefox-121.0.new/third_party/wayland-proxy/moz.build
+--- firefox-121.0.orig/third_party/wayland-proxy/moz.build 1970-01-01 01:00:00.000000000 +0100
++++ firefox-121.0.new/third_party/wayland-proxy/moz.build 2024-01-09 02:23:05.161484173 +0100
+@@ -0,0 +1,16 @@
++# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
++# vim: set filetype=python:
++# This Source Code Form is subject to the terms of the Mozilla Public
++# License, v. 2.0. If a copy of the MPL was not distributed with this
++# file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++with Files("**"):
++ BUG_COMPONENT = ("Core", "Widget: Gtk")
++
++SOURCES += [
++ "wayland-proxy.cpp",
++]
++EXPORTS += [
++ "wayland-proxy.h",
++]
++FINAL_LIBRARY = "xul"
+diff --color --unified --recursive --text --new-file firefox-121.0.orig/third_party/wayland-proxy/wayland-proxy.cpp firefox-121.0.new/third_party/wayland-proxy/wayland-proxy.cpp
+--- firefox-121.0.orig/third_party/wayland-proxy/wayland-proxy.cpp 1970-01-01 01:00:00.000000000 +0100
++++ firefox-121.0.new/third_party/wayland-proxy/wayland-proxy.cpp 2024-01-09 02:23:05.161484173 +0100
+@@ -0,0 +1,742 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++// This code is based on Rust implementation at
++// https://github.com/the8472/weyland-p5000
++
++// Version 1.0
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdarg.h>
++#include <sys/ioctl.h>
++#include <sys/socket.h>
++#include <sys/stat.h>
++#include <sys/wait.h>
++#include <sys/un.h>
++#include <spawn.h>
++#include <poll.h>
++#include <vector>
++#include <cerrno>
++#include <fcntl.h>
++#include <unistd.h>
++#include <memory>
++#include <cassert>
++#include <pthread.h>
++#include <sched.h>
++
++#include "wayland-proxy.h"
++
++// The maximum number of fds libwayland can recvmsg at once
++#define MAX_LIBWAY_FDS 28
++#define MAX_DATA_SIZE 4096
++#define POLL_TIMEOUT 30000
++
++// sockaddr_un has hardcoded max len of sun_path
++#define MAX_WAYLAND_DISPLAY_NAME_LEN 108
++
++// Name of Wayland display provided by compositor
++char sWaylandDisplay[MAX_WAYLAND_DISPLAY_NAME_LEN];
++
++// Name of Wayland display provided by us
++char sWaylandProxy[MAX_WAYLAND_DISPLAY_NAME_LEN];
++
++bool sPrintInfo = false;
++
++void Info(const char* aFormat, ...) {
++ if (!sPrintInfo) {
++ return;
++ }
++ va_list args;
++ va_start(args, aFormat);
++ vfprintf(stderr, aFormat, args);
++ va_end(args);
++}
++
++void Warning(const char* aOperation, bool aPrintErrno = true) {
++ fprintf(stderr, "Wayland Proxy warning: %s : %s\n", aOperation,
++ aPrintErrno ? strerror(errno) : "");
++}
++
++void Error(const char* aOperation, bool aPrintErrno = true) {
++ fprintf(stderr, "Wayland Proxy error: %s : %s\n", aOperation,
++ aPrintErrno ? strerror(errno) : "");
++}
++
++void ErrorPlain(const char* aFormat, ...) {
++ va_list args;
++ va_start(args, aFormat);
++ vfprintf(stderr, aFormat, args);
++ va_end(args);
++}
++
++class WaylandMessage {
++ public:
++ bool Write(int aSocket);
++
++ bool Loaded() { return mLoaded && (mFds.size() || mData.size()); }
++ bool Failed() { return mFailed; }
++
++ explicit WaylandMessage(int aSocket) { Read(aSocket); }
++ ~WaylandMessage();
++
++ private:
++ bool Read(int aSocket);
++
++ private:
++ bool mLoaded = false;
++ bool mFailed = false;
++
++ std::vector<int> mFds;
++ std::vector<byte> mData;
++};
++
++class ProxiedConnection {
++ public:
++ bool Init(int aChildSocket);
++ bool IsConnected() { return mCompositorConnected; }
++
++ struct pollfd* AddToPollFd(struct pollfd* aPfds);
++ struct pollfd* LoadPollFd(struct pollfd* aPfds);
++
++ // Process this connection (send/receive data).
++ // Returns false if connection is broken and should be removed.
++ bool Process();
++
++ ~ProxiedConnection();
++
++ private:
++ // Try to connect to compositor. Returns false in case of fatal error.
++ bool ConnectToCompositor();
++
++ bool TransferOrQueue(
++ int aSourceSocket, int aSourcePollFlags, int aDestSocket,
++ std::vector<std::unique_ptr<WaylandMessage>>* aMessageQueue);
++ bool FlushQueue(int aDestSocket, int aDestPollFlags,
++ std::vector<std::unique_ptr<WaylandMessage>>& aMessageQueue);
++
++ // We don't have connected compositor yet. Try to connect
++ bool mCompositorConnected = false;
++
++ // We're disconnected from app or compositor. We will close this connection.
++ bool mFailed = false;
++
++ int mCompositorSocket = -1;
++ int mCompositorFlags = 0;
++
++ int mApplicationSocket = -1;
++ int mApplicationFlags = 0;
++
++ // Stored proxied data
++ std::vector<std::unique_ptr<WaylandMessage>> mToCompositorQueue;
++ std::vector<std::unique_ptr<WaylandMessage>> mToApplicationQueue;
++};
++
++WaylandMessage::~WaylandMessage() {
++ for (auto const fd : mFds) {
++ close(fd);
++ }
++}
++
++bool WaylandMessage::Read(int aSocket) {
++ // We don't expect WaylandMessage re-read
++ assert(!mLoaded && !mFailed);
++
++ mData.resize(MAX_DATA_SIZE);
++
++ struct msghdr msg = {0};
++ struct iovec iov = {mData.data(), mData.size()};
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ char cmsgdata[(CMSG_LEN(MAX_LIBWAY_FDS * sizeof(int32_t)))] = {0};
++ msg.msg_control = &cmsgdata;
++ msg.msg_controllen = sizeof(cmsgdata);
++
++ ssize_t ret = recvmsg(aSocket, &msg, MSG_CMSG_CLOEXEC | MSG_DONTWAIT);
++ if (msg.msg_flags & (MSG_CTRUNC | MSG_TRUNC)) {
++ Error("WaylandMessage::Read() data truncated, small buffer?");
++ mFailed = true;
++ return false;
++ }
++
++ if (ret < 1) {
++ switch (errno) {
++ case EAGAIN:
++ case EINTR:
++ // Neither loaded nor failed, we'll try again later
++ Info("WaylandMessage::Write() failed %s\n", strerror(errno));
++ return false;
++ default:
++ Error("WaylandMessage::Write() failed");
++ mFailed = true;
++ return false;
++ }
++ }
++
++ // Set correct data size
++ mData.resize(ret);
++
++ // Read cmsg
++ struct cmsghdr* header = CMSG_FIRSTHDR(&msg);
++ while (header) {
++ struct cmsghdr* next = CMSG_NXTHDR(&msg, header);
++ if (header->cmsg_level != SOL_SOCKET || header->cmsg_type != SCM_RIGHTS) {
++ header = next;
++ continue;
++ }
++
++ int* data = (int*)CMSG_DATA(header);
++ int filenum = (int)((header->cmsg_len - CMSG_LEN(0)) / sizeof(int));
++ for (int i = 0; i < filenum; i++) {
++#ifdef DEBUG
++ int flags = fcntl(data[i], F_GETFL, 0);
++ if (flags == -1 && errno == EBADF) {
++ Error("WaylandMessage::Read() invalid fd");
++ }
++#endif
++ mFds.push_back(data[i]);
++ }
++ header = next;
++ }
++
++ mLoaded = true;
++ return true;
++}
++
++bool WaylandMessage::Write(int aSocket) {
++ if (!mLoaded || mFailed) {
++ return false;
++ }
++
++ struct msghdr msg = {0};
++ struct iovec iov = {mData.data(), mData.size()};
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ int filenum = mFds.size();
++ if (filenum) {
++ if (filenum >= MAX_LIBWAY_FDS) {
++ Error("WaylandMessage::Write() too many files to send\n", false);
++ return false;
++ }
++#ifdef DEBUG
++ for (int i = 0; i < filenum; i++) {
++ int flags = fcntl(mFds[i], F_GETFL, 0);
++ if (flags == -1 && errno == EBADF) {
++ Error("WaylandMessage::Write() invalid fd\n");
++ }
++ }
++#endif
++ union {
++ char buf[CMSG_SPACE(sizeof(int) * MAX_LIBWAY_FDS)];
++ struct cmsghdr align;
++ } cmsgu;
++ memset(cmsgu.buf, 0, sizeof(cmsgu.buf));
++
++ msg.msg_control = cmsgu.buf;
++ msg.msg_controllen = sizeof(cmsgu.buf);
++ msg.msg_controllen = CMSG_SPACE(filenum * sizeof(int));
++
++ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
++ cmsg->cmsg_level = SOL_SOCKET;
++ cmsg->cmsg_type = SCM_RIGHTS;
++ cmsg->cmsg_len = CMSG_LEN(filenum * sizeof(int));
++ memcpy(CMSG_DATA(cmsg), mFds.data(), filenum * sizeof(int));
++ }
++
++ ssize_t ret = sendmsg(aSocket, &msg, MSG_CMSG_CLOEXEC | MSG_DONTWAIT);
++ if (ret < 1) {
++ switch (errno) {
++ case EAGAIN:
++ case EINTR:
++ // Neither loaded nor failed, we'll try again later
++ Info("WaylandMessage::Write() failed %s\n", strerror(errno));
++ return false;
++ default:
++ Warning("WaylandMessage::Write() failed");
++ mFailed = true;
++ return false;
++ }
++ }
++
++ if (ret != (ssize_t)mData.size()) {
++ Info("WaylandMessage::Write() failed to write all data! (%d vs. %d)\n", ret,
++ mData.size());
++ }
++ return true;
++}
++
++ProxiedConnection::~ProxiedConnection() {
++ if (mCompositorSocket != -1) {
++ close(mCompositorSocket);
++ }
++ if (mApplicationSocket != -1) {
++ close(mApplicationSocket);
++ }
++}
++
++bool ProxiedConnection::Init(int aApplicationSocket) {
++ mApplicationSocket = aApplicationSocket;
++ mCompositorSocket =
++ socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
++ if (mCompositorSocket == -1) {
++ Error("ProxiedConnection::Init() socket()");
++ }
++ return mApplicationSocket > 0 && mCompositorSocket > 0;
++}
++
++struct pollfd* ProxiedConnection::AddToPollFd(struct pollfd* aPfds) {
++ // Listen application's requests
++ aPfds->fd = mApplicationSocket;
++ aPfds->events = POLLIN;
++
++ // We're connected and we have data for appplication from compositor.
++ // Add POLLOUT to request write to app socket.
++ if (mCompositorConnected && mToApplicationQueue.size()) {
++ aPfds->events |= POLLOUT;
++ }
++ aPfds++;
++
++ aPfds->fd = mCompositorSocket;
++ // We're waiting for connection or we have data for compositor
++ if (!mCompositorConnected || mToCompositorQueue.size()) {
++ aPfds->events |= POLLOUT;
++ }
++ if (mCompositorConnected) {
++ aPfds->events = POLLIN;
++ }
++ aPfds++;
++
++ return aPfds;
++}
++
++struct pollfd* ProxiedConnection::LoadPollFd(struct pollfd* aPfds) {
++ if (aPfds->fd != mApplicationSocket) {
++ return aPfds;
++ }
++ mApplicationFlags = aPfds->revents;
++ aPfds++;
++ mCompositorFlags = aPfds->revents;
++ aPfds++;
++ return aPfds;
++}
++
++bool ProxiedConnection::ConnectToCompositor() {
++ if (!(mCompositorFlags & POLLOUT)) {
++ // Try again later
++ return true;
++ }
++
++ struct sockaddr_un addr = {};
++ addr.sun_family = AF_UNIX;
++ strcpy(addr.sun_path, sWaylandDisplay);
++
++ mCompositorConnected =
++ connect(mCompositorSocket, (const struct sockaddr*)&addr,
++ sizeof(struct sockaddr_un)) != -1;
++ if (!mCompositorConnected) {
++ switch (errno) {
++ case EAGAIN:
++ case EALREADY:
++ case ECONNREFUSED:
++ case EINPROGRESS:
++ case EINTR:
++ case EISCONN:
++ case ETIMEDOUT:
++ // We can recover from these errors and try again
++ Warning("ConnectToCompositor() try again");
++ return true;
++ default:
++ Error("ConnectToCompositor() connect()");
++ return false;
++ }
++ }
++ return true;
++}
++
++// Read data from aSourceSocket and try to twite them to aDestSocket.
++// If data write fails, append them to aMessageQueue.
++// Return
++bool ProxiedConnection::TransferOrQueue(
++ int aSourceSocket, int aSourcePollFlags, int aDestSocket,
++ std::vector<std::unique_ptr<WaylandMessage>>* aMessageQueue) {
++ // Don't read if we don't have any data ready
++ if (!(aSourcePollFlags & POLLIN)) {
++ return true;
++ }
++
++ while (1) {
++ int availableData = 0;
++ if (ioctl(aSourceSocket, FIONREAD, &availableData) < 0) {
++ // Broken connection, we're finished here
++ Warning("ProxiedConnection::TransferOrQueue() broken source socket %s\n");
++ return false;
++ }
++ if (availableData == 0) {
++ return true;
++ }
++
++ auto message = std::make_unique<WaylandMessage>(aSourceSocket);
++ if (message->Failed()) {
++ // Failed to read message due to error
++ return false;
++ }
++ if (!message->Loaded()) {
++ // Let's try again
++ return true;
++ }
++ if (!message->Write(aDestSocket)) {
++ if (message->Failed()) {
++ // Failed to write and we can't recover
++ return false;
++ }
++ aMessageQueue->push_back(std::move(message));
++ }
++ }
++}
++
++// Try to flush all data to aMessageQueue.
++bool ProxiedConnection::FlushQueue(
++ int aDestSocket, int aDestPollFlags,
++ std::vector<std::unique_ptr<WaylandMessage>>& aMessageQueue) {
++ // Can't write to destination yet
++ if (!(aDestPollFlags & POLLOUT)) {
++ return true;
++ }
++
++ while (aMessageQueue.size()) {
++ if (!aMessageQueue[0]->Write(aDestSocket)) {
++ return !aMessageQueue[0]->Failed();
++ }
++ aMessageQueue.erase(aMessageQueue.begin());
++ }
++ return true;
++}
++
++bool ProxiedConnection::Process() {
++ if (mFailed) {
++ return false;
++ }
++
++ // Check if appplication is still listening
++ if (mApplicationFlags & (POLLHUP | POLLERR)) {
++ return false;
++ }
++
++ // Check if compositor is still listening
++ if (mCompositorConnected) {
++ if (mCompositorFlags & (POLLHUP | POLLERR)) {
++ return false;
++ }
++ } else {
++ // Try to reconnect to compositor.
++ if (!ConnectToCompositor()) {
++ Info("Failed to connect to compositor\n");
++ return false;
++ }
++ // We're not connected yet but ConnectToCompositor() didn't return
++ // fatal error. Try again later.
++ if (!mCompositorConnected) {
++ return true;
++ }
++ }
++
++ mFailed =
++ !TransferOrQueue(mCompositorSocket, mCompositorFlags, mApplicationSocket,
++ &mToApplicationQueue) ||
++ !TransferOrQueue(mApplicationSocket, mApplicationFlags, mCompositorSocket,
++ &mToCompositorQueue) ||
++ !FlushQueue(mCompositorSocket, mCompositorFlags, mToCompositorQueue) ||
++ !FlushQueue(mApplicationSocket, mApplicationFlags, mToApplicationQueue);
++
++ return !mFailed;
++}
++
++bool WaylandProxy::SetupWaylandDisplays() {
++ char* waylandDisplay = getenv("WAYLAND_DISPLAY");
++ if (!waylandDisplay) {
++ Error("Init(), Missing Wayland display, WAYLAND_DISPLAY is empty.", false);
++ return false;
++ }
++
++ char* XDGRuntimeDir = getenv("XDG_RUNTIME_DIR");
++ if (!XDGRuntimeDir) {
++ Error("Init() Missing XDG_RUNTIME_DIR", false);
++ return false;
++ }
++
++ // WAYLAND_DISPLAY can be absolute path
++ if (waylandDisplay[0] == '/') {
++ if (strlen(sWaylandDisplay) >= MAX_WAYLAND_DISPLAY_NAME_LEN) {
++ Error("Init() WAYLAND_DISPLAY is too large.", false);
++ return false;
++ }
++ strcpy(sWaylandDisplay, waylandDisplay);
++ } else {
++ int ret = snprintf(sWaylandDisplay, MAX_WAYLAND_DISPLAY_NAME_LEN, "%s/%s",
++ XDGRuntimeDir, waylandDisplay);
++ if (ret < 0 || ret >= MAX_WAYLAND_DISPLAY_NAME_LEN) {
++ Error("Init() WAYLAND_DISPLAY/XDG_RUNTIME_DIR is too large.", false);
++ return false;
++ }
++ }
++ int ret = snprintf(sWaylandProxy, MAX_WAYLAND_DISPLAY_NAME_LEN,
++ "%s/wayland-proxy-%d", XDGRuntimeDir, getpid());
++ if (ret < 0 || ret >= MAX_WAYLAND_DISPLAY_NAME_LEN) {
++ Error("Init() WAYLAND_DISPLAY/XDG_RUNTIME_DIR is too large.", false);
++ return false;
++ }
++
++ Info("WaylandProxy Wayland '%s' proxy '%s'\n", sWaylandDisplay, sWaylandProxy);
++ return true;
++}
++
++bool WaylandProxy::StartProxyServer() {
++ mProxyServerSocket =
++ socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
++ if (mProxyServerSocket == -1) {
++ Error("StartProxyServer(): failed to create socket");
++ return false;
++ }
++
++ struct sockaddr_un serverName = {0};
++ serverName.sun_family = AF_UNIX;
++ strcpy(serverName.sun_path, sWaylandProxy);
++
++ if (bind(mProxyServerSocket, (struct sockaddr*)&serverName,
++ sizeof(serverName)) == -1) {
++ Error("StartProxyServer(): bind() error");
++ return false;
++ }
++ if (listen(mProxyServerSocket, 128) == -1) {
++ Error("StartProxyServer(): listen() error");
++ return false;
++ }
++
++ return true;
++}
++
++bool WaylandProxy::Init() {
++ if (!SetupWaylandDisplays()) {
++ return false;
++ }
++
++ if (!StartProxyServer()) {
++ return false;
++ }
++ return true;
++}
++
++void WaylandProxy::SetWaylandProxyDisplay() {
++ setenv("WAYLAND_DISPLAY", sWaylandProxy, true);
++}
++
++void WaylandProxy::SetWaylandDisplay() {
++ setenv("WAYLAND_DISPLAY", sWaylandDisplay, true);
++}
++
++bool WaylandProxy::IsChildAppTerminated() {
++ if (!mApplicationPID) {
++ return false;
++ }
++ int status = 0;
++ int ret = waitpid(mApplicationPID, &status, WNOHANG | WUNTRACED | WCONTINUED);
++ if (ret == 0) {
++ return false;
++ }
++ if (ret == mApplicationPID) {
++ // Child application is terminated, so quit too.
++ return true;
++ }
++ bool terminate = (errno == ECHILD);
++ Error("IsChildAppTerminated: waitpid() error");
++ return terminate;
++}
++
++bool WaylandProxy::PollConnections() {
++ int nfds_max = mConnections.size() * 2 + 1;
++
++ struct pollfd pollfds[nfds_max];
++ struct pollfd* addedPollfd = pollfds;
++
++ for (auto const& connection : mConnections) {
++ addedPollfd = connection->AddToPollFd(addedPollfd);
++ }
++ int nfds = (addedPollfd - pollfds);
++
++ // If all connections are attached to compositor, add another one
++ // for new potential connection from application.
++ bool addNewConnection = mConnections.empty() ||
++ mConnections.back()->IsConnected();
++ if (addNewConnection) {
++ addedPollfd->fd = mProxyServerSocket;
++ addedPollfd->events = POLLIN;
++ nfds++;
++ }
++ assert(addedPollfd < pollfds + nfds_max);
++
++ while (1) {
++ int ret = poll(pollfds, nfds, POLL_TIMEOUT);
++ if (ret == 0) {
++ // No change on fds
++ continue;
++ } else if (ret > 0) {
++ // We have FD to read
++ break;
++ } else if (ret == -1) {
++ switch (errno) {
++ case EINTR:
++ case EAGAIN:
++ if (IsChildAppTerminated()) {
++ return false;
++ }
++ continue;
++ default:
++ Error("Run: poll() error");
++ return false;
++ }
++ }
++ }
++
++ struct pollfd* loadedPollfd = pollfds;
++ for (auto const& connection : mConnections) {
++ loadedPollfd = connection->LoadPollFd(loadedPollfd);
++ }
++
++ assert(loadedPollfd == addedPollfd);
++ assert(loadedPollfd < pollfds + nfds_max);
++
++ // Create a new connection if there's a new client waiting
++ if (addNewConnection && (loadedPollfd->revents & POLLIN)) {
++ Info("WaylandProxy: new child connection\n");
++ int applicationSocket = accept4(loadedPollfd->fd, nullptr, nullptr,
++ SOCK_NONBLOCK | SOCK_CLOEXEC);
++ if (applicationSocket == -1) {
++ switch (errno) {
++ case EAGAIN:
++ case EINTR:
++ // Try again later
++ break;
++ default:
++ Error("Faild to accept connection from application");
++ return false;
++ }
++ } else {
++ auto connection = std::make_unique<ProxiedConnection>();
++ if (connection->Init(applicationSocket)) {
++ mConnections.push_back(std::move(connection));
++ }
++ }
++ }
++
++ return true;
++}
++
++bool WaylandProxy::ProcessConnections() {
++ std::vector<std::unique_ptr<ProxiedConnection>>::iterator connection;
++ for (connection = mConnections.begin(); connection != mConnections.end();) {
++ if (!(*connection)->Process()) {
++ Info("WaylandProxy: remove connection\n");
++ connection = mConnections.erase(connection);
++ if (!mConnections.size()) {
++ // We removed last connection - quit.
++ Info("WaylandProxy: removed last connection, quit\n");
++ return false;
++ }
++ } else {
++ connection++;
++ }
++ }
++ return true;
++}
++
++void WaylandProxy::Run() {
++ while (!IsChildAppTerminated() && PollConnections() && ProcessConnections())
++ ;
++}
++
++WaylandProxy::~WaylandProxy() {
++ Info("WaylandProxy terminated\n");
++ if (mThreadRunning) {
++ Info("WaylandProxy thread is still running, terminating.\n");
++ pthread_cancel(mThread);
++ pthread_join(mThread, nullptr);
++ }
++ unlink(sWaylandProxy);
++ if (mProxyServerSocket != -1) {
++ close(mProxyServerSocket);
++ }
++ SetWaylandDisplay();
++}
++
++void* WaylandProxy::RunProxyThread(WaylandProxy* aProxy) {
++#ifdef __linux__
++ pthread_setname_np(pthread_self(), "WaylandProxy");
++#endif
++ aProxy->Run();
++ aProxy->mThreadRunning = false;
++ Info("WaylandProxy thread exited\n");
++ return nullptr;
++}
++
++std::unique_ptr<WaylandProxy> WaylandProxy::Create() {
++ auto proxy = std::make_unique<WaylandProxy>();
++ if (!proxy->Init()) {
++ return nullptr;
++ }
++
++ Info("WaylandProxyCreated, display %s\n", sWaylandProxy);
++ return proxy;
++}
++
++bool WaylandProxy::RunChildApplication(char* argv[]) {
++ if (!argv[0]) {
++ Error("WaylandProxy::RunChildApplication: missing application to run", false);
++ return false;
++ }
++
++ mApplicationPID = fork();
++ if (mApplicationPID == -1) {
++ Error("WaylandProxy::RunChildApplication: fork() error");
++ return false;
++ }
++ if (mApplicationPID == 0) {
++ SetWaylandProxyDisplay();
++ if (execv(argv[0], argv) == -1) {
++ ErrorPlain("WaylandProxy::RunChildApplication: failed to run %s error %s\n", argv[0], strerror(errno));
++ exit(1);
++ }
++ }
++
++ Run();
++ return true;
++}
++
++bool WaylandProxy::RunThread() {
++ pthread_attr_t attr;
++ if (pthread_attr_init(&attr) != 0) {
++ return false;
++ }
++
++ sched_param param;
++ if (pthread_attr_getschedparam(&attr, &param) == 0) {
++ param.sched_priority = sched_get_priority_min(SCHED_RR);
++ pthread_attr_setschedparam(&attr, &param);
++ }
++
++ SetWaylandProxyDisplay();
++
++ mThreadRunning = pthread_create(&mThread, nullptr, (void* (*)(void*))RunProxyThread, this) == 0;
++ if (!mThreadRunning) {
++ // If we failed to run proxy thread, set WAYLAND_DISPLAY back.
++ SetWaylandDisplay();
++ }
++
++ pthread_attr_destroy(&attr);
++ return mThreadRunning;
++}
++
++void WaylandProxy::SetVerbose(bool aVerbose) { sPrintInfo = aVerbose; }
+diff --color --unified --recursive --text --new-file firefox-121.0.orig/third_party/wayland-proxy/wayland-proxy.h firefox-121.0.new/third_party/wayland-proxy/wayland-proxy.h
+--- firefox-121.0.orig/third_party/wayland-proxy/wayland-proxy.h 1970-01-01 01:00:00.000000000 +0100
++++ firefox-121.0.new/third_party/wayland-proxy/wayland-proxy.h 2024-01-09 02:23:05.161484173 +0100
+@@ -0,0 +1,55 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef _wayland_proxy_h_
++#define _wayland_proxy_h_
++
++#include <poll.h>
++#include <vector>
++#include <fcntl.h>
++#include <atomic>
++#include <memory>
++
++typedef unsigned char byte;
++
++class ProxiedConnection;
++
++class WaylandProxy {
++ public:
++
++ static std::unique_ptr<WaylandProxy> Create();
++
++ bool RunChildApplication(char* argv[]);
++ bool RunThread();
++
++ void SetWaylandDisplay();
++ static void SetVerbose(bool aVerbose);
++
++ ~WaylandProxy();
++
++ private:
++ bool Init();
++ void Run();
++
++ void SetWaylandProxyDisplay();
++ static void* RunProxyThread(WaylandProxy* aProxy);
++
++ bool SetupWaylandDisplays();
++ bool StartProxyServer();
++ bool IsChildAppTerminated();
++
++ bool PollConnections();
++ bool ProcessConnections();
++
++ private:
++ // List of all Compositor <-> Application connections
++ std::vector<std::unique_ptr<ProxiedConnection>> mConnections;
++ int mProxyServerSocket = -1;
++ pid_t mApplicationPID = 0;
++ std::atomic<bool> mThreadRunning = false;
++ pthread_t mThread;
++};
++
++#endif // _wayland_proxy_h_
+diff --color --unified --recursive --text --new-file firefox-121.0.orig/widget/gtk/moz.build firefox-121.0.new/widget/gtk/moz.build
+--- firefox-121.0.orig/widget/gtk/moz.build 2024-01-09 02:21:53.366076929 +0100
++++ firefox-121.0.new/widget/gtk/moz.build 2024-01-09 02:23:05.162484164 +0100
+@@ -23,7 +23,11 @@
+ DIRS += ["mozgtk"]
+
+ if CONFIG["MOZ_WAYLAND"]:
+- DIRS += ["wayland", "mozwayland"]
++ DIRS += [
++ "wayland",
++ "mozwayland",
++ "../../third_party/wayland-proxy"
++ ]
+
+ if CONFIG["MOZ_ENABLE_VAAPI"]:
+ DIRS += ["vaapitest"]
diff --git a/0002-wayland-proxy.patch b/0002-wayland-proxy.patch
new file mode 100644
index 000000000000..c76bc21924e0
--- /dev/null
+++ b/0002-wayland-proxy.patch
@@ -0,0 +1,88 @@
+diff --color --unified --recursive --text firefox-121.0.orig/toolkit/xre/nsAppRunner.cpp firefox-121.0.new/toolkit/xre/nsAppRunner.cpp
+--- firefox-121.0.orig/toolkit/xre/nsAppRunner.cpp 2024-01-09 02:00:34.503779191 +0100
++++ firefox-121.0.new/toolkit/xre/nsAppRunner.cpp 2024-01-09 02:01:28.333190186 +0100
+@@ -340,13 +340,24 @@
+ # ifdef MOZ_WAYLAND
+ # include <gdk/gdkwayland.h>
+ # include "mozilla/widget/nsWaylandDisplay.h"
++# include "wayland-proxy.h"
+ # endif
+ # ifdef MOZ_X11
+ # include <gdk/gdkx.h>
+ # endif /* MOZ_X11 */
+ #endif
++
++#if defined(MOZ_WAYLAND)
++std::unique_ptr<WaylandProxy> gWaylandProxy;
++#endif
++
+ #include "BinaryPath.h"
+
++#ifdef MOZ_LOGGING
++# include "mozilla/Logging.h"
++extern mozilla::LazyLogModule gWidgetWaylandLog;
++#endif /* MOZ_LOGGING */
++
+ #ifdef FUZZING
+ # include "FuzzerRunner.h"
+
+@@ -2788,6 +2799,9 @@
+ gRemoteService = nullptr;
+ }
+ #endif
++#if defined(MOZ_WAYLAND)
++ gWaylandProxy = nullptr;
++#endif
+ return LaunchChild(false, true);
+ }
+ } else {
+@@ -2902,6 +2916,9 @@
+ gRemoteService = nullptr;
+ }
+ #endif
++#if defined(MOZ_WAYLAND)
++ gWaylandProxy = nullptr;
++#endif
+ return LaunchChild(false, true);
+ }
+
+@@ -4707,6 +4724,23 @@
+ const char* display_name = nullptr;
+ bool saveDisplayArg = false;
+
++ bool waylandEnabled = IsWaylandEnabled();
++# ifdef MOZ_WAYLAND
++ auto* proxyEnv = getenv("MOZ_DISABLE_WAYLAND_PROXY");
++ bool disableWaylandProxy = proxyEnv && *proxyEnv;
++ if (!disableWaylandProxy && XRE_IsParentProcess() && waylandEnabled) {
++# ifdef MOZ_LOGGING
++ if (MOZ_LOG_TEST(gWidgetWaylandLog, mozilla::LogLevel::Debug)) {
++ WaylandProxy::SetVerbose(true);
++ }
++# endif
++ gWaylandProxy = WaylandProxy::Create();
++ if (gWaylandProxy) {
++ gWaylandProxy->RunThread();
++ }
++ }
++# endif
++
+ // display_name is owned by gdk.
+ display_name = gdk_get_display_arg_name();
+ // if --display argument is given make sure it's
+@@ -4716,7 +4750,6 @@
+ saveDisplayArg = true;
+ }
+
+- bool waylandEnabled = IsWaylandEnabled();
+ // On Wayland disabled builds read X11 DISPLAY env exclusively
+ // and don't care about different displays.
+ if (!waylandEnabled && !display_name) {
+@@ -5918,6 +5951,7 @@
+ if (!gfxPlatform::IsHeadless()) {
+ # ifdef MOZ_WAYLAND
+ WaylandDisplayRelease();
++ gWaylandProxy = nullptr;
+ # endif
+ }
+ #endif
diff --git a/0001-enable-vaapi.patch b/0003-enable-vaapi.patch
index 25b2b78aa45d..25b2b78aa45d 100644
--- a/0001-enable-vaapi.patch
+++ b/0003-enable-vaapi.patch
diff --git a/0002-remove-nvidia-blocklist.patch b/0004-remove-nvidia-blocklist.patch
index 4a8f1160e16c..4a8f1160e16c 100644
--- a/0002-remove-nvidia-blocklist.patch
+++ b/0004-remove-nvidia-blocklist.patch
diff --git a/PKGBUILD b/PKGBUILD
index c5557398585f..17e6dcfa7617 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -6,7 +6,7 @@
pkgname=firefox-vaapi
_pkgname=firefox
pkgver=121.0
-pkgrel=1
+pkgrel=2
pkgdesc="Standalone web browser from mozilla.org (with VA-API patches)"
url="https://www.mozilla.org/firefox/"
arch=(x86_64)
@@ -71,8 +71,10 @@ source=(
https://archive.mozilla.org/pub/firefox/releases/$pkgver/source/firefox-$pkgver.source.tar.xz{,.asc}
firefox.desktop
identity-icons-brand.svg
- 0001-enable-vaapi.patch
- 0002-remove-nvidia-blocklist.patch
+ 0001-wayland-proxy.patch
+ 0002-wayland-proxy.patch
+ 0003-enable-vaapi.patch
+ 0004-remove-nvidia-blocklist.patch
)
validpgpkeys=(
# Mozilla Software Releases <release@mozilla.com>
@@ -83,12 +85,16 @@ sha256sums=('edc7a5159d23ff2a23e22bf5abe22231658cee2902b93b5889ee73958aa06aa4'
'SKIP'
'1f241fdc619f92a914c75aece7c7c717401d7467c9a306458e106b05f34e5044'
'a9b8b4a0a1f4a7b4af77d5fc70c2686d624038909263c795ecc81e0aec7711e9'
+ 'bbec9e3ed1fe1372f587383e8ca86bb28e4dd90874dc146450e6ecdc8d30f387'
+ '2b439551262f6b1f341ff8156ad447b5196d5d5d1bf1d8f3a9f9910895d6c1de'
'00c449422246283cd7e0bdc65d216fce4a42f755ad881106a08fb7d97eab1679'
'75d3c213f3717cfc3f72acd4e3b6d029d373916f9ff9a1e8a3e2d7b0958760ed')
b2sums=('80905caeb208ef5dce7b62e248c86598ca786eb7032e114ad5d10812623bfceb688832f646dfbe220ef2fcecacf11cefae2afb0f1cdc0f7952647b71c58c9602'
'SKIP'
'd07557840097dd48a60c51cc5111950781e1c6ce255557693bd11306c7a9258b2a82548329762148f117b2295145f9e66e0483a18e2fe09c5afcffed2e4b8628'
'63a8dd9d8910f9efb353bed452d8b4b2a2da435857ccee083fc0c557f8c4c1339ca593b463db320f70387a1b63f1a79e709e9d12c69520993e26d85a3d742e34'
+ '4daf6c7d670f94d782408cd6f7fa7c6a96e109d6d368f5e41b0353e6f81f9a12f0f32b72efb734814652df42e63941312edc54446e874ce84e82862fbdee8a33'
+ '896de88f76d37ad35d34084706c70170883e8b27630714ce326e00e327257c19e5ebee84cec45f3ab5db66becb6a7b5fb925f3b37b17f5b636d3517da07b914d'
'f84752e04c7e69b69158b9514a5227a2b71b60ccbbe5acb437d9830bfa2e725fe6784e1603890722a114abda424f9cafc007e9934310f21483b6540bc19da905'
'87ecd8a3891a9a171173a97cf3b2b5f978be9ec876bb257d9f5e037f21dc5bd91167eabeb1c3cc181260b82cb2774c7b38ad73e1d807cc49b6d95617e2fb5d55')
@@ -108,13 +114,20 @@ prepare() {
mkdir mozbuild
cd firefox-$pkgver
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1743144
+ # https://www.phoronix.com/news/Wayland-Proxy-Firefox
+ # https://mastransky.wordpress.com/2023/12/22/wayland-proxy-load-balancer/
+ # https://src.fedoraproject.org/rpms/firefox/c/5d26feb54833974e37fbf31d07d2ddf59538a157?branch=rawhide
+ patch -Np1 -i ../0001-wayland-proxy.patch
+ patch -Np1 -i ../0002-wayland-proxy.patch
+
# https://bugzilla.mozilla.org/show_bug.cgi?id=1809068
# https://bbs.archlinux.org/viewtopic.php?id=281398
# https://src.fedoraproject.org/rpms/firefox/blob/rawhide/f/firefox-enable-vaapi.patch
- patch -Np1 -i ../0001-enable-vaapi.patch
+ patch -Np1 -i ../0003-enable-vaapi.patch
# Disable NVIDIA blocklists, to make it function with libva-nvidia-driver-git AUR package
- patch -Np1 -i ../0002-remove-nvidia-blocklist.patch
+ patch -Np1 -i ../0004-remove-nvidia-blocklist.patch
echo -n "$_google_api_key" >google-api-key
echo -n "$_mozilla_api_key" >mozilla-api-key
@@ -163,10 +176,11 @@ END
build() {
cd firefox-$pkgver
- export MOZ_NOSPAM=1
+ export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=pip
export MOZBUILD_STATE_PATH="$srcdir/mozbuild"
+ export MOZ_BUILD_DATE="$(date -u${SOURCE_DATE_EPOCH:+d @$SOURCE_DATE_EPOCH} +%Y%m%d%H%M%S)"
export MOZ_ENABLE_FULL_SYMBOLS=1
- export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=pip
+ export MOZ_NOSPAM=1
# malloc_usable_size is used in various parts of the codebase
CFLAGS="${CFLAGS/_FORTIFY_SOURCE=3/_FORTIFY_SOURCE=2}"