Skip to content

fix: set default cursor when cursor is null#324

Merged
mhduiy merged 1 commit intolinuxdeepin:masterfrom
mhduiy:cursor
Feb 7, 2026
Merged

fix: set default cursor when cursor is null#324
mhduiy merged 1 commit intolinuxdeepin:masterfrom
mhduiy:cursor

Conversation

@mhduiy
Copy link
Contributor

@mhduiy mhduiy commented Feb 7, 2026

When the cursor parameter is null in overrideChangeCursor, the original function call would pass null to QPlatformCursor::changeCursor. This could cause the platform cursor to fall back to the parent window's cursor, which might be incorrect or unintended. By creating a default Qt::ArrowCursor and using it when cursor is null, we ensure a consistent cursor appearance and prevent unexpected cursor behavior.

Log: Fixed cursor display issue when setting null cursor

fix: 当光标为null时设置默认光标

当overrideChangeCursor函数中的cursor参数为null时,原始函数调用会将
null传递给QPlatformCursor::changeCursor。这可能导致平台光标回退到父 窗口的光标,而父窗口的光标可能是错误或不正确的。通过创建一个默认的
Qt::ArrowCursor并在cursor为null时使用它,我们确保了光标外观的一致性,并
防止了意外的光标行为。

Log: 修复设置null光标时的显示问题
PMS: BUG-345829
PMS: BUG-344197

@mhduiy
Copy link
Contributor Author

mhduiy commented Feb 7, 2026

qquickwindow中,当鼠标移动到底层窗口上时,会unsetCursor, 此时传递一个空的QCursor 给平台光标设置,xcbcursor会给 libxcb 设置 XCB_CURSOR_NONE,此时该窗口会复用其父窗口的光标,而父窗口可能是kwin的装饰器窗口或者root窗口,目前kwin就算设置了光标实时更改,Qt的窗口的默认光标也还是一个错误的光标。还没有找到具体原因,此笔提交将设置给平台光标的null手动设置为Qt的默认光标,防止给libxcb设置XCB_CURSOR_NONE,从而fallback到父窗口光标,达到修复的目的。

若之后找到根因,可回退该提交

@mhduiy mhduiy requested a review from 18202781743 February 7, 2026 05:13
When the cursor parameter is null in overrideChangeCursor, the original
function call would pass null to QPlatformCursor::changeCursor. This
could cause the platform cursor to fall back to the parent window's
cursor, which might be incorrect or unintended. By creating a default
Qt::ArrowCursor and using it when cursor is null, we ensure a consistent
cursor appearance and prevent unexpected cursor behavior.

Log: Fixed cursor display issue when setting null cursor

fix: 当光标为null时设置默认光标

当overrideChangeCursor函数中的cursor参数为null时,原始函数调用会将
null传递给QPlatformCursor::changeCursor。这可能导致平台光标回退到父
窗口的光标,而父窗口的光标可能是错误或不正确的。通过创建一个默认的
Qt::ArrowCursor并在cursor为null时使用它,我们确保了光标外观的一致性,并
防止了意外的光标行为。

Log: 修复设置null光标时的显示问题
PMS: BUG-345829
PMS: BUG-344197
@deepin-ci-robot
Copy link
Contributor

deepin pr auto review

这段代码修改的目的是在 cursor 指针为空时,提供一个默认的鼠标光标,而不是直接将空指针传递给底层的 changeCursor 函数。这是一个很好的防御性编程实践,可以防止潜在的空指针解引用或底层处理空指针时的未定义行为。

以下是对这段代码的详细审查意见:

1. 语法与逻辑

  • 现状:逻辑基本正确。它检查了 cursor 是否为空。如果为空,则创建一个临时的 QCursor 对象 defaultCursor 并将其传递下去。
  • 潜在问题(生命周期)
    • else 分支中,QCursor defaultCursor; 是一个局部栈变量
    • 代码通过 VtableHook::callOriginalFun 传递了该栈变量的地址 &defaultCursor
    • 风险:如果 callOriginalFun 内部(即原始的 QPlatformCursor::changeCursor 实现)仅仅是同步读取该指针指向的数据来设置光标形状,那么这是安全的。但如果原始实现将该指针保存起来供后续异步使用(例如存储在某个全局变量中),那么当 overrideChangeCursor 函数返回后,defaultCursor 对象会被销毁,保存的指针将变为悬空指针(Dangling Pointer),后续访问会导致崩溃或未定义行为。
    • 建议:需要确认 Qt 底层 QPlatformCursor::changeCursor 的实现方式。如果它只是同步读取,则当前代码可以接受;如果它存储了指针,则必须修改。

2. 代码质量

  • 可读性:代码结构清晰,if-else 分支意图明确。
  • 默认光标语义QCursor defaultCursor; 调用默认构造函数,通常会创建一个箭头光标(Qt::ArrowCursor)。这符合“回退到默认”的预期。
  • 重复代码VtableHook::callOriginalFun(...) 调用了两次,参数列表大部分相同。虽然在这里不算严重问题,但可以通过调整逻辑减少冗余。

3. 代码性能

  • 开销:在 cursor 为空的情况下,每次调用都会在栈上构造一个 QCursor 对象。QCursor 的构造涉及轻量级的资源引用,开销极小,通常不会造成性能问题。
  • 建议:无需优化,除非该函数被极高频率地调用且 cursor 为空的情况非常频繁。

4. 代码安全

  • 空指针检查:增加了对 cursor 的检查,有效防止了将 nullptr 传递给底层函数,提高了健壮性。
  • 悬空指针风险:如上所述,这是最大的安全隐患。如果底层函数持有指针,必须使用静态或动态分配的内存。

改进建议

方案一:确保指针有效性(推荐,假设底层不持有指针)

如果确定底层函数只是同步读取,当前的代码是可以的,但为了更安全和明确,可以使用 static 变量确保该对象在程序生命周期内一直存在,彻底消除悬空指针的风险。

    // 使用 static 变量确保 defaultCursor 的生命周期贯穿整个程序运行期
    // 这样即使底层函数异步访问该指针也是安全的
    static QCursor defaultCursor; 
    
    // 如果 cursor 为空,则使用 defaultCursor 的地址,否则使用传入的 cursor
    QCursor *effectiveCursor = cursor ? cursor : &defaultCursor;
    
    VtableHook::callOriginalFun(cursorHandle, &QPlatformCursor::changeCursor, effectiveCursor, widget);

优点

  1. 消除悬空指针风险static 对象在程序启动时初始化,结束时销毁,永远有效。
  2. 代码更简洁:消除了重复的 callOriginalFun 调用。
  3. 性能更好:避免了每次进入 else 分支时都构造临时对象(虽然构造开销很小,但省去总是好的)。

方案二:明确指定默认光标类型

如果不想依赖 QCursor 默认构造函数的行为(以防未来 Qt 版本修改默认行为),可以显式指定。

    static QCursor defaultCursor(Qt::ArrowCursor);
    QCursor *effectiveCursor = cursor ? cursor : &defaultCursor;
    VtableHook::callOriginalFun(cursorHandle, &QPlatformCursor::changeCursor, effectiveCursor, widget);

总结

原代码的修复方向是正确的(防止空指针),但存在因局部变量生命周期导致的潜在悬空指针风险。强烈建议采用方案一,利用 static 局部变量来替代栈上的临时变量,这样既安全又简洁。

@deepin-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, mhduiy

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

@mhduiy mhduiy merged commit 0bae7d6 into linuxdeepin:master Feb 7, 2026
20 of 21 checks passed
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.

3 participants