diff --git a/src/server/frontend_xwayland/CMakeLists.txt b/src/server/frontend_xwayland/CMakeLists.txt index d699fa6a6ac..694b0bcee05 100644 --- a/src/server/frontend_xwayland/CMakeLists.txt +++ b/src/server/frontend_xwayland/CMakeLists.txt @@ -4,7 +4,7 @@ set( xwayland_default_configuration.cpp xwayland_connector.cpp xwayland_connector.h xwayland_server.cpp xwayland_server.h - xcb_atoms.cpp xcb_atoms.h + xcb_connection.cpp xcb_connection.h xwayland_wm.cpp xwayland_wm.h xwayland_surface.cpp xwayland_surface.h xwayland_surface_role.cpp xwayland_surface_role.h diff --git a/src/server/frontend_xwayland/xcb_atoms.cpp b/src/server/frontend_xwayland/xcb_atoms.cpp deleted file mode 100644 index fff83913f2a..00000000000 --- a/src/server/frontend_xwayland/xcb_atoms.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2018 Marius Gripsgard - * Copyright (C) 2020 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include "xcb_atoms.h" -#include "boost/throw_exception.hpp" - -namespace mf = mir::frontend; - -mf::XCBAtoms::Atom::Atom(std::string const& name, Context const& context) - : context{context}, - name_{name}, - cookie{xcb_intern_atom(context.xcb_connection, 0, name_.size(), name_.c_str())} -{ -} - -mf::XCBAtoms::Atom::operator xcb_atom_t() const -{ - if (!atom) - { - auto const reply = xcb_intern_atom_reply(context.xcb_connection, cookie, nullptr); - if (!reply) - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to look up atom " + name_)); - atom = reply->atom; - free(reply); - } - return atom.value(); -} - -auto mf::XCBAtoms::Atom::name() const -> std::string -{ - return name_; -} - -mf::XCBAtoms::XCBAtoms(xcb_connection_t* xcb_connection) - : context{xcb_connection}, - wm_protocols{"WM_PROTOCOLS", context}, - wm_normal_hints{"WM_NORMAL_HINTS", context}, - wm_take_focus{"WM_TAKE_FOCUS", context}, - wm_delete_window{"WM_DELETE_WINDOW", context}, - wm_state{"WM_STATE", context}, - wm_change_state{"WM_CHANGE_STATE", context}, - wm_s0{"WM_S0", context}, - wm_client_machine{"WM_CLIENT_MACHINE", context}, - net_wm_cm_s0{"_NET_WM_CM_S0", context}, - net_wm_name{"_NET_WM_NAME", context}, - net_wm_pid{"_NET_WM_PID", context}, - net_wm_icon{"_NET_WM_ICON", context}, - net_wm_state{"_NET_WM_STATE", context}, - net_wm_state_maximized_vert{"_NET_WM_STATE_MAXIMIZED_VERT", context}, - net_wm_state_maximized_horz{"_NET_WM_STATE_MAXIMIZED_HORZ", context}, - net_wm_state_hidden{"_NET_WM_STATE_HIDDEN", context}, - net_wm_state_fullscreen{"_NET_WM_STATE_FULLSCREEN", context}, - net_wm_user_time{"_NET_WM_USER_TIME", context}, - net_wm_icon_name{"_NET_WM_ICON_NAME", context}, - net_wm_desktop{"_NET_WM_DESKTOP", context}, - net_wm_window_type{"_NET_WM_WINDOW_TYPE", context}, - net_wm_window_type_desktop{"_NET_WM_WINDOW_TYPE_DESKTOP", context}, - net_wm_window_type_dock{"_NET_WM_WINDOW_TYPE_DOCK", context}, - net_wm_window_type_toolbar{"_NET_WM_WINDOW_TYPE_TOOLBAR", context}, - net_wm_window_type_menu{"_NET_WM_WINDOW_TYPE_MENU", context}, - net_wm_window_type_utility{"_NET_WM_WINDOW_TYPE_UTILITY", context}, - net_wm_window_type_splash{"_NET_WM_WINDOW_TYPE_SPLASH", context}, - net_wm_window_type_dialog{"_NET_WM_WINDOW_TYPE_DIALOG", context}, - net_wm_window_type_dropdown{"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", context}, - net_wm_window_type_popup{"_NET_WM_WINDOW_TYPE_POPUP_MENU", context}, - net_wm_window_type_tooltip{"_NET_WM_WINDOW_TYPE_TOOLTIP", context}, - net_wm_window_type_notification{"_NET_WM_WINDOW_TYPE_NOTIFICATION", context}, - net_wm_window_type_combo{"_NET_WM_WINDOW_TYPE_COMBO", context}, - net_wm_window_type_dnd{"_NET_WM_WINDOW_TYPE_DND", context}, - net_wm_window_type_normal{"_NET_WM_WINDOW_TYPE_NORMAL", context}, - net_wm_moveresize{"_NET_WM_MOVERESIZE", context}, - net_supporting_wm_check{"_NET_SUPPORTING_WM_CHECK", context}, - net_supported{"_NET_SUPPORTED", context}, - net_active_window{"_NET_ACTIVE_WINDOW", context}, - motif_wm_hints{"_MOTIF_WM_HINTS", context}, - clipboard{"CLIPBOARD", context}, - clipboard_manager{"CLIPBOARD_MANAGER", context}, - targets{"TARGETS", context}, - utf8_string{"UTF8_STRING", context}, - wl_selection{"_WL_SELECTION", context}, - incr{"INCR", context}, - timestamp{"TIMESTAMP", context}, - multiple{"MULTIPLE", context}, - compound_text{"COMPOUND_TEXT", context}, - text{"TEXT", context}, - string{"STRING", context}, - window{"WINDOW", context}, - text_plain_utf8{"text/plain;charset=utf-8", context}, - text_plain{"text/plain", context}, - xdnd_selection{"XdndSelection", context}, - xdnd_aware{"XdndAware", context}, - xdnd_enter{"XdndEnter", context}, - xdnd_leave{"XdndLeave", context}, - xdnd_drop{"XdndDrop", context}, - xdnd_status{"XdndStatus", context}, - xdnd_finished{"XdndFinished", context}, - xdnd_type_list{"XdndTypeList", context}, - xdnd_action_copy{"XdndActionCopy", context}, - wl_surface_id{"WL_SURFACE_ID", context}, - allow_commits{"_XWAYLAND_ALLOW_COMMITS", context} -{ -} diff --git a/src/server/frontend_xwayland/xcb_connection.cpp b/src/server/frontend_xwayland/xcb_connection.cpp new file mode 100644 index 00000000000..3cfa200e2aa --- /dev/null +++ b/src/server/frontend_xwayland/xcb_connection.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2018 Marius Gripsgard + * Copyright (C) 2020 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "xcb_connection.h" +#include "boost/throw_exception.hpp" + +namespace mf = mir::frontend; + +mf::XCBConnection::Atom::Atom(std::string const& name, XCBConnection* connection) + : connection{connection}, + name_{name}, + cookie{xcb_intern_atom(*connection, 0, name_.size(), name_.c_str())} +{ +} + +mf::XCBConnection::Atom::operator xcb_atom_t() const +{ + if (!atom) + { + auto const reply = xcb_intern_atom_reply(*connection, cookie, nullptr); + if (!reply) + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to look up atom " + name_)); + atom = reply->atom; + free(reply); + } + return atom.value(); +} + +auto mf::XCBConnection::Atom::name() const -> std::string +{ + return name_; +} + +mf::XCBConnection::XCBConnection(int fd) + : xcb_connection{xcb_connect_to_fd(fd, nullptr)}, + wm_protocols{"WM_PROTOCOLS", this}, + wm_normal_hints{"WM_NORMAL_HINTS", this}, + wm_take_focus{"WM_TAKE_FOCUS", this}, + wm_delete_window{"WM_DELETE_WINDOW", this}, + wm_state{"WM_STATE", this}, + wm_change_state{"WM_CHANGE_STATE", this}, + wm_s0{"WM_S0", this}, + wm_client_machine{"WM_CLIENT_MACHINE", this}, + net_wm_cm_s0{"_NET_WM_CM_S0", this}, + net_wm_name{"_NET_WM_NAME", this}, + net_wm_pid{"_NET_WM_PID", this}, + net_wm_icon{"_NET_WM_ICON", this}, + net_wm_state{"_NET_WM_STATE", this}, + net_wm_state_maximized_vert{"_NET_WM_STATE_MAXIMIZED_VERT", this}, + net_wm_state_maximized_horz{"_NET_WM_STATE_MAXIMIZED_HORZ", this}, + net_wm_state_hidden{"_NET_WM_STATE_HIDDEN", this}, + net_wm_state_fullscreen{"_NET_WM_STATE_FULLSCREEN", this}, + net_wm_user_time{"_NET_WM_USER_TIME", this}, + net_wm_icon_name{"_NET_WM_ICON_NAME", this}, + net_wm_desktop{"_NET_WM_DESKTOP", this}, + net_wm_window_type{"_NET_WM_WINDOW_TYPE", this}, + net_wm_window_type_desktop{"_NET_WM_WINDOW_TYPE_DESKTOP", this}, + net_wm_window_type_dock{"_NET_WM_WINDOW_TYPE_DOCK", this}, + net_wm_window_type_toolbar{"_NET_WM_WINDOW_TYPE_TOOLBAR", this}, + net_wm_window_type_menu{"_NET_WM_WINDOW_TYPE_MENU", this}, + net_wm_window_type_utility{"_NET_WM_WINDOW_TYPE_UTILITY", this}, + net_wm_window_type_splash{"_NET_WM_WINDOW_TYPE_SPLASH", this}, + net_wm_window_type_dialog{"_NET_WM_WINDOW_TYPE_DIALOG", this}, + net_wm_window_type_dropdown{"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", this}, + net_wm_window_type_popup{"_NET_WM_WINDOW_TYPE_POPUP_MENU", this}, + net_wm_window_type_tooltip{"_NET_WM_WINDOW_TYPE_TOOLTIP", this}, + net_wm_window_type_notification{"_NET_WM_WINDOW_TYPE_NOTIFICATION", this}, + net_wm_window_type_combo{"_NET_WM_WINDOW_TYPE_COMBO", this}, + net_wm_window_type_dnd{"_NET_WM_WINDOW_TYPE_DND", this}, + net_wm_window_type_normal{"_NET_WM_WINDOW_TYPE_NORMAL", this}, + net_wm_moveresize{"_NET_WM_MOVERESIZE", this}, + net_supporting_wm_check{"_NET_SUPPORTING_WM_CHECK", this}, + net_supported{"_NET_SUPPORTED", this}, + net_active_window{"_NET_ACTIVE_WINDOW", this}, + motif_wm_hints{"_MOTIF_WM_HINTS", this}, + clipboard{"CLIPBOARD", this}, + clipboard_manager{"CLIPBOARD_MANAGER", this}, + targets{"TARGETS", this}, + utf8_string{"UTF8_STRING", this}, + wl_selection{"_WL_SELECTION", this}, + incr{"INCR", this}, + timestamp{"TIMESTAMP", this}, + multiple{"MULTIPLE", this}, + compound_text{"COMPOUND_TEXT", this}, + text{"TEXT", this}, + string{"STRING", this}, + window{"WINDOW", this}, + text_plain_utf8{"text/plain;charset=utf-8", this}, + text_plain{"text/plain", this}, + xdnd_selection{"XdndSelection", this}, + xdnd_aware{"XdndAware", this}, + xdnd_enter{"XdndEnter", this}, + xdnd_leave{"XdndLeave", this}, + xdnd_drop{"XdndDrop", this}, + xdnd_status{"XdndStatus", this}, + xdnd_finished{"XdndFinished", this}, + xdnd_type_list{"XdndTypeList", this}, + xdnd_action_copy{"XdndActionCopy", this}, + wl_surface_id{"WL_SURFACE_ID", this}, + allow_commits{"_XWAYLAND_ALLOW_COMMITS", this} +{ +} + +mf::XCBConnection::~XCBConnection() +{ + xcb_disconnect(xcb_connection); +} + +mf::XCBConnection::operator xcb_connection_t*() const +{ + return xcb_connection; +} diff --git a/src/server/frontend_xwayland/xcb_atoms.h b/src/server/frontend_xwayland/xcb_connection.h similarity index 86% rename from src/server/frontend_xwayland/xcb_atoms.h rename to src/server/frontend_xwayland/xcb_connection.h index d9911640712..acd1291c5d6 100644 --- a/src/server/frontend_xwayland/xcb_atoms.h +++ b/src/server/frontend_xwayland/xcb_connection.h @@ -16,8 +16,8 @@ * */ -#ifndef MIR_FRONTEND_XCB_ATOMS_H -#define MIR_FRONTEND_XCB_ATOMS_H +#ifndef MIR_FRONTEND_XCB_CONNECTION_H +#define MIR_FRONTEND_XCB_CONNECTION_H #include #include @@ -27,22 +27,27 @@ namespace mir { namespace frontend { -class XCBAtoms +class XCBConnection { +public: + explicit XCBConnection(int fd); + ~XCBConnection(); + + operator xcb_connection_t*() const; + private: - struct Context - { - xcb_connection_t* const xcb_connection; - } const context; + XCBConnection(XCBConnection&) = delete; + XCBConnection(XCBConnection&&) = delete; + XCBConnection& operator=(XCBConnection&) = delete; -public: - XCBAtoms(xcb_connection_t* xcb_connection); + xcb_connection_t* const xcb_connection; +public: class Atom { public: /// Context should outlive the atom - Atom(std::string const& name, Context const& context); + Atom(std::string const& name, XCBConnection* connection); operator xcb_atom_t() const; auto name() const -> std::string; @@ -51,7 +56,7 @@ class XCBAtoms Atom(Atom&&) = delete; Atom& operator=(Atom&) = delete; - Context const& context; + XCBConnection* const connection; std::string const name_; xcb_intern_atom_cookie_t const cookie; std::experimental::optional mutable atom; @@ -122,13 +127,8 @@ class XCBAtoms Atom const xdnd_action_copy; Atom const wl_surface_id; Atom const allow_commits; - -private: - XCBAtoms(XCBAtoms&) = delete; - XCBAtoms(XCBAtoms&&) = delete; - XCBAtoms& operator=(XCBAtoms&) = delete; }; } } -#endif // MIR_FRONTEND_XCB_ATOMS_H +#endif // MIR_FRONTEND_XCB_CONNECTION_H diff --git a/src/server/frontend_xwayland/xwayland_surface.cpp b/src/server/frontend_xwayland/xwayland_surface.cpp index 3310293840e..02d216fef45 100644 --- a/src/server/frontend_xwayland/xwayland_surface.cpp +++ b/src/server/frontend_xwayland/xwayland_surface.cpp @@ -71,12 +71,14 @@ auto wm_resize_edge_to_mir_resize_edge(uint32_t wm_resize_edge) -> std::experime mf::XWaylandSurface::XWaylandSurface( XWaylandWM *wm, + std::shared_ptr const& connection, WlSeat& seat, std::shared_ptr const& shell, xcb_create_notify_event_t *event) : xwm(wm), + connection{connection}, seat(seat), - shell(shell), + shell{shell}, window(event->window), props_dirty(true), init{ @@ -85,17 +87,8 @@ mf::XWaylandSurface::XWaylandSurface( {event->width, event->height}, (bool)event->override_redirect} { - xcb_get_geometry_cookie_t const geometry_cookie = xcb_get_geometry(xwm->get_xcb_connection(), window); - - uint32_t const values[]{ - XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE}; - xcb_change_window_attributes(xwm->get_xcb_connection(), window, XCB_CW_EVENT_MASK, values); - - xcb_get_geometry_reply_t* const geometry_reply = - xcb_get_geometry_reply(xwm->get_xcb_connection(), geometry_cookie, nullptr); - - if (!geometry_reply) - mir::log_error("xcb gemom reply faled"); + uint32_t const value = XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE; + xcb_change_window_attributes(*connection, window, XCB_CW_EVENT_MASK, &value); } mf::XWaylandSurface::~XWaylandSurface() @@ -184,11 +177,11 @@ void mf::XWaylandSurface::net_wm_state_client_message(uint32_t const (&data)[5]) { bool nil{false}, *prop_ptr = &nil; - if (property == xwm->xcb_atom.net_wm_state_hidden) + if (property == connection->net_wm_state_hidden) prop_ptr = &new_window_state.minimized; - else if (property == xwm->xcb_atom.net_wm_state_maximized_horz) // assume vert is also set + else if (property == connection->net_wm_state_maximized_horz) // assume vert is also set prop_ptr = &new_window_state.maximized; - else if (property == xwm->xcb_atom.net_wm_state_fullscreen) + else if (property == connection->net_wm_state_fullscreen) prop_ptr = &new_window_state.fullscreen; switch (action) @@ -256,14 +249,14 @@ void mf::XWaylandSurface::set_workspace(int workspace) // Passing a workspace < 0 deletes the property if (workspace >= 0) { - xcb_change_property(xwm->get_xcb_connection(), XCB_PROP_MODE_REPLACE, window, xwm->xcb_atom.net_wm_desktop, + xcb_change_property(*connection, XCB_PROP_MODE_REPLACE, window, connection->net_wm_desktop, XCB_ATOM_CARDINAL, 31, 1, &workspace); } else { - xcb_delete_property(xwm->get_xcb_connection(), window, xwm->xcb_atom.net_wm_desktop); + xcb_delete_property(*connection, window, connection->net_wm_desktop); } - xcb_flush(xwm->get_xcb_connection()); + xcb_flush(*connection); } void mf::XWaylandSurface::unmap() @@ -274,18 +267,18 @@ void mf::XWaylandSurface::unmap() }; xcb_change_property( - xwm->get_xcb_connection(), + *connection, XCB_PROP_MODE_REPLACE, - window, xwm->xcb_atom.wm_state, - xwm->xcb_atom.wm_state, 32, + window, connection->wm_state, + connection->wm_state, 32, length_of(wm_state_properties), wm_state_properties); xcb_delete_property( - xwm->get_xcb_connection(), + *connection, window, - xwm->xcb_atom.net_wm_state); + connection->net_wm_state); - xcb_flush(xwm->get_xcb_connection()); + xcb_flush(*connection); } void mf::XWaylandSurface::read_properties() @@ -300,17 +293,17 @@ void mf::XWaylandSurface::read_properties() props[XCB_ATOM_WM_CLASS] = XCB_ATOM_STRING; props[XCB_ATOM_WM_NAME] = XCB_ATOM_STRING; props[XCB_ATOM_WM_TRANSIENT_FOR] = XCB_ATOM_WINDOW; - props[xwm->xcb_atom.wm_protocols] = TYPE_WM_PROTOCOLS; - props[xwm->xcb_atom.wm_normal_hints] = TYPE_WM_NORMAL_HINTS; - props[xwm->xcb_atom.net_wm_window_type] = XCB_ATOM_ATOM; - props[xwm->xcb_atom.net_wm_name] = XCB_ATOM_STRING; - props[xwm->xcb_atom.motif_wm_hints] = TYPE_MOTIF_WM_HINTS; + props[connection->wm_protocols] = TYPE_WM_PROTOCOLS; + props[connection->wm_normal_hints] = TYPE_WM_NORMAL_HINTS; + props[connection->net_wm_window_type] = XCB_ATOM_ATOM; + props[connection->net_wm_name] = XCB_ATOM_STRING; + props[connection->motif_wm_hints] = TYPE_MOTIF_WM_HINTS; std::map cookies; for (const auto &atom : props) { xcb_get_property_cookie_t cookie = - xcb_get_property(xwm->get_xcb_connection(), 0, window, atom.first, XCB_ATOM_ANY, 0, 2048); + xcb_get_property(*connection, 0, window, atom.first, XCB_ATOM_ANY, 0, 2048); cookies[atom.first] = cookie; } @@ -319,7 +312,7 @@ void mf::XWaylandSurface::read_properties() for (const auto &atom_ptr : props) { xcb_atom_t atom = atom_ptr.first; - xcb_get_property_reply_t *reply = xcb_get_property_reply(xwm->get_xcb_connection(), cookies[atom], nullptr); + xcb_get_property_reply_t *reply = xcb_get_property_reply(*connection, cookies[atom], nullptr); if (!reply) { // Bad window, usually @@ -341,7 +334,7 @@ void mf::XWaylandSurface::read_properties() xcb_get_property_value_length(reply)); if (atom == XCB_ATOM_WM_CLASS) { properties.appId = std::string(p); - } else if (atom == XCB_ATOM_WM_NAME || xwm->xcb_atom.net_wm_name) { + } else if (atom == XCB_ATOM_WM_NAME || connection->net_wm_name) { properties.title = std::string(p); } else { free(p); @@ -354,7 +347,7 @@ void mf::XWaylandSurface::read_properties() } case XCB_ATOM_ATOM: { - if (atom == xwm->xcb_atom.net_wm_window_type) + if (atom == connection->net_wm_window_type) { } break; @@ -363,7 +356,7 @@ void mf::XWaylandSurface::read_properties() { xcb_atom_t *atoms = reinterpret_cast(xcb_get_property_value(reply)); for (uint32_t i = 0; i < reply->value_len; ++i) - if (atoms[i] == xwm->xcb_atom.wm_delete_window) + if (atoms[i] == connection->wm_delete_window) properties.deleteWindow = 1; break; } @@ -472,14 +465,14 @@ void mf::XWaylandSurface::scene_surface_resized(const geometry::Size& new_size) new_size.width.as_uint32_t(), new_size.height.as_uint32_t()}; - xcb_configure_window(xwm->get_xcb_connection(), window, mask, values); - xcb_flush(xwm->get_xcb_connection()); + xcb_configure_window(*connection, window, mask, values); + xcb_flush(*connection); } void mf::XWaylandSurface::scene_surface_close_requested() { - xcb_destroy_window(xwm->get_xcb_connection(), window); - xcb_flush(xwm->get_xcb_connection()); + xcb_destroy_window(*connection, window); + xcb_flush(*connection); } void mf::XWaylandSurface::run_on_wayland_thread(std::function&& work) @@ -555,39 +548,37 @@ void mf::XWaylandSurface::set_window_state(WindowState const& new_window_state) }; xcb_change_property( - xwm->get_xcb_connection(), + *connection, XCB_PROP_MODE_REPLACE, - window, xwm->xcb_atom.wm_state, - xwm->xcb_atom.wm_state, 32, + window, connection->wm_state, + connection->wm_state, 32, length_of(wm_state_properties), wm_state_properties); std::vector net_wm_states; if (new_window_state.minimized) { - net_wm_states.push_back(xwm->xcb_atom.net_wm_state_hidden); + net_wm_states.push_back(connection->net_wm_state_hidden); } if (new_window_state.maximized) { - net_wm_states.push_back(xwm->xcb_atom.net_wm_state_maximized_horz); - net_wm_states.push_back(xwm->xcb_atom.net_wm_state_maximized_vert); + net_wm_states.push_back(connection->net_wm_state_maximized_horz); + net_wm_states.push_back(connection->net_wm_state_maximized_vert); } if (new_window_state.fullscreen) { - net_wm_states.push_back(xwm->xcb_atom.net_wm_state_fullscreen); + net_wm_states.push_back(connection->net_wm_state_fullscreen); } // TODO: Set _NET_WM_STATE_MODAL if appropriate xcb_change_property( - xwm->get_xcb_connection(), + *connection, XCB_PROP_MODE_REPLACE, window, - xwm->xcb_atom.net_wm_state, + connection->net_wm_state, XCB_ATOM_ATOM, 32, // type and format net_wm_states.size(), net_wm_states.data()); - xcb_flush(xwm->get_xcb_connection()); - MirWindowState mir_window_state; if (new_window_state.minimized) diff --git a/src/server/frontend_xwayland/xwayland_surface.h b/src/server/frontend_xwayland/xwayland_surface.h index 0e2ee671453..8bce6255d4e 100644 --- a/src/server/frontend_xwayland/xwayland_surface.h +++ b/src/server/frontend_xwayland/xwayland_surface.h @@ -135,6 +135,7 @@ class XWaylandSurface public: XWaylandSurface( XWaylandWM *wm, + std::shared_ptr const& connection, WlSeat& seat, std::shared_ptr const& shell, xcb_create_notify_event_t *event); @@ -195,6 +196,7 @@ class XWaylandSurface auto latest_input_timestamp(std::lock_guard const&) -> std::chrono::nanoseconds; XWaylandWM* const xwm; + std::shared_ptr const connection; WlSeat& seat; std::shared_ptr const shell; xcb_window_t const window; diff --git a/src/server/frontend_xwayland/xwayland_wm.cpp b/src/server/frontend_xwayland/xwayland_wm.cpp index 9b40827333c..178f31c066a 100644 --- a/src/server/frontend_xwayland/xwayland_wm.cpp +++ b/src/server/frontend_xwayland/xwayland_wm.cpp @@ -96,21 +96,20 @@ auto data_buffer_to_debug_string(T* data, size_t elements) -> std::string mf::XWaylandWM::XWaylandWM(std::shared_ptr wayland_connector, wl_client* wayland_client, int fd) : wm_fd{fd}, - xcb_connection{xcb_connect_to_fd(wm_fd, nullptr)}, - xcb_atom{xcb_connection}, + connection{std::make_shared(fd)}, wayland_connector(wayland_connector), dispatcher{std::make_shared()}, wayland_client{wayland_client}, wm_shell{std::static_pointer_cast(wayland_connector->get_extension("x11-support"))} { - if (xcb_connection_has_error(xcb_connection)) + if (xcb_connection_has_error(*connection)) { mir::log_error("XWAYLAND: xcb_connect_to_fd failed"); close(wm_fd); return; } - xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)); + xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(*connection)); xcb_screen = iter.data; wm_dispatcher = @@ -126,42 +125,42 @@ mf::XWaylandWM::XWaylandWM(std::shared_ptr wayland_connector, uint32_t const attrib_values[]{ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_PROPERTY_CHANGE}; - xcb_change_window_attributes(xcb_connection, xcb_screen->root, XCB_CW_EVENT_MASK, attrib_values); + xcb_change_window_attributes(*connection, xcb_screen->root, XCB_CW_EVENT_MASK, attrib_values); - xcb_composite_redirect_subwindows(xcb_connection, xcb_screen->root, XCB_COMPOSITE_REDIRECT_MANUAL); + xcb_composite_redirect_subwindows(*connection, xcb_screen->root, XCB_COMPOSITE_REDIRECT_MANUAL); xcb_atom_t const supported[]{ - xcb_atom.net_wm_moveresize, - xcb_atom.net_wm_state, - xcb_atom.net_wm_state_fullscreen, - xcb_atom.net_wm_state_maximized_vert, - xcb_atom.net_wm_state_maximized_horz, - xcb_atom.net_active_window}; + connection->net_wm_moveresize, + connection->net_wm_state, + connection->net_wm_state_fullscreen, + connection->net_wm_state_maximized_vert, + connection->net_wm_state_maximized_horz, + connection->net_active_window}; xcb_change_property( - xcb_connection, + *connection, XCB_PROP_MODE_REPLACE, xcb_screen->root, - xcb_atom.net_supported, + connection->net_supported, XCB_ATOM_ATOM, 32, // type and format length_of(supported), supported); uint32_t const window_none = XCB_WINDOW_NONE; xcb_change_property( - xcb_connection, + *connection, XCB_PROP_MODE_REPLACE, - xcb_screen->root, xcb_atom.net_active_window, - xcb_atom.window, 32, + xcb_screen->root, connection->net_active_window, + connection->window, 32, 1, &window_none); wm_selector(); - xcb_flush(xcb_connection); + xcb_flush(*connection); create_wm_cursor(); set_cursor(xcb_screen->root, CursorLeftPointer); create_wm_window(); - xcb_flush(xcb_connection); + xcb_flush(*connection); } mf::XWaylandWM::~XWaylandWM() @@ -200,12 +199,12 @@ mf::XWaylandWM::~XWaylandWM() { mir::log_info("Cleaning cursors"); for (auto xcb_cursor : xcb_cursors) - xcb_free_cursor(xcb_connection, xcb_cursor); + xcb_free_cursor(*connection, xcb_cursor); } - if (xcb_connection != nullptr) + if (*connection != nullptr) { - xcb_disconnect(xcb_connection); + xcb_disconnect(*connection); } close(wm_fd); @@ -218,10 +217,10 @@ void mf::XWaylandWM::wm_selector() uint32_t const values[]{ XCB_EVENT_MASK_PROPERTY_CHANGE}; - xcb_selection_window = xcb_generate_id(xcb_connection); + xcb_selection_window = xcb_generate_id(*connection); xcb_create_window( - xcb_connection, + *connection, XCB_COPY_FROM_PARENT, xcb_selection_window, xcb_screen->root, @@ -233,14 +232,14 @@ void mf::XWaylandWM::wm_selector() XCB_CW_EVENT_MASK, values); - xcb_set_selection_owner(xcb_connection, xcb_selection_window, xcb_atom.clipboard_manager, XCB_TIME_CURRENT_TIME); + xcb_set_selection_owner(*connection, xcb_selection_window, connection->clipboard_manager, XCB_TIME_CURRENT_TIME); uint32_t const mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE; - xcb_xfixes_select_selection_input(xcb_connection, xcb_selection_window, xcb_atom.clipboard, mask); + xcb_xfixes_select_selection_input(*connection, xcb_selection_window, connection->clipboard, mask); } void mf::XWaylandWM::set_cursor(xcb_window_t id, const CursorType &cursor) @@ -250,8 +249,8 @@ void mf::XWaylandWM::set_cursor(xcb_window_t id, const CursorType &cursor) xcb_cursor = cursor; uint32_t cursor_value_list = xcb_cursors[cursor]; - xcb_change_window_attributes(xcb_connection, id, XCB_CW_CURSOR, &cursor_value_list); - xcb_flush(xcb_connection); + xcb_change_window_attributes(*connection, id, XCB_CW_CURSOR, &cursor_value_list); + xcb_flush(*connection); } void mf::XWaylandWM::create_wm_cursor() @@ -278,27 +277,27 @@ void mf::XWaylandWM::create_wm_window() { std::string const wm_name{"Mir XWM"}; - xcb_window = xcb_generate_id(xcb_connection); - xcb_create_window(xcb_connection, XCB_COPY_FROM_PARENT, xcb_window, xcb_screen->root, 0, 0, 10, 10, 0, + xcb_window = xcb_generate_id(*connection); + xcb_create_window(*connection, XCB_COPY_FROM_PARENT, xcb_window, xcb_screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, xcb_screen->root_visual, 0, NULL); - xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, xcb_window, xcb_atom.net_supporting_wm_check, + xcb_change_property(*connection, XCB_PROP_MODE_REPLACE, xcb_window, connection->net_supporting_wm_check, XCB_ATOM_WINDOW, 32, /* format */ 1, &xcb_window); - xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, xcb_window, xcb_atom.net_wm_name, xcb_atom.utf8_string, + xcb_change_property(*connection, XCB_PROP_MODE_REPLACE, xcb_window, connection->net_wm_name, connection->utf8_string, 8, /* format */ wm_name.size(), wm_name.c_str()); - xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, xcb_screen->root, xcb_atom.net_supporting_wm_check, + xcb_change_property(*connection, XCB_PROP_MODE_REPLACE, xcb_screen->root, connection->net_supporting_wm_check, XCB_ATOM_WINDOW, 32, /* format */ 1, &xcb_window); /* Claim the WM_S0 selection even though we don't support * the --replace functionality. */ - xcb_set_selection_owner(xcb_connection, xcb_window, xcb_atom.wm_s0, XCB_TIME_CURRENT_TIME); + xcb_set_selection_owner(*connection, xcb_window, connection->wm_s0, XCB_TIME_CURRENT_TIME); - xcb_set_selection_owner(xcb_connection, xcb_window, xcb_atom.net_wm_cm_s0, XCB_TIME_CURRENT_TIME); + xcb_set_selection_owner(*connection, xcb_window, connection->net_wm_cm_s0, XCB_TIME_CURRENT_TIME); } auto mf::XWaylandWM::get_wm_surface( @@ -323,7 +322,7 @@ void mf::XWaylandWM::handle_events() { bool got_events = false; - while (xcb_generic_event_t* const event = xcb_poll_for_event(xcb_connection)) + while (xcb_generic_event_t* const event = xcb_poll_for_event(*connection)) { try { @@ -343,7 +342,7 @@ void mf::XWaylandWM::handle_events() if (got_events) { - xcb_flush(xcb_connection); + xcb_flush(*connection); } } @@ -433,7 +432,7 @@ void mf::XWaylandWM::handle_property_notify(xcb_property_notify_event_t *event) else { xcb_get_property_cookie_t const cookie = xcb_get_property( - xcb_connection, + *connection, 0, // don't delete event->window, event->atom, @@ -441,7 +440,7 @@ void mf::XWaylandWM::handle_property_notify(xcb_property_notify_event_t *event) 0, 2048); - xcb_get_property_reply_t* const reply = xcb_get_property_reply(xcb_connection, cookie, NULL); + xcb_get_property_reply_t* const reply = xcb_get_property_reply(*connection, cookie, NULL); auto const prop_name = get_atom_name(event->atom); auto const reply_str = get_reply_debug_string(reply); @@ -478,7 +477,12 @@ void mf::XWaylandWM::handle_create_notify(xcb_create_notify_event_t *event) if (!is_ours(event->window)) { - auto const surface = std::make_shared(this, wm_shell->seat, wm_shell->shell, event); + auto const surface = std::make_shared( + this, + connection, + wm_shell->seat, + wm_shell->shell, + event); { std::lock_guard lock{mutex}; @@ -545,8 +549,8 @@ void mf::XWaylandWM::handle_map_request(xcb_map_request_event_t *event) surface.value()->read_properties(); surface.value()->set_workspace(0); surface.value()->map(); - xcb_map_window(xcb_connection, event->window); - xcb_flush(xcb_connection); + xcb_map_window(*connection, event->window); + xcb_flush(*connection); } } @@ -572,8 +576,8 @@ void mf::XWaylandWM::handle_unmap_notify(xcb_unmap_notify_event_t *event) { surface.value()->unmap(); surface.value()->set_workspace(-1); - xcb_unmap_window(xcb_connection, event->window); - xcb_flush(xcb_connection); + xcb_unmap_window(*connection, event->window); + xcb_flush(*connection); } } @@ -609,13 +613,13 @@ void mf::XWaylandWM::handle_client_message(xcb_client_message_event_t *event) if (auto const surface = get_wm_surface(event->window)) { - if (event->type == xcb_atom.net_wm_moveresize) + if (event->type == connection->net_wm_moveresize) handle_move_resize(surface.value(), event); - else if (event->type == xcb_atom.net_wm_state) + else if (event->type == connection->net_wm_state) surface.value()->net_wm_state_client_message(event->data.data32); - else if (event->type == xcb_atom.wm_change_state) + else if (event->type == connection->wm_change_state) surface.value()->wm_change_state_client_message(event->data.data32); - else if (event->type == xcb_atom.wl_surface_id) + else if (event->type == connection->wl_surface_id) handle_surface_id(surface.value(), event); } } @@ -700,8 +704,8 @@ void mf::XWaylandWM::handle_configure_request(xcb_configure_request_event_t *eve if (!values.empty()) { - xcb_configure_window(xcb_connection, event->window, event->value_mask, values.data()); - xcb_flush(xcb_connection); + xcb_configure_window(*connection, event->window, event->value_mask, values.data()); + xcb_flush(*connection); } } @@ -724,7 +728,7 @@ void mf::XWaylandWM::handle_configure_notify(xcb_configure_notify_event_t *event // Cursor xcb_cursor_t mf::XWaylandWM::xcb_cursor_image_load_cursor(const XcursorImage *img) { - xcb_connection_t *c = xcb_connection; + xcb_connection_t *c = *connection; xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c)); xcb_screen_t *screen = s.data; xcb_gcontext_t gc; @@ -799,24 +803,24 @@ void mf::XWaylandWM::wm_get_resources() xcb_render_pictforminfo_t *formats; uint32_t i; - xcb_prefetch_extension_data(xcb_connection, &xcb_xfixes_id); - xcb_prefetch_extension_data(xcb_connection, &xcb_composite_id); + xcb_prefetch_extension_data(*connection, &xcb_xfixes_id); + xcb_prefetch_extension_data(*connection, &xcb_composite_id); - formats_cookie = xcb_render_query_pict_formats(xcb_connection); + formats_cookie = xcb_render_query_pict_formats(*connection); - xfixes = xcb_get_extension_data(xcb_connection, &xcb_xfixes_id); + xfixes = xcb_get_extension_data(*connection, &xcb_xfixes_id); if (!xfixes || !xfixes->present) log_warning("xfixes not available"); - xfixes_cookie = xcb_xfixes_query_version(xcb_connection, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); - xfixes_reply = xcb_xfixes_query_version_reply(xcb_connection, xfixes_cookie, NULL); + xfixes_cookie = xcb_xfixes_query_version(*connection, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); + xfixes_reply = xcb_xfixes_query_version_reply(*connection, xfixes_cookie, NULL); if (verbose_xwayland_logging_enabled()) log_debug("xfixes version: %d.%d", xfixes_reply->major_version, xfixes_reply->minor_version); free(xfixes_reply); - formats_reply = xcb_render_query_pict_formats_reply(xcb_connection, formats_cookie, 0); + formats_reply = xcb_render_query_pict_formats_reply(*connection, formats_cookie, 0); if (formats_reply == NULL) return; @@ -911,7 +915,7 @@ auto mf::XWaylandWM::get_window_debug_string(xcb_window_t window) -> std::string auto mf::XWaylandWM::get_reply_string(xcb_get_property_reply_t* reply) -> std::experimental::optional { - if (reply->type == xcb_atom.string || reply->type == xcb_atom.utf8_string) + if (reply->type == connection->string || reply->type == connection->utf8_string) return std::string{(const char *)xcb_get_property_value(reply), reply->value_len}; else return std::experimental::nullopt; @@ -925,8 +929,8 @@ auto mf::XWaylandWM::get_atom_name(xcb_atom_t atom) -> std::string if (atom == XCB_ATOM_NONE) return "None"; - xcb_get_atom_name_cookie_t const cookie = xcb_get_atom_name(xcb_connection, atom); - xcb_get_atom_name_reply_t* const reply = xcb_get_atom_name_reply(xcb_connection, cookie, nullptr); + xcb_get_atom_name_cookie_t const cookie = xcb_get_atom_name(*connection, atom); + xcb_get_atom_name_reply_t* const reply = xcb_get_atom_name_reply(*connection, cookie, nullptr); std::string name; @@ -970,12 +974,12 @@ void mf::XWaylandWM::setup_visual_and_colormap() } xcb_visual_id = visualType->visual_id; - xcb_colormap = xcb_generate_id(xcb_connection); - xcb_create_colormap(xcb_connection, XCB_COLORMAP_ALLOC_NONE, xcb_colormap, xcb_screen->root, xcb_visual_id); + xcb_colormap = xcb_generate_id(*connection); + xcb_create_colormap(*connection, XCB_COLORMAP_ALLOC_NONE, xcb_colormap, xcb_screen->root, xcb_visual_id); } bool mf::XWaylandWM::is_ours(uint32_t id) { - auto setup = xcb_get_setup(xcb_connection); + auto setup = xcb_get_setup(*connection); return (id & ~setup->resource_id_mask) == setup->resource_id_base; } diff --git a/src/server/frontend_xwayland/xwayland_wm.h b/src/server/frontend_xwayland/xwayland_wm.h index d0c11ee8dee..6eea233396e 100644 --- a/src/server/frontend_xwayland/xwayland_wm.h +++ b/src/server/frontend_xwayland/xwayland_wm.h @@ -21,7 +21,7 @@ #include "mir/dispatch/threaded_dispatcher.h" #include "wayland_connector.h" -#include "xcb_atoms.h" +#include "xcb_connection.h" #include #include @@ -59,22 +59,15 @@ class XWaylandWM { private: int const wm_fd; - xcb_connection_t* const xcb_connection; + std::shared_ptr const connection; public: XWaylandWM(std::shared_ptr wayland_connector, wl_client* wayland_client, int fd); ~XWaylandWM(); - auto get_xcb_connection() const -> xcb_connection_t* - { - return xcb_connection; - } - auto get_wm_surface(xcb_window_t xcb_window) -> std::experimental::optional>; void run_on_wayland_thread(std::function&& work); - XCBAtoms const xcb_atom; - private: enum CursorType