Skip to content

Commit

Permalink
macOS: Fix QSlider's knob positioning on Monterey
Browse files Browse the repository at this point in the history
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
Pick-to: 6.2 6.2.2
Change-Id: I3423b9f7cb125a59831c6722509ab3b74742b6ae
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
(cherry picked from commit 4bee9cd)
  • Loading branch information
vohi authored and AlienCowEatCake committed Jul 20, 2023
1 parent e919767 commit 1b8440d
Showing 1 changed file with 13 additions and 1 deletion.
14 changes: 13 additions & 1 deletion src/plugins/styles/mac/qmacstyle_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,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;
Expand Down Expand Up @@ -498,6 +502,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;
}

Expand Down

0 comments on commit 1b8440d

Please sign in to comment.