Skip to content

feat: allow bypassing the compositor when fullscreen#844

Open
LiHua000 wants to merge 2 commits intolinuxdeepin:masterfrom
LiHua000:master
Open

feat: allow bypassing the compositor when fullscreen#844
LiHua000 wants to merge 2 commits intolinuxdeepin:masterfrom
LiHua000:master

Conversation

@LiHua000
Copy link
Copy Markdown
Contributor

@LiHua000 LiHua000 commented Apr 24, 2026

Log: as title

task: https://pms.uniontech.com/task-view-384659.html

Summary by Sourcery

Allow X11 fullscreen windows to request compositor bypass for performance and restore normal compositing when exiting fullscreen.

New Features:

  • Add a Utility helper to toggle the _NET_WM_BYPASS_COMPOSITOR property on X11 windows.
  • Enable main window implementations to set compositor bypass when entering fullscreen and clear it when leaving fullscreen.

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: LiHua000

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 24, 2026

Reviewer's Guide

Adds X11 support for toggling _NET_WM_BYPASS_COMPOSITOR when the main windows enter or exit fullscreen, while ensuring the behavior is disabled on Wayland and wired into both MainWindow and Platform_MainWindow fullscreen flows.

Sequence diagram for toggling compositor bypass on fullscreen enter/exit

sequenceDiagram
    actor User
    participant MainWindow
    participant Utility
    participant X11Server

    User->>MainWindow: trigger fullscreen (mipsShowFullScreen)
    MainWindow->>MainWindow: start fullscreen animation
    MainWindow->>MainWindow: setWindowState(WindowFullScreen)
    MainWindow-->>MainWindow: QPropertyAnimation finished
    MainWindow->>Utility: setBypassCompositor(winId, true)
    Utility->>Utility: check_wayland_env()
    alt running_on_X11
        Utility->>X11Server: XChangeProperty(_NET_WM_BYPASS_COMPOSITOR = 1)
        X11Server-->>Utility: property_set
    else running_on_Wayland
        Utility-->>MainWindow: return without changes
    end

    User->>MainWindow: exit fullscreen (requestAction)
    MainWindow->>MainWindow: isFullScreen() == true
    MainWindow->>Utility: setBypassCompositor(winId, false)
    Utility->>Utility: check_wayland_env()
    alt running_on_X11
        Utility->>X11Server: XChangeProperty(_NET_WM_BYPASS_COMPOSITOR = 0)
        X11Server-->>Utility: property_set
    else running_on_Wayland
        Utility-->>MainWindow: return without changes
    end
    MainWindow->>MainWindow: clear WindowFullScreen flag
Loading

Class diagram for Utility and main window fullscreen integration

classDiagram
    class Utility {
        +static QByteArray windowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, quint32 len)
        +static QList~xcb_atom_t~ windowNetWMState(quint32 WId)
        +static void setWindowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, const void *data, quint32 len, uint8_t format)
        +static void setBypassCompositor(quint32 WId, bool bypass)
    }

    class MainWindow {
        +void mipsShowFullScreen()
        +void requestAction(ActionFactory::ActionKind actionKind, bool bFromUser)
    }

    class Platform_MainWindow {
        +void mipsShowFullScreen()
        +void requestAction(ActionFactory::ActionKind actionKind, bool bFromUser)
    }

    MainWindow ..> Utility : uses
    Platform_MainWindow ..> Utility : uses
Loading

File-Level Changes

Change Details Files
Introduce X11 helper to set the _NET_WM_BYPASS_COMPOSITOR property on a window, guarded against Wayland environments.
  • Include utils header in X11 utility implementation to access environment checks
  • Define kAtomNameBypassCompositor constant for the _NET_WM_BYPASS_COMPOSITOR atom name
  • Implement Utility::setBypassCompositor to early-return on Wayland, validate display and window id, intern required atoms, and set/unset the CARDINAL property value via XChangeProperty and XFlush
  • Declare the new setBypassCompositor API in the Utility class interface
