boo/lib/x11/ApplicationUnix.cpp
Lioncash baff71cdc3 General: Tidy up includes
Alphabetizes includes and resolves quite a few instances of indirect
inclusions, making the requirements of several interfaces explicit. This
also trims out includes that aren't actually necessary (likely due to
changes in the API over time).
2019-08-19 21:02:56 -04:00

148 lines
4.9 KiB
C++

/* Meta-implementation for dynamically-constructing user's preferred
* platform interface
*/
#define APPLICATION_UNIX_CPP
#include <cstdint>
#include <cstdlib>
#include "boo/IApplication.hpp"
#include <dbus/dbus.h>
#include <logvisor/logvisor.hpp>
#include <unistd.h>
namespace boo {
static logvisor::Module Log("boo::ApplicationUnix");
IApplication* APP = nullptr;
class ScreenSaverInhibitor {
DBusConnection* m_dbus;
uint64_t m_wid;
DBusPendingCall* m_pending = nullptr;
uint32_t m_cookie = UINT32_MAX;
static void Callback(DBusPendingCall* pending, ScreenSaverInhibitor* user_data) {
user_data->HandleReply();
}
void HandleReply() {
DBusMessage* msg = nullptr;
DBusError err = DBUS_ERROR_INIT;
if ((msg = dbus_pending_call_steal_reply(m_pending)) &&
dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &m_cookie, DBUS_TYPE_INVALID)) {
Log.report(logvisor::Info, fmt("Screen saver inhibited"));
} else {
/* Fallback to xdg-screensaver */
dbus_error_free(&err);
Log.report(logvisor::Info, fmt("Falling back to xdg-screensaver inhibit"));
if (!fork()) {
execlp("xdg-screensaver", "xdg-screensaver", "suspend", fmt::format(fmt("0x{:X}"), m_wid).c_str(), nullptr);
exit(1);
}
}
if (msg)
dbus_message_unref(msg);
dbus_pending_call_unref(m_pending);
m_pending = nullptr;
}
public:
ScreenSaverInhibitor(DBusConnection* dbus, uint64_t wid) : m_dbus(dbus), m_wid(wid) {
#ifndef BOO_MSAN
DBusMessage* msg =
dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver",
"org.freedesktop.ScreenSaver", "Inhibit");
const char* appName = APP->getUniqueName().data();
const char* reason = "Game Active";
dbus_message_append_args(msg, DBUS_TYPE_STRING, &appName, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
dbus_connection_send_with_reply(m_dbus, msg, &m_pending, -1);
dbus_pending_call_set_notify(m_pending, DBusPendingCallNotifyFunction(Callback), this, nullptr);
dbus_message_unref(msg);
dbus_connection_flush(m_dbus);
#endif
}
~ScreenSaverInhibitor() {
#ifndef BOO_MSAN
if (m_cookie != UINT32_MAX) {
DBusMessage* msg =
dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver",
"org.freedesktop.ScreenSaver", "UnInhibit");
dbus_message_append_args(msg, DBUS_TYPE_UINT32, &m_cookie, DBUS_TYPE_INVALID);
dbus_connection_send(m_dbus, msg, nullptr);
dbus_message_unref(msg);
dbus_connection_flush(m_dbus);
}
#endif
}
};
}
#include "ApplicationXlib.hpp"
#include "ApplicationWayland.hpp"
#include <memory>
#include <cstdio>
/* No icon by default */
extern "C" const uint8_t MAINICON_NETWM[] __attribute__((weak)) = {};
extern "C" const size_t MAINICON_NETWM_SZ __attribute__((weak)) = 0;
DBusConnection* RegisterDBus(const char* appName, bool& isFirst) {
isFirst = true;
DBusError err = {};
dbus_error_init(&err);
/* connect to the bus and check for errors */
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {
fmt::print(stderr, fmt("DBus Connection Error ({})\n"), err.message);
dbus_error_free(&err);
}
if (conn == nullptr)
return nullptr;
/* request our name on the bus and check for errors */
int ret = dbus_bus_request_name(conn, fmt::format(fmt("boo.{}.unique"), appName).c_str(),
DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
if (dbus_error_is_set(&err)) {
fmt::print(stderr, fmt("DBus Name Error ({})\n"), err.message);
dbus_error_free(&err);
dbus_connection_close(conn);
return nullptr;
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
isFirst = false;
return conn;
}
namespace boo {
int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, std::string_view uniqueName,
std::string_view friendlyName, std::string_view pname, const std::vector<std::string>& args,
std::string_view gfxApi, uint32_t samples, uint32_t anisotropy, bool deepColor,
bool singleInstance) {
std::string thrName = std::string(friendlyName) + " Main";
logvisor::RegisterThreadName(thrName.c_str());
if (APP)
return 1;
if (platform == IApplication::EPlatformType::Wayland)
APP = new ApplicationWayland(cb, uniqueName, friendlyName, pname, args, gfxApi, samples, anisotropy, deepColor,
singleInstance);
else if (platform == IApplication::EPlatformType::Xlib || platform == IApplication::EPlatformType::Auto)
APP = new ApplicationXlib(cb, uniqueName, friendlyName, pname, args, gfxApi, samples, anisotropy, deepColor,
singleInstance);
else
return 1;
int ret = APP->run();
delete APP;
APP = nullptr;
return ret;
}
} // namespace boo