| 3279 | } |
| 3280 | |
| 3281 | bool MainWindow::eventFilter(QObject* watched, QEvent* event) { |
| 3282 | const QEvent::Type type = event->type(); |
| 3283 | // QTipLabel is the internal widget Qt creates for tooltips. On Linux |
| 3284 | // KWin / Mutter normally paint a drop shadow around any tool/popup |
| 3285 | // window; setting Qt::NoDropShadowWindowHint asks the platform plugin |
| 3286 | // to suppress it. Polish fires once before the first show and the |
| 3287 | // QTipLabel is reused for all tooltips, so a single tweak covers |
| 3288 | // every subsequent tooltip. |
| 3289 | if (type == QEvent::Polish && watched->inherits("QTipLabel")) { |
| 3290 | if (auto* w = qobject_cast<QWidget*>(watched)) { |
| 3291 | w->setWindowFlag(Qt::NoDropShadowWindowHint, true); |
| 3292 | } |
| 3293 | return false; |
| 3294 | } |
| 3295 | // The align rail sits in the window's bottom-right corner, where the default |
| 3296 | // tooltip placement needs an upward flip that fails under Wayland. Show the |
| 3297 | // rail's tooltips ourselves, to the left of the rail and clamped on-screen. |
| 3298 | if (type == QEvent::ToolTip) { |
| 3299 | auto* btn = qobject_cast<QToolButton*>(watched); |
| 3300 | if (btn != nullptr && ui_->timelineAlignRail != nullptr && btn->parentWidget() == ui_->timelineAlignRail && |
| 3301 | !btn->toolTip().isEmpty()) { |
| 3302 | const QFontMetrics fm(QToolTip::font()); |
| 3303 | const QSize tip_size = fm.size(Qt::TextSingleLine, btn->toolTip()) + QSize(12, 8); // ~QTipLabel chrome |
| 3304 | const QPoint btn_top_left = btn->mapToGlobal(QPoint(0, 0)); |
| 3305 | QPoint pos( |
| 3306 | btn_top_left.x() - tip_size.width() - 4, // just left of the rail |
| 3307 | btn_top_left.y() + (btn->height() - tip_size.height()) / 2); // vertically centered on the button |
| 3308 | if (const QScreen* screen = btn->screen()) { |
| 3309 | const QRect avail = screen->availableGeometry(); |
| 3310 | pos.setX(std::clamp(pos.x(), avail.left() + 4, avail.right() - tip_size.width() - 4)); |
| 3311 | pos.setY(std::clamp(pos.y(), avail.top() + 4, avail.bottom() - tip_size.height() - 4)); |
| 3312 | } |
| 3313 | QToolTip::showText(pos, btn->toolTip(), btn); |
| 3314 | return true; |
| 3315 | } |
| 3316 | return false; |
| 3317 | } |
| 3318 | if (type != QEvent::MouseMove && type != QEvent::MouseButtonPress) { |
| 3319 | return false; |
| 3320 | } |
| 3321 | // Only act on mouse events that target a widget in this window. |
| 3322 | auto* widget = qobject_cast<QWidget*>(watched); |
| 3323 | if (widget == nullptr || widget->window() != this) { |
| 3324 | return false; |
| 3325 | } |
| 3326 | if (isMaximized() || isFullScreen()) { |
| 3327 | return false; |
| 3328 | } |
| 3329 | |
| 3330 | auto* mouse_event = static_cast<QMouseEvent*>(event); |
| 3331 | const QPoint window_pos = mapFromGlobal(mouse_event->globalPosition().toPoint()); |
| 3332 | const Qt::Edges edges = edgesAtPoint(size(), window_pos); |
| 3333 | |
| 3334 | if (type == QEvent::MouseMove) { |
| 3335 | if (edges != 0) { |
| 3336 | setCursor(cursorForEdges(edges)); |
| 3337 | } else { |
| 3338 | unsetCursor(); |