From df2ef8602e71fa1dfcf4b5670e19e772220fdd32 Mon Sep 17 00:00:00 2001 From: liuxinhao Date: Thu, 28 Nov 2024 16:47:31 +0800 Subject: [PATCH] fix(thumbnail): Fix window thumbnails not being fetched by window manager takeover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复窗口管理器接管的窗口缩略图无法获取的问题 Related #56152 --- lib/window.cpp | 75 +++++++++++++++++++- lib/window.h | 6 ++ src/common/kiran-helper.h | 3 + src/workspace/workspace-window-thumbnail.cpp | 4 +- src/workspace/workspace-windows-overview.cpp | 20 +++--- 5 files changed, 93 insertions(+), 15 deletions(-) diff --git a/lib/window.cpp b/lib/window.cpp index eaf2211..a16f4c3 100644 --- a/lib/window.cpp +++ b/lib/window.cpp @@ -26,6 +26,7 @@ #include "lib/app.h" #include "lib/base.h" #include "lib/workspace-manager.h" +#include "window.h" namespace Kiran { @@ -41,6 +42,7 @@ Window::Window(WnckWindow *wnck_window) : wnck_window_(wnck_window), state_changed_handler(0) { xid_ = wnck_window_get_xid(wnck_window_); + real_toplevle_xid_ = xid_; auto workspace = this->get_workspace(); if (workspace) { @@ -52,12 +54,14 @@ Window::Window(WnckWindow *wnck_window) : wnck_window_(wnck_window), this->workspace_changed_handler_ = g_signal_connect(this->wnck_window_, "workspace-changed", G_CALLBACK(Window::workspace_changed), NULL); this->geometry_changed_handler_ = g_signal_connect(this->wnck_window_, "geometry-changed", G_CALLBACK(Window::geometry_changed), NULL); this->state_changed_handler = g_signal_connect(this->wnck_window_, "state-changed", G_CALLBACK(Window::state_changed), NULL); + this->update_real_toplevel_xid(); this->update_window_pixmap(); } Window::Window(gulong xid) : wnck_window_(nullptr), gdk_window_(NULL), xid_(xid), + real_toplevle_xid_(xid_), last_workspace_number_(-1), last_is_pinned_(false), pixmap_(None), @@ -90,6 +94,7 @@ Window::Window(gulong xid) : wnck_window_(nullptr), { KLOG_WARNING("No WnckWindow found for Window with ID 0x%x", xid); } + this->update_real_toplevel_xid(); this->update_window_pixmap(); } @@ -164,7 +169,7 @@ cairo_surface_t *Window::get_thumbnail(int &thumbnail_width, int &thumbnail_heig if (pixmap != None) { gdk_x11_display_error_trap_push(display); - XGetWindowAttributes(xdisplay, get_xid(), &attrs); + XGetWindowAttributes(xdisplay, this->real_toplevle_xid_, &attrs); surface = cairo_xlib_surface_create(xdisplay, pixmap, attrs.visual, @@ -506,6 +511,25 @@ WindowGeometry Window::get_client_window_geometry() return std::make_tuple(x, y, w, h); } +WindowGeometry Window::get_real_toplevel_window_geometry() +{ + auto display = gdk_x11_get_default_xdisplay(); + auto gdk_display = gdk_x11_lookup_xdisplay(display); + + if ( this->real_toplevle_xid_ && gdk_display) + { + gdk_x11_display_error_trap_push(gdk_display); + XWindowAttributes attrs; + XGetWindowAttributes(display, this->real_toplevle_xid_, &attrs); + if (gdk_x11_display_error_trap_pop(gdk_display) == 0) + { + return std::make_tuple(attrs.x, attrs.y, attrs.width, attrs.height); + } + } + + return std::make_tuple(0, 0, 0, 0); +} + void Window::set_geometry(WnckWindowGravity gravity, WnckWindowMoveResizeMask geometry_mask, int x, @@ -676,7 +700,12 @@ void Window::process_events(GdkXEvent *xevent, GdkEvent *event) { auto x_event = (XEvent *)xevent; - if (x_event->type == MapNotify || x_event->type == ConfigureNotify) + if ( x_event->type == ReparentNotify ) + { + update_real_toplevel_xid(); + update_window_pixmap(); + } + else if (x_event->type == MapNotify || x_event->type == ConfigureNotify ) { this->update_window_pixmap(); } @@ -697,8 +726,10 @@ bool Window::update_window_pixmap() } gdk_x11_display_error_trap_push(gdk_display); - this->pixmap_ = XCompositeNameWindowPixmap(display, this->get_xid()); + uint64_t thumbnail_window = this->real_toplevle_xid_; + this->pixmap_ = XCompositeNameWindowPixmap(display, thumbnail_window); + if (gdk_x11_display_error_trap_pop(gdk_display)) { this->pixmap_ = None; @@ -706,6 +737,44 @@ bool Window::update_window_pixmap() return false; } +void Window::update_real_toplevel_xid() +{ + auto display = gdk_x11_get_default_xdisplay(); + g_return_if_fail(display); + + auto gdk_display = gdk_x11_lookup_xdisplay(display); + g_return_if_fail(gdk_display); + + uint64_t window = this->get_xid(); + uint64_t root_window=0,parent_window=0; + uint64_t* children_windows = NULL; + unsigned int n_children = 0; + + gdk_x11_display_error_trap_push(gdk_display); + + XQueryTree(display, window, &root_window, &parent_window, &children_windows, &n_children); + if( n_children ) + { + XFree(children_windows); + } + + if (gdk_x11_display_error_trap_pop(gdk_display)) + { + KLOG_WARNING("update window real toplevel id failed, xid: 0x%lx\n",window); + this->real_toplevle_xid_ = window; + return; + } + + if ( parent_window != root_window ) + { + this->real_toplevle_xid_ = parent_window; + } + else + { + this->real_toplevle_xid_ = window; + } +} + void Window::set_on_visible_workspace(bool on) { if (on) diff --git a/lib/window.h b/lib/window.h index 60e3747..e9886c8 100644 --- a/lib/window.h +++ b/lib/window.h @@ -135,6 +135,7 @@ public: // 获取窗口位置和大小,get_geometry函数包含窗口管理器添加边框的大小,如果需要获取(未被窗口管理器处理过的)实际大小,可以使用get_client_window_geometry WindowGeometry get_geometry(); WindowGeometry get_client_window_geometry(); + WindowGeometry get_real_toplevel_window_geometry(); // 设置窗口的位置和大小,位置和大小包含了窗口管理器添加的边框大小 void set_geometry(WnckWindowGravity gravity, @@ -169,12 +170,17 @@ private: static void state_changed(WnckWindow* wnck_window, gpointer user_data); void process_events(GdkXEvent* xevent, GdkEvent* event); + + // 更新窗口真正顶层窗口ID + void update_real_toplevel_xid(); + bool update_window_pixmap(); private: WnckWindow* wnck_window_; GdkWindow* gdk_window_; gulong xid_; + gulong real_toplevle_xid_; int32_t last_workspace_number_; diff --git a/src/common/kiran-helper.h b/src/common/kiran-helper.h index 3d20d03..ab395da 100644 --- a/src/common/kiran-helper.h +++ b/src/common/kiran-helper.h @@ -26,6 +26,9 @@ using KiranWorkspacePointer = std::shared_ptr; #define WINDOW_WIDTH(w) (std::get<2>(w->get_client_window_geometry())) #define WINDOW_HEIGHT(w) (std::get<3>(w->get_client_window_geometry())) +#define REAL_WINDOW_WIDTH(w) (std::get<2>(w->get_real_toplevel_window_geometry())) +#define REAL_WINDOW_HEIGHT(w) (std::get<3>(w->get_real_toplevel_window_geometry())) + #define UNUSED __attribute__((unused)) class KiranHelper diff --git a/src/workspace/workspace-window-thumbnail.cpp b/src/workspace/workspace-window-thumbnail.cpp index 3f8071a..0a01c2d 100644 --- a/src/workspace/workspace-window-thumbnail.cpp +++ b/src/workspace/workspace-window-thumbnail.cpp @@ -35,8 +35,8 @@ WorkspaceWindowThumbnail::WorkspaceWindowThumbnail(KiranWindowPointer &win_, dou init_drag_and_drop(); int scale_factor = get_scale_factor(); - window_width = WINDOW_WIDTH(win_); - window_height = WINDOW_HEIGHT(win_); + window_width = REAL_WINDOW_WIDTH(win_); + window_height = REAL_WINDOW_HEIGHT(win_); set_thumbnail_size(static_cast(window_width / scale_factor * scale), static_cast(window_height / scale_factor * scale)); } diff --git a/src/workspace/workspace-windows-overview.cpp b/src/workspace/workspace-windows-overview.cpp index 5b805a8..13cae9c 100644 --- a/src/workspace/workspace-windows-overview.cpp +++ b/src/workspace/workspace-windows-overview.cpp @@ -192,7 +192,7 @@ void WorkspaceWindowsOverview::reload_thumbnails() std::vector> results; for (auto window : windows) { - width_vector.push_back(WINDOW_WIDTH(window)); + width_vector.push_back(REAL_WINDOW_WIDTH(window)); } results = arrange_data(width_vector, rows); @@ -211,11 +211,11 @@ void WorkspaceWindowsOverview::reload_thumbnails() auto w1 = windows.at(i); auto w2 = windows.at(j); - if (WINDOW_WIDTH(w1) != WINDOW_WIDTH(w2)) - return WINDOW_WIDTH(w1) >= WINDOW_WIDTH(w2); - else - return WINDOW_HEIGHT(w1) >= WINDOW_HEIGHT(w2); - }); + if (REAL_WINDOW_WIDTH(w1) != REAL_WINDOW_WIDTH(w2)) + return REAL_WINDOW_WIDTH(w1) >= REAL_WINDOW_WIDTH(w2); + else + return REAL_WINDOW_HEIGHT(w1) >= REAL_WINDOW_HEIGHT(w2); + }); /* * 提取该行窗口的最大高度 @@ -224,8 +224,8 @@ void WorkspaceWindowsOverview::reload_thumbnails() { auto window = windows.at(index); - sum += WINDOW_WIDTH(window); - max_height = std::max(max_height, WINDOW_HEIGHT(window)); + sum += REAL_WINDOW_WIDTH(window); + max_height = std::max(max_height, REAL_WINDOW_HEIGHT(window)); } /* @@ -274,8 +274,8 @@ int WorkspaceWindowsOverview::calculate_rows(std::vector