299 lines
8.5 KiB
C++
299 lines
8.5 KiB
C++
#include "XcbInterface.h"
|
|
|
|
#include "DesktopManager.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xlib-xcb.h> /* for XGetXCBConnection, link with libX11-xcb */
|
|
#include <xkbcommon/xkbcommon-x11.h>
|
|
#include <xcb/xcb.h>
|
|
|
|
// Header is c-like, uses explicit as a var
|
|
#define explicit explicit_
|
|
#include <xcb/xkb.h>
|
|
#undef explicit
|
|
|
|
#include "PaintEvent.h"
|
|
#include "ResizeEvent.h"
|
|
#include "Screen.h"
|
|
#include "XcbScreen.h"
|
|
#include "Color.h"
|
|
#include "Widget.h"
|
|
#include "UiEvent.h"
|
|
#include "XcbKeyboard.h"
|
|
#include "XcbWindow.h"
|
|
|
|
#include "XcbEventInterface.h"
|
|
#include "XcbGlInterface.h"
|
|
#include "XcbExtensionInterface.h"
|
|
|
|
#include "FileLogger.h"
|
|
#include "FontsManager.h"
|
|
|
|
#include <iostream>
|
|
|
|
namespace {
|
|
typedef union {
|
|
struct {
|
|
uint8_t response_type;
|
|
uint8_t xkbType;
|
|
uint16_t sequence;
|
|
xcb_timestamp_t time;
|
|
uint8_t deviceID;
|
|
} any;
|
|
xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify;
|
|
xcb_xkb_map_notify_event_t map_notify;
|
|
xcb_xkb_state_notify_event_t state_notify;
|
|
} _xkb_event;
|
|
}
|
|
|
|
XcbInterface::XcbInterface(DesktopManager* desktopManager, std::unique_ptr<FontsManager> fontsManager, bool useHardware)
|
|
: AbstractUIInterface(desktopManager, std::move(fontsManager), useHardware),
|
|
mEventInterface(XcbEventInterface::Create()),
|
|
mExtensionInterface(std::make_unique<XcbExtensionInterface>())
|
|
{
|
|
|
|
}
|
|
|
|
XcbInterface::~XcbInterface()
|
|
{
|
|
shutDown();
|
|
}
|
|
|
|
void XcbInterface::initialize()
|
|
{
|
|
connect();
|
|
updateScreen();
|
|
createGraphicsContext();
|
|
if (mUseHardwareRendering)
|
|
{
|
|
initializeHardwareRendering();
|
|
}
|
|
|
|
mExtensionInterface->initialize(mConnection);
|
|
mDesktopManager->setKeyboard(XcbKeyboard::Create(mConnection));
|
|
|
|
const auto num_windows = mDesktopManager->getWindowManager()->getNumWindows();
|
|
for(std::size_t idx=0; idx< num_windows; idx++)
|
|
{
|
|
addWindow(mDesktopManager->getWindowManager()->getWindow(idx));
|
|
}
|
|
|
|
mDesktopManager->getWindowManager()->getMainWindow()->show();
|
|
}
|
|
|
|
void XcbInterface::connect()
|
|
{
|
|
if (mUseHardwareRendering)
|
|
{
|
|
mX11Display = XOpenDisplay(0);
|
|
if (!mX11Display)
|
|
{
|
|
MLOG_ERROR("Can't open X11 display");
|
|
return;
|
|
}
|
|
mConnection = XGetXCBConnection(mX11Display);
|
|
if (!mConnection)
|
|
{
|
|
XCloseDisplay(mX11Display);
|
|
MLOG_ERROR("Can't get xcb connection from display");
|
|
return;
|
|
}
|
|
XSetEventQueueOwner(mX11Display, XCBOwnsEventQueue);
|
|
}
|
|
else
|
|
{
|
|
mConnection = xcb_connect(nullptr, nullptr);
|
|
}
|
|
}
|
|
|
|
void XcbInterface::updateScreen()
|
|
{
|
|
if (!mConnection)
|
|
{
|
|
return;
|
|
}
|
|
auto screen_iter = xcb_setup_roots_iterator(xcb_get_setup(mConnection));
|
|
if (mUseHardwareRendering)
|
|
{
|
|
if (!mX11Display)
|
|
{
|
|
return;
|
|
}
|
|
const auto default_screen = DefaultScreen(mX11Display);
|
|
for(int screen_num = default_screen; screen_iter.rem && screen_num > 0;
|
|
--screen_num, xcb_screen_next(&screen_iter));
|
|
}
|
|
auto xcb_screen = XcbScreen::Create(screen_iter.data);
|
|
auto screen = mt::Screen::Create();
|
|
screen->SetPlatformScreen(std::move(xcb_screen));
|
|
mDesktopManager->addScreen(std::move(screen));
|
|
}
|
|
|
|
void XcbInterface::initializeHardwareRendering()
|
|
{
|
|
const auto default_screen = DefaultScreen(mX11Display);
|
|
mGlInterface = XcbGlInterface::Create(mX11Display, default_screen);
|
|
}
|
|
|
|
void XcbInterface::createGraphicsContext()
|
|
{
|
|
if (!mConnection || mDesktopManager->getDefaultScreen())
|
|
{
|
|
return;
|
|
}
|
|
auto xcb_screen = dynamic_cast<XcbScreen*>(mDesktopManager->getDefaultScreen()->GetPlatformScreen());
|
|
if (!xcb_screen)
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto gc = xcb_generate_id(mConnection);
|
|
xcb_drawable_t window = xcb_screen->GetNativeScreen()->root;
|
|
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
|
|
auto color = Color(240, 240, 240);
|
|
uint32_t values[2] = {color.getAsUInt32(), 0};
|
|
xcb_create_gc(mConnection, gc, window, mask, values);
|
|
xcb_screen->SetGraphicsContext(gc);
|
|
}
|
|
|
|
void XcbInterface::mapWindow(mt::Window* window)
|
|
{
|
|
window->map();
|
|
}
|
|
|
|
void XcbInterface::showWindow(mt::Window* window)
|
|
{
|
|
window->show();
|
|
}
|
|
|
|
uint32_t XcbInterface::getEventMask()
|
|
{
|
|
return XCB_EVENT_MASK_KEY_RELEASE |
|
|
XCB_EVENT_MASK_BUTTON_PRESS |
|
|
XCB_EVENT_MASK_BUTTON_RELEASE |
|
|
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY;
|
|
}
|
|
|
|
void XcbInterface::addWindow(mt::Window* window)
|
|
{
|
|
auto screen = mDesktopManager->getDefaultScreen();
|
|
XcbWindow::add(window, mConnection, screen, getEventMask(), mFontsManager.get(), mGlInterface.get());
|
|
}
|
|
|
|
void XcbInterface::onPaint()
|
|
{
|
|
mDesktopManager->onUiEvent(PaintEvent::Create());
|
|
|
|
auto mainWindow = mDesktopManager->getWindowManager()->getMainWindow();
|
|
auto defaultScreen = mDesktopManager->getDefaultScreen();
|
|
|
|
mainWindow->doPaint(defaultScreen);
|
|
}
|
|
|
|
void XcbInterface::onExposeEvent(xcb_expose_event_t* event)
|
|
{
|
|
//auto window = mWindows[event->window];
|
|
//window->SetSize(event->width, event->height);
|
|
|
|
onPaint();
|
|
}
|
|
|
|
void XcbInterface::loop()
|
|
{
|
|
initialize();
|
|
|
|
xcb_generic_event_t *event;
|
|
while ((event = xcb_wait_for_event(mConnection)))
|
|
{
|
|
auto handled = true;
|
|
switch (event->response_type & ~0x80)
|
|
{
|
|
case XCB_EXPOSE:{
|
|
auto expose_event = reinterpret_cast<xcb_expose_event_t*>(event);
|
|
onExposeEvent(expose_event);
|
|
break;
|
|
}
|
|
case XCB_KEY_PRESS: {
|
|
auto kp = reinterpret_cast<xcb_key_press_event_t*>(event);
|
|
auto ui_event = mEventInterface->ConvertKeyPress(kp, mDesktopManager->getKeyboard());
|
|
mDesktopManager->onUiEvent(std::move(ui_event));
|
|
break;
|
|
}
|
|
case XCB_KEY_RELEASE: {
|
|
auto kr = reinterpret_cast<xcb_key_release_event_t*>(event);
|
|
auto ui_event = mEventInterface->ConvertKeyRelease(kr, mDesktopManager->getKeyboard());
|
|
mDesktopManager->onUiEvent(std::move(ui_event));
|
|
break;
|
|
}
|
|
case XCB_BUTTON_PRESS: {
|
|
auto press = reinterpret_cast<xcb_button_press_event_t*>(event);
|
|
auto ui_event = mEventInterface->ConvertButtonPress(press);
|
|
mDesktopManager->onUiEvent(std::move(ui_event));
|
|
break;
|
|
}
|
|
case XCB_BUTTON_RELEASE: {
|
|
auto release = reinterpret_cast<xcb_button_release_event_t*>(event);
|
|
auto ui_event = mEventInterface->ConvertButtonRelease(release);
|
|
mDesktopManager->onUiEvent(std::move(ui_event));
|
|
break;
|
|
}
|
|
case XCB_CONFIGURE_NOTIFY:
|
|
{
|
|
auto config_event = (xcb_configure_notify_event_t*) event;
|
|
auto mainWindow = mDesktopManager->getWindowManager()->getMainWindow();
|
|
auto width = mainWindow->getWidth();
|
|
auto height = mainWindow->getHeight();
|
|
|
|
bool changed = false;
|
|
if (config_event->width != width)
|
|
{
|
|
width = config_event->width;
|
|
changed = true;
|
|
}
|
|
if (config_event->height != height)
|
|
{
|
|
height = config_event->height;
|
|
changed = true;
|
|
}
|
|
if (changed)
|
|
{
|
|
auto ui_event = std::make_unique<ResizeEvent>(width, height);
|
|
mDesktopManager->onUiEvent(std::move(ui_event));
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
handled = false;
|
|
break;
|
|
}
|
|
|
|
if (!handled)
|
|
{
|
|
if (mExtensionInterface->isXkBEvent(event->response_type))
|
|
{
|
|
auto xkb_event = reinterpret_cast<_xkb_event *>(event);
|
|
if (xkb_event->any.xkbType == XCB_XKB_STATE_NOTIFY)
|
|
{
|
|
dynamic_cast<XcbKeyboard*>(mDesktopManager->getKeyboard())->updateState(&xkb_event->state_notify);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
free(event);
|
|
mDesktopManager->onLoopIteration();
|
|
}
|
|
}
|
|
|
|
void XcbInterface::shutDown()
|
|
{
|
|
mDesktopManager->getWindowManager()->clearPlatformWindows();
|
|
|
|
if (!mConnection)
|
|
{
|
|
return;
|
|
}
|
|
MLOG_INFO("starting shutdown");
|
|
xcb_disconnect(mConnection);
|
|
MLOG_INFO("Ending shutdown");
|
|
}
|