diff --git a/meson.build b/meson.build index f2a2f5f0..691878c6 100644 --- a/meson.build +++ b/meson.build @@ -33,6 +33,7 @@ threads_dep = dependency('threads') # The built in threads dependency does not know how to handle winegcc wine_threads_dep = declare_dependency(link_args : '-lpthread') xcb_dep = dependency('xcb') +xcb_ewmh_dep = dependency('xcb-ewmh') include_dir = include_directories('src/include') @@ -62,7 +63,7 @@ executable( ], native : false, include_directories : include_dir, - dependencies : [boost_dep, bitsery_dep, wine_threads_dep, xcb_dep], + dependencies : [boost_dep, bitsery_dep, wine_threads_dep, xcb_dep, xcb_ewmh_dep], cpp_args : compiler_options, link_args : [] ) diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp index 0fd45a0c..68853c68 100644 --- a/src/wine-host/editor.cpp +++ b/src/wine-host/editor.cpp @@ -1,5 +1,8 @@ #include "editor.h" +#include + +constexpr char xembed_proeprty[] = "_XEMBED"; constexpr char xembed_info_proeprty[] = "_XEMBED_INFO"; ATOM register_window_class(std::string window_class_name); @@ -10,10 +13,14 @@ Editor::Editor(std::string window_class_name) // We need a bunch of property atoms for the XEmbed protocol xcb_generic_error_t* err; + const auto xembed_cookie = xcb_intern_atom( + x11_connection.get(), 0, strlen(xembed_proeprty), xembed_proeprty); const auto xembed_info_cookie = xcb_intern_atom(x11_connection.get(), 0, strlen(xembed_info_proeprty), xembed_info_proeprty); + xcb_xembed = + xcb_intern_atom_reply(x11_connection.get(), xembed_cookie, &err)->atom; xcb_xembed_info = xcb_intern_atom_reply(x11_connection.get(), xembed_info_cookie, &err) ->atom; @@ -126,6 +133,19 @@ std::optional Editor::get_x11_handle() { GetProp(win32_handle.value().get(), "__wine_x11_whole_window")); } +void Editor::send_xembed_event(const xcb_window_t& window, + const uint32_t message, + const uint32_t detail, + const uint32_t data1, + const uint32_t data2) { + const std::array event_data{XCB_TIME_CURRENT_TIME, message, + detail, data1, data2}; + + xcb_ewmh_send_client_message(x11_connection.get(), window, window, + xcb_xembed, event_data.size(), + event_data.data()); +} + ATOM register_window_class(std::string window_class_name) { WNDCLASSEX window_class{}; diff --git a/src/wine-host/editor.h b/src/wine-host/editor.h index 6e7f32ad..899e838b 100644 --- a/src/wine-host/editor.h +++ b/src/wine-host/editor.h @@ -70,6 +70,17 @@ class Editor { */ std::optional get_x11_handle(); + /** + * Send an XEmbed message to a window. See the spec for more information. + * + * https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html#lifecycle + */ + void send_xembed_event(const xcb_window_t& window, + const uint32_t message, + const uint32_t detail, + const uint32_t data1, + const uint32_t data2); + /** * The Win32 window class registered for the window window. */ @@ -84,5 +95,6 @@ class Editor { win32_handle; std::unique_ptr x11_connection; + xcb_atom_t xcb_xembed; xcb_atom_t xcb_xembed_info; };