From 03fdef133e213677c542c33ae372f7ca2631e61f Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 10 Nov 2021 16:38:28 +0100 Subject: macOS: Fix QSlider's knob positioning on Monterey QMacStyle has a single NSSlider that is used to render any QSlider. For each QStyle API operating on a slider, the style sets the slider up with respecive properties. On macOS 12, the NSSlider maintains some states that make QSlider instances influence each other's knob position when rendering, resulting in uncontrollable jumping of the slider. This can be fixed by not using startTrackingAt/stopTracking APIs, which are however the only way we have to make the slider knob get rendered pressed - there is no property in NSSlider(Cell), and none of the NSCell attributes have any effect. So we need to use startTrackingAt, and work around the side effect by reinitializing the NSSlider by calling initWithFrame. This fixes the positioning error, but also causes flickering of the knob when dragging. To fix the flickering, we have to always call startTrackingAt for a slider that is pressed, even for calls to setupSlider that are made in QStyle APIs that are not drawing anything. Also tried with no complete success (either positiong bug or flicker): * call prepareForReuse on the NSView * always call stopTracking on the NSSlider Fixes: QTBUG-98093 Change-Id: I3423b9f7cb125a59831c6722509ab3b74742b6ae Reviewed-by: Timur Pocheptsov (cherry picked from commit 4bee9cdc0ac4bbee7f061e8f6050d704032f6d0f) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/styles/mac/qmacstyle_mac.mm | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index f2919ec1b5..ed89ccb528 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -467,7 +467,11 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl) if (sl->minimum >= sl->maximum) return false; - slider.frame = sl->rect.toCGRect(); + // NSSlider seems to cache values based on tracking and the last layout of the + // NSView, resulting in incorrect knob rects that break the interaction with + // multiple sliders. So completely reinitialize the slider. + [slider initWithFrame:sl->rect.toCGRect()]; + slider.minValue = sl->minimum; slider.maxValue = sl->maximum; slider.intValue = sl->sliderPosition; @@ -497,6 +501,14 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl) // the cell for its metrics and to draw itself. [slider layoutSubtreeIfNeeded]; + if (sl->state & QStyle::State_Sunken) { + const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped]; + CGPoint pressPoint; + pressPoint.x = CGRectGetMidX(knobRect); + pressPoint.y = CGRectGetMidY(knobRect); + [slider.cell startTrackingAt:pressPoint inView:slider]; + } + return true; } -- cgit v1.2.3