stuff-from-scratch/src/windows/ui_interfaces/x11/XcbInterface.cpp
2022-11-14 11:19:51 +00:00

238 lines
6.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 <xcb/xcb.h>
#include "PaintEvent.h"
#include "Screen.h"
#include "XcbScreen.h"
#include "UiEvent.h"
#include "VisualLayer.h"
#include "XcbKeyboard.h"
#include "XcbWindow.h"
#include "XcbLayerInterface.h"
#include "XcbEventInterface.h"
#include "XcbGlInterface.h"
#include "FileLogger.h"
XcbInterface::XcbInterface(DesktopManager* desktopManager, bool useHardware)
: AbstractUIInterface(desktopManager, useHardware),
mEventInterface(XcbEventInterface::Create())
{
}
XcbInterface::~XcbInterface()
{
shutDown();
}
void XcbInterface::initialize()
{
connect();
updateScreen();
createGraphicsContext();
if (mUseHardwareRendering)
{
initializeHardwareRendering();
}
mDesktopManager->setKeyboard(XcbKeyboard::Create());
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;
uint32_t values[2] = {XcbLayerInterface::getColor(240, 240, 240), 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;
}
void XcbInterface::addWindow(mt::Window* window)
{
auto screen = mDesktopManager->getDefaultScreen();
XcbWindow::add(window, mConnection, screen, getEventMask(), 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)))
{
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;
}
default:
/* Unknown event type, ignore it */
break;
}
onEventsDispatched();
free(event);
}
}
void XcbInterface::onEventsDispatched()
{
if (mDesktopManager->isModified())
{
mDesktopManager->setIsModified(false);
auto mainWindow = mDesktopManager->getWindowManager()->getMainWindow();
mainWindow->clear();
}
}
void XcbInterface::shutDown()
{
mDesktopManager->getWindowManager()->clearPlatformWindows();
if (!mConnection)
{
return;
}
MLOG_INFO("starting shutdown");
xcb_disconnect(mConnection);
MLOG_INFO("Ending shutdown");
}