249 lines
6.4 KiB
C++
249 lines
6.4 KiB
C++
// Copyright (C) 2015 Jérôme Leclercq
|
|
// This file is part of the "Nazara Engine - Utility module"
|
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
|
|
|
#include <Nazara/Utility/X11/Display.hpp>
|
|
#include <Nazara/Core/Error.hpp>
|
|
#include <Nazara/Core/Log.hpp>
|
|
#include <Nazara/Core/String.hpp>
|
|
#include <xcb/xcb_keysyms.h>
|
|
#include <map>
|
|
#include <Nazara/Utility/Debug.hpp>
|
|
|
|
namespace Nz
|
|
{
|
|
namespace
|
|
{
|
|
// The shared display and its reference counter
|
|
xcb_connection_t* sharedConnection = nullptr;
|
|
int screen_nbr = 0;
|
|
unsigned int referenceCountConnection = 0;
|
|
|
|
xcb_key_symbols_t* sharedkeySymbol = nullptr;
|
|
unsigned int referenceCountKeySymbol = 0;
|
|
|
|
xcb_ewmh_connection_t* sharedEwmhConnection = nullptr;
|
|
unsigned int referenceCountEwmhConnection = 0;
|
|
|
|
using AtomMap = std::map<String, xcb_atom_t>;
|
|
AtomMap atoms;
|
|
}
|
|
|
|
bool X11::CheckCookie(xcb_connection_t* connection, xcb_void_cookie_t cookie)
|
|
{
|
|
ScopedXCB<xcb_generic_error_t> error(xcb_request_check(
|
|
connection,
|
|
cookie
|
|
));
|
|
|
|
if (error)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
void X11::CloseConnection(xcb_connection_t* connection)
|
|
{
|
|
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
|
--referenceCountConnection;
|
|
}
|
|
|
|
void X11::CloseEWMHConnection(xcb_ewmh_connection_t* ewmh_connection)
|
|
{
|
|
NazaraAssert(ewmh_connection == sharedEwmhConnection, "The model is meant for one connection to X11 server");
|
|
--referenceCountEwmhConnection;
|
|
}
|
|
|
|
xcb_atom_t X11::GetAtom(const String& name, bool onlyIfExists)
|
|
{
|
|
AtomMap::const_iterator iter = atoms.find(name);
|
|
|
|
if (iter != atoms.end())
|
|
return iter->second;
|
|
|
|
ScopedXCB<xcb_generic_error_t> error(nullptr);
|
|
|
|
xcb_connection_t* connection = OpenConnection();
|
|
|
|
ScopedXCB<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(
|
|
connection,
|
|
xcb_intern_atom(
|
|
connection,
|
|
onlyIfExists,
|
|
name.GetSize(),
|
|
name.GetConstBuffer()
|
|
),
|
|
&error
|
|
));
|
|
|
|
CloseConnection(connection);
|
|
|
|
if (error || !reply)
|
|
{
|
|
NazaraError("Failed to get " + name + " atom.");
|
|
return XCB_ATOM_NONE;
|
|
}
|
|
|
|
atoms[name] = reply->atom;
|
|
|
|
return reply->atom;
|
|
}
|
|
|
|
bool X11::Initialize()
|
|
{
|
|
if (IsInitialized())
|
|
{
|
|
s_moduleReferenceCounter++;
|
|
return true; // Déjà initialisé
|
|
}
|
|
|
|
s_moduleReferenceCounter++;
|
|
|
|
NazaraAssert(referenceCountConnection == 0, "Initialize should be called before anything");
|
|
NazaraAssert(referenceCountKeySymbol == 0, "Initialize should be called before anything");
|
|
NazaraAssert(referenceCountEwmhConnection == 0, "Initialize should be called before anything");
|
|
|
|
{
|
|
sharedConnection = xcb_connect(nullptr, &screen_nbr);
|
|
|
|
// Opening display failed: The best we can do at the moment is to output a meaningful error message
|
|
// and cause an abnormal program termination
|
|
if (!sharedConnection || xcb_connection_has_error(sharedConnection))
|
|
{
|
|
NazaraError("Failed to open xcb connection");
|
|
std::abort();
|
|
}
|
|
|
|
OpenConnection();
|
|
}
|
|
|
|
{
|
|
sharedkeySymbol = xcb_key_symbols_alloc(sharedConnection);
|
|
|
|
XCBKeySymbolsAlloc(sharedConnection);
|
|
}
|
|
|
|
{
|
|
sharedEwmhConnection = new xcb_ewmh_connection_t;
|
|
xcb_intern_atom_cookie_t* ewmh_cookie = xcb_ewmh_init_atoms(sharedConnection, sharedEwmhConnection);
|
|
|
|
if(!xcb_ewmh_init_atoms_replies(sharedEwmhConnection, ewmh_cookie, nullptr))
|
|
{
|
|
NazaraError("Could not initialize EWMH Connection");
|
|
sharedEwmhConnection = nullptr;
|
|
}
|
|
|
|
OpenEWMHConnection(sharedConnection);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool X11::IsInitialized()
|
|
{
|
|
return s_moduleReferenceCounter != 0;
|
|
}
|
|
|
|
xcb_key_symbols_t* X11::XCBKeySymbolsAlloc(xcb_connection_t* connection)
|
|
{
|
|
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
|
|
|
++referenceCountKeySymbol;
|
|
return sharedkeySymbol;
|
|
}
|
|
|
|
void X11::XCBKeySymbolsFree(xcb_key_symbols_t* keySymbols)
|
|
{
|
|
NazaraAssert(keySymbols == sharedkeySymbol, "The model is meant for one connection to X11 server");
|
|
|
|
--referenceCountKeySymbol;
|
|
}
|
|
|
|
xcb_connection_t* X11::OpenConnection()
|
|
{
|
|
++referenceCountConnection;
|
|
return sharedConnection;
|
|
}
|
|
|
|
xcb_ewmh_connection_t* X11::OpenEWMHConnection(xcb_connection_t* connection)
|
|
{
|
|
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
|
|
|
++referenceCountEwmhConnection;
|
|
return sharedEwmhConnection;
|
|
}
|
|
|
|
void X11::Uninitialize()
|
|
{
|
|
if (s_moduleReferenceCounter != 1)
|
|
{
|
|
// Le module est soit encore utilisé, soit pas initialisé
|
|
if (s_moduleReferenceCounter > 1)
|
|
s_moduleReferenceCounter--;
|
|
|
|
return;
|
|
}
|
|
|
|
s_moduleReferenceCounter = 0;
|
|
|
|
{
|
|
NazaraAssert(referenceCountEwmhConnection == 1, "Uninitialize should be called after anything or a close is missing");
|
|
CloseEWMHConnection(sharedEwmhConnection);
|
|
|
|
xcb_ewmh_connection_wipe(sharedEwmhConnection);
|
|
delete sharedEwmhConnection;
|
|
}
|
|
|
|
{
|
|
NazaraAssert(referenceCountKeySymbol == 1, "Uninitialize should be called after anything or a free is missing");
|
|
XCBKeySymbolsFree(sharedkeySymbol);
|
|
|
|
xcb_key_symbols_free(sharedkeySymbol);
|
|
}
|
|
|
|
{
|
|
NazaraAssert(referenceCountConnection == 1, "Uninitialize should be called after anything or a close is missing");
|
|
CloseConnection(sharedConnection);
|
|
|
|
xcb_disconnect(sharedConnection);
|
|
}
|
|
}
|
|
|
|
xcb_window_t X11::XCBDefaultRootWindow(xcb_connection_t* connection)
|
|
{
|
|
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
|
xcb_screen_t* screen = XCBDefaultScreen(connection);
|
|
if (screen)
|
|
return screen->root;
|
|
return XCB_NONE;
|
|
}
|
|
|
|
xcb_screen_t* X11::XCBDefaultScreen(xcb_connection_t* connection)
|
|
{
|
|
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
|
return XCBScreenOfDisplay(connection, screen_nbr);
|
|
}
|
|
|
|
int X11::XCBScreen(xcb_connection_t* connection)
|
|
{
|
|
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
|
return screen_nbr;
|
|
}
|
|
|
|
xcb_screen_t* X11::XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr)
|
|
{
|
|
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
|
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
|
|
|
|
for (; iter.rem; --screen_nbr, xcb_screen_next (&iter))
|
|
{
|
|
if (screen_nbr == 0)
|
|
return iter.data;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
unsigned int X11::s_moduleReferenceCounter = 0;
|
|
}
|