#pragma once #include "XDataSource.hpp" #include "Dnd.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/signal/Signal.hpp" #include #include #include #include #include #include #include // for PRIxPTR #include struct wl_event_source; class CXWaylandSurfaceResource; struct SXSelection; struct SXTransfer { ~SXTransfer(); SXSelection& selection; bool out = true; bool incremental = false; bool flushOnDelete = false; bool propertySet = false; Hyprutils::OS::CFileDescriptor wlFD; wl_event_source* eventSource = nullptr; std::vector data; xcb_selection_request_event_t request; int propertyStart = 0; xcb_get_property_reply_t* propertyReply = nullptr; xcb_window_t incomingWindow = 0; bool getIncomingSelectionProp(bool erase); }; struct SXSelection { xcb_window_t window = 0; xcb_window_t owner = 0; xcb_timestamp_t timestamp = 0; SP dataSource; bool notifyOnFocus = false; void onSelection(); void onKeyboardFocus(); bool sendData(xcb_selection_request_event_t* e, std::string mime); int onRead(int fd, uint32_t mask); int onWrite(); void removeTransfer(xcb_window_t window); struct { CHyprSignalListener setSelection; CHyprSignalListener keyboardFocusChange; } listeners; std::vector> transfers; }; class CXCBConnection { public: CXCBConnection(int fd) : m_connection{xcb_connect_to_fd(fd, nullptr)} { ; } ~CXCBConnection() { if (m_connection) { Log::logger->log(Log::DEBUG, "Disconnecting XCB connection {:x}", rc(m_connection)); xcb_disconnect(m_connection); m_connection = nullptr; } else Log::logger->log(Log::ERR, "Double xcb_disconnect attempt"); } bool hasError() const { return xcb_connection_has_error(m_connection); } operator xcb_connection_t*() const { return m_connection; } private: xcb_connection_t* m_connection = nullptr; }; class CXCBErrorContext { public: explicit CXCBErrorContext(xcb_connection_t* connection) { if (xcb_errors_context_new(connection, &m_errors) != 0) m_errors = nullptr; } ~CXCBErrorContext() { if (m_errors) xcb_errors_context_free(m_errors); } bool isValid() const { return m_errors != nullptr; } private: xcb_errors_context_t* m_errors = nullptr; }; class CXWM { public: CXWM(); ~CXWM(); int onEvent(int fd, uint32_t mask); SP getDataDevice(); SP createX11DataOffer(SP surf, SP source); void updateWorkArea(int x, int y, int w, int h); private: void setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot); void gatherResources(); void getVisual(); void getRenderFormat(); void createWMWindow(); void initSelection(); void onNewSurface(SP surf); void onNewResource(SP resource); void setActiveWindow(xcb_window_t window); void sendState(SP surf); void focusWindow(SP surf); void activateSurface(SP surf, bool activate); bool isWMWindow(xcb_window_t w); void updateOverrideRedirect(SP surf, bool overrideRedirect); void sendWMMessage(SP surf, xcb_client_message_data_t* data, uint32_t mask); SP windowForXID(xcb_window_t wid); SP windowForWayland(SP surf); void readWindowData(SP surf); void associate(SP surf, SP wlSurf); void dissociate(SP surf); void updateClientList(); // event handlers void handleCreate(xcb_create_notify_event_t* e); void handleDestroy(xcb_destroy_notify_event_t* e); void handleConfigureRequest(xcb_configure_request_event_t* e); void handleConfigureNotify(xcb_configure_notify_event_t* e); void handleMapRequest(xcb_map_request_event_t* e); void handleMapNotify(xcb_map_notify_event_t* e); void handleUnmapNotify(xcb_unmap_notify_event_t* e); void handlePropertyNotify(xcb_property_notify_event_t* e); void handleClientMessage(xcb_client_message_event_t* e); void handleFocusIn(xcb_focus_in_event_t* e); void handleFocusOut(xcb_focus_out_event_t* e); void handleError(xcb_value_error_t* e); void removeTransfersForWindow(xcb_window_t window); bool handleSelectionEvent(xcb_generic_event_t* e); void handleSelectionNotify(xcb_selection_notify_event_t* e); bool handleSelectionPropertyNotify(xcb_property_notify_event_t* e); void handleSelectionRequest(xcb_selection_request_event_t* e); bool handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e); void selectionSendNotify(xcb_selection_request_event_t* e, bool success); xcb_atom_t mimeToAtom(const std::string& mime); std::string mimeFromAtom(xcb_atom_t atom); void setClipboardToWayland(SXSelection& sel); void getTransferData(SXSelection& sel); std::string getAtomName(uint32_t atom); void readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply); SXSelection* getSelection(xcb_atom_t atom); // UP m_connection; xcb_errors_context_t* m_errors = nullptr; xcb_screen_t* m_screen = nullptr; xcb_window_t m_wmWindow; wl_event_source* m_eventSource = nullptr; const xcb_query_extension_reply_t* m_xfixes = nullptr; const xcb_query_extension_reply_t* m_xres = nullptr; int m_xfixesMajor = 0; xcb_visualid_t m_visualID; xcb_colormap_t m_colormap; uint32_t m_cursorXID = 0; xcb_render_pictformat_t m_renderFormatID; std::vector> m_shellResources; std::vector> m_surfaces; std::vector> m_mappedSurfaces; // ordered by map time std::vector> m_mappedSurfacesStacking; // ordered by stacking WP m_focusedSurface; uint64_t m_lastFocusSeq = 0; SXSelection m_clipboard; SXSelection m_primarySelection; SXSelection m_dndSelection; SP m_dndDataDevice = makeShared(); std::vector> m_dndDataOffers; inline xcb_connection_t* getConnection() { return m_connection ? *m_connection : nullptr; } struct { CHyprSignalListener newWLSurface; CHyprSignalListener newXShellSurface; } m_listeners; friend class CXWaylandSurface; friend class CXWayland; friend class CXDataSource; friend class CX11DataDevice; friend class CX11DataSource; friend class CX11DataOffer; friend class CWLDataDeviceProtocol; friend struct SXSelection; friend struct SXTransfer; };