src/common/utility_x11.cpp
src/common/utility.h
Hook compositor bypass toggling into fullscreen enter/exit flows for both MainWindow and Platform_MainWindow.
  • In MainWindow::mipsShowFullScreen, connect the fullscreen animation’s finished signal to a lambda that enables compositor bypass for the window
  • In MainWindow::requestAction, before leaving fullscreen, disable compositor bypass for the window and then proceed with existing fullscreen/maximize logic
  • In Platform_MainWindow::mipsShowFullScreen, after setting fullscreen and visibility, enable compositor bypass for the window
  • In Platform_MainWindow::requestAction, before leaving fullscreen, disable compositor bypass and then perform existing state changes
src/common/mainwindow.cpp
src/common/platform/platform_mainwindow.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In Utility::setBypassCompositor, using unsigned long as the property payload for a 32-bit CARDINAL can be architecture-dependent; consider using a fixed-width type like uint32_t (and adjusting the format parameter if needed) to avoid size mismatches on 64-bit platforms.
  • The fullscreen compositor-bypass logic is duplicated in both MainWindow and Platform_MainWindow; consider extracting a small helper or centralizing this behavior to keep the fullscreen handling consistent and easier to maintain.
  • In MainWindow::mipsShowFullScreen, the bypass is set only after the animation finishes, while Platform_MainWindow::mipsShowFullScreen sets it immediately after calling setWindowState; verify whether this intentional difference is required or if these code paths should align for predictable behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `Utility::setBypassCompositor`, using `unsigned long` as the property payload for a 32-bit `CARDINAL` can be architecture-dependent; consider using a fixed-width type like `uint32_t` (and adjusting the format parameter if needed) to avoid size mismatches on 64-bit platforms.
- The fullscreen compositor-bypass logic is duplicated in both `MainWindow` and `Platform_MainWindow`; consider extracting a small helper or centralizing this behavior to keep the fullscreen handling consistent and easier to maintain.
- In `MainWindow::mipsShowFullScreen`, the bypass is set only after the animation finishes, while `Platform_MainWindow::mipsShowFullScreen` sets it immediately after calling `setWindowState`; verify whether this intentional difference is required or if these code paths should align for predictable behavior.

## Individual Comments

### Comment 1
<location path="src/common/utility_x11.cpp" line_range="412-413" />
<code_context>
+        return;
+    }
+
+    unsigned long value = bypass ? 1 : 0;
+    XChangeProperty(display, windowId, bypassAtom, cardinalAtom, 32,
+                   PropModeReplace, reinterpret_cast<unsigned char*>(&value), 1);
+    XFlush(display);
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Use a fixed-width 32-bit type for the CARDINAL property value

`_NET_WM_BYPASS_COMPOSITOR` is defined as a 32-bit `CARDINAL`, but `unsigned long` can be 64-bit on some platforms while we declare a 32-bit format in `XChangeProperty`. This mismatch can cause ABI/endianness issues. Use a fixed-width 32-bit type, e.g. `uint32_t value = bypass ? 1u : 0u;`, and pass that to `XChangeProperty`.

Suggested implementation:

```cpp
    uint32_t value = bypass ? 1u : 0u;
    XChangeProperty(display, windowId, bypassAtom, cardinalAtom, 32,
                   PropModeReplace, reinterpret_cast<unsigned char*>(&value), 1);
    XFlush(display);

```

