#include "XcbInterface.h" #include "DesktopManager.h" #include #include /* for XGetXCBConnection, link with libX11-xcb */ #include #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(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(event); onExposeEvent(expose_event); break; } case XCB_KEY_PRESS: { auto kp = reinterpret_cast(event); auto ui_event = mEventInterface->ConvertKeyPress(kp, mDesktopManager->getKeyboard()); mDesktopManager->onUiEvent(std::move(ui_event)); break; } case XCB_KEY_RELEASE: { auto kr = reinterpret_cast(event); auto ui_event = mEventInterface->ConvertKeyRelease(kr, mDesktopManager->getKeyboard()); mDesktopManager->onUiEvent(std::move(ui_event)); break; } case XCB_BUTTON_PRESS: { auto press = reinterpret_cast(event); auto ui_event = mEventInterface->ConvertButtonPress(press); mDesktopManager->onUiEvent(std::move(ui_event)); break; } case XCB_BUTTON_RELEASE: { auto release = reinterpret_cast(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"); }