diff options
author | Ewout van Mansom | 2024-01-09 20:33:32 +0100 |
---|---|---|
committer | Ewout van Mansom | 2024-01-09 20:33:32 +0100 |
commit | 06412def98aff916f9977f2f6bd9f7fdeb114eb8 (patch) | |
tree | ce2eee346c658ffb34d0bafab2bf5ed31fb0de70 | |
parent | a595f56b6f9815773f7b00dfe4ae633b8d132813 (diff) | |
download | aur-06412def98aff916f9977f2f6bd9f7fdeb114eb8.tar.gz |
add wayland proxy
-rw-r--r-- | .SRCINFO | 12 | ||||
-rw-r--r-- | 0001-wayland-proxy.patch | 841 | ||||
-rw-r--r-- | 0002-wayland-proxy.patch | 88 | ||||
-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-- | PKGBUILD | 28 |
6 files changed, 959 insertions, 10 deletions
@@ -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, ¶m) == 0) { ++ param.sched_priority = sched_get_priority_min(SCHED_RR); ++ pthread_attr_setschedparam(&attr, ¶m); ++ } ++ ++ 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 @@ -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}" |