To compile cleanly with `uint32_t`, ensure that either `<cstdint>` or `<stdint.h>` is included in this translation unit (or via a common header). Add the appropriate include near the top of `utility_x11.cpp` if it's not already present.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +412 to +413
unsigned long value = bypass ? 1 : 0;
XChangeProperty(display, windowId, bypassAtom, cardinalAtom, 32,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Use a fixed-width 32-bit type for the CARDINAL property value

_NET_WM_BYPASS_COMPOSITOR is defined as a 32-bit CARDINAL, but unsigned long can be 64-bit on some platforms while we declare a 32-bit format in XChangeProperty. This mismatch can cause ABI/endianness issues. Use a fixed-width 32-bit type, e.g. uint32_t value = bypass ? 1u : 0u;, and pass that to XChangeProperty.

Suggested implementation:

    uint32_t value = bypass ? 1u : 0u;
    XChangeProperty(display, windowId, bypassAtom, cardinalAtom, 32,
                   PropModeReplace, reinterpret_cast<unsigned char*>(&value), 1);
    XFlush(display);

To compile cleanly with uint32_t, ensure that either <cstdint> or <stdint.h> is included in this translation unit (or via a common header). Add the appropriate include near the top of utility_x11.cpp if it's not already present.

@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

Git Diff 代码审查报告

总体评价

这段代码主要实现了在全屏模式下绕过窗口合成器(compositor)的功能,以提升全屏视频播放的性能。修改涉及多个文件,包括 .gitignore、mainwindow.cpp、platform_mainwindow.cpp、utility.h 和 utility_x11.cpp。

1. 语法逻辑审查

1.1 mainwindow.cpp 中的逻辑问题

void MainWindow::mipsShowFullScreen()
{
    // ... 动画设置代码 ...
    setWindowState(windowState() | Qt::WindowFullScreen);

    connect(pAn, &QPropertyAnimation::finished, this, [=](){
        // 全屏时设置绕过合成器
        if (windowHandle()) {
            Utility::setBypassCompositor(windowHandle()->winId(), true);
        }
    });
}

问题:每次调用 mipsShowFullScreen() 都会创建一个新的 connect 连接,可能导致多次调用时产生多个连接,进而多次调用 setBypassCompositor

建议:应该使用 QObject::disconnect 断开之前的连接,或者使用 QPointerQMetaObject::Connection 来管理连接生命周期。

1.2 platform_mainwindow.cpp 中的不一致性

Platform_MainWindow::mipsShowFullScreen() 中,设置绕过合成器的代码与动画完成事件无关,而是直接在全屏时设置:

void Platform_MainWindow::mipsShowFullScreen()
{
    // ... 其他代码 ...
    setWindowState(windowState() | Qt::WindowFullScreen);
    setVisible(true);

    // 全屏时设置绕过合成器
    if (windowHandle()) {
        Utility::setBypassCompositor(windowHandle()->winId(), true);
    }
}

这与 MainWindow::mipsShowFullScreen() 中的实现不一致,可能导致两个窗口类的行为不一致。

2. 代码质量审查

2.1 缺少错误处理

Utility::setBypassCompositor 函数中,虽然有一些基本的空指针检查,但没有检查 XChangeProperty 的返回值,无法确认属性设置是否成功。

2.2 魔法数字

Utility::setBypassCompositor 中使用了魔法数字 10 来表示绕过合成器的开关:

unsigned long value = bypass ? 1 : 0;

建议:定义常量或枚举来提高代码可读性:

enum BypassCompositorMode {
    BypassDisabled = 0,
    BypassEnabled = 1
};

2.3 代码注释不足

setBypassCompositor 函数缺少详细的功能说明,特别是关于 _NET_WM_BYPASS_COMPOSITOR 属性的作用和值的含义。

3. 代码性能审查

3.1 X11 调用优化

setBypassCompositor 函数中,每次调用都会执行多个 X11 函数,包括 XInternAtomXChangeProperty。如果这个函数被频繁调用,可能会影响性能。

建议:可以考虑缓存 bypassAtomcardinalAtom,避免每次调用时都进行原子查找。

3.2 动画与合成器设置的时机

MainWindow::mipsShowFullScreen() 中,绕过合成器的设置是在动画完成后执行的。这可能导致在全屏动画过程中仍然使用合成器,而在动画完成后才绕过合成器,可能会造成视觉上的闪烁。

建议:考虑在动画开始前就设置绕过合成器,或者评估动画过程中是否需要合成器。

4. 代码安全审查

4.1 潜在的内存安全问题

Utility::setBypassCompositor 中使用了 reinterpret_cast 来转换指针类型:

XChangeProperty(display, windowId, bypassAtom, cardinalAtom, 32,
               PropModeReplace, reinterpret_cast<unsigned char*>(&value), 1);

虽然在这个特定情况下是安全的,但建议添加注释说明为什么这种转换是安全的,或者使用更安全的转换方式。

4.2 窗口ID的有效性检查

虽然代码中检查了 windowId == 0,但这并不能完全保证窗口ID的有效性。窗口ID可能已经被释放但尚未重用。

建议:考虑添加更严格的窗口有效性检查,或者确保在窗口销毁前取消绕过合成器设置。

5. 改进建议

5.1 统一全屏处理逻辑

建议将全屏处理逻辑提取为一个共同的基类方法,确保 MainWindowPlatform_MainWindow 的行为一致。

5.2 添加RAII包装器

考虑为X11资源创建RAII包装器,确保资源在异常情况下也能正确释放。

5.3 改进后的代码示例

// utility.h 中添加
enum BypassCompositorMode {
    BypassDisabled = 0,
    BypassEnabled = 1
};

// utility_x11.cpp 中改进
void Utility::setBypassCompositor(quint32 WId, bool bypass)
{
    if (dmr::utils::check_wayland_env()) {
        return;
    }

    Display *display = QX11Info::display();
    if (!display) {
        qWarning() << "Failed to get X11 display";
        return;
    }

    Window windowId = static_cast<Window>(WId);
    if (windowId == 0) {
        qWarning() << "Invalid window ID";
        return;
    }

    // 缓存原子以提高性能
    static Atom bypassAtom = None;
    static Atom cardinalAtom = None;
    
    if (bypassAtom == None) {
        bypassAtom = XInternAtom(display, kAtomNameBypassCompositor, false);
        if (bypassAtom == None) {
            qWarning() << "Failed to get bypass compositor atom";
            return;
        }
    }
    
    if (cardinalAtom == None) {
        cardinalAtom = XInternAtom(display, "CARDINAL", false);
        if (cardinalAtom == None) {
            qWarning() << "Failed to get cardinal atom";
            return;
        }
    }

    unsigned long value = bypass ? BypassEnabled : BypassDisabled;
    int result = XChangeProperty(display, windowId, bypassAtom, cardinalAtom, 32,
                                PropModeReplace, reinterpret_cast<unsigned char*>(&value), 1);
    if (result != Success) {
        qWarning() << "Failed to set bypass compositor property:" << result;
    }
    
    XFlush(display);
}

5.4 改进 mainwindow.cpp 中的连接管理

// 在 MainWindow 类中添加成员变量
private:
    QMetaObject::Connection m_fullScreenAnimationConnection;

// 在 mipsShowFullScreen 中
void MainWindow::mipsShowFullScreen()
{
    // ... 动画设置代码 ...
    setWindowState(windowState() | Qt::WindowFullScreen);

    // 断开之前的连接
    if (m_fullScreenAnimationConnection) {
        disconnect(m_fullScreenAnimationConnection);
    }
    
    // 创建新连接并保存
    m_fullScreenAnimationConnection = connect(pAn, &QPropertyAnimation::finished, this, [=](){
        // 全屏时设置绕过合成器
        if (windowHandle()) {
            Utility::setBypassCompositor(windowHandle()->winId(), true);
        }
    });
}

6. 其他建议

  1. 测试覆盖:确保添加针对全屏和绕过合成器功能的单元测试和集成测试。

  2. 文档更新:更新相关文档,说明绕过合成器的行为和效果。

  3. 跨平台考虑:虽然代码中已经检查了 Wayland 环境,但可能还需要考虑其他平台的行为。

  4. 性能监控:添加性能监控代码,验证绕过合成器确实带来了性能提升。

这些改进应该能提高代码的健壮性、可维护性和性能,同时保持功能的一致性。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants