Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ def config_orca(button):
switch = GSettingsSwitch(_("Lens mode"), "org.cinnamon.desktop.a11y.magnifier", "lens-mode")
settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")

switch = GSettingsSwitch(_("Smoothing"), "org.cinnamon.desktop.a11y.magnifier", "smoothing")
switch.set_tooltip_text(_("Disable to see true pixels of display image."))
settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")

self.zoom_stack = SettingsStack()
self.zoom_stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)

Expand Down
101 changes: 94 additions & 7 deletions js/ui/magnifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const MAGNIFIER_SCHEMA = 'org.cinnamon.desktop.a11y.magnifier';
const SCREEN_POSITION_KEY = 'screen-position';
const MAG_FACTOR_KEY = 'mag-factor';
const LENS_MODE_KEY = 'lens-mode';
const SMOOTHING_KEY = 'smoothing';
const LENS_SHAPE_KEY = 'lens-shape';
const CLAMP_MODE_KEY = 'scroll-at-edges';
const MOUSE_TRACKING_KEY = 'mouse-tracking';
Expand Down Expand Up @@ -212,6 +213,11 @@ var Magnifier = class Magnifier {
this._mouseSprite.content = new MouseSpriteContent();
this._cursorTracker = cursorTracker;

// Set the monitor scale so the cursor texture is decoded at the
// correct size on HiDPI / fractional-scale displays.
this._mouseSprite.content.monitorScale =
St.ThemeContext.get_for_stage(global.stage).scale_factor;

this._updateMouseSprite();

this._cursorRoot = new Clutter.Actor();
Expand All @@ -221,6 +227,11 @@ var Magnifier = class Magnifier {

cursorTracker.connect('cursor-changed', this._updateMouseSprite.bind(this));

// A resolution or scale change invalidates the screen geometry the
// zoom regions cached at activation, so refresh them when it happens.
this._monitorsChangedId = Main.layoutManager.connect('monitors-changed',
this._monitorsChanged.bind(this));

// Create the first ZoomRegion and initialize it according to the
// magnification settings.
let aZoomRegion = new ZoomRegion(this, this._cursorRoot);
Expand Down Expand Up @@ -648,6 +659,7 @@ var Magnifier = class Magnifier {

zoomRegion.setLensMode(this._settings.get_boolean(LENS_MODE_KEY));
zoomRegion.setClampScrollingAtEdges(!this._settings.get_boolean(CLAMP_MODE_KEY));
zoomRegion.setSmoothing(this._settings.get_boolean(SMOOTHING_KEY));

this._updateZoomRegion(zoomRegion)

Expand All @@ -672,6 +684,8 @@ var Magnifier = class Magnifier {
this._updateClampMode.bind(this));
this._settings.connect('changed::' + MOUSE_TRACKING_KEY,
this._updateMouseTrackingMode.bind(this));
this._settings.connect('changed::' + SMOOTHING_KEY,
this._updateSmoothing.bind(this));

this._settings.connect('changed::' + SHOW_CROSS_HAIRS_KEY, () => {
this.setCrosshairsVisible(this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY));
Expand Down Expand Up @@ -700,6 +714,16 @@ var Magnifier = class Magnifier {
return ret > 1.0;
}

_monitorsChanged() {
if (!this._initialized)
return;

this._mouseSprite.content.monitorScale =
St.ThemeContext.get_for_stage(global.stage).scale_factor;

this._zoomRegions.forEach(zoomRegion => zoomRegion.refreshGeometry());
}

_updateScreenPosition() {
// Applies only to the first zoom region.
if (this._zoomRegions.length) {
Expand Down Expand Up @@ -736,6 +760,13 @@ var Magnifier = class Magnifier {
}
}

_updateSmoothing() {
// Applies only to the first zoom region.
if (this._zoomRegions.length) {
this._zoomRegions[0].setSmoothing(this._settings.get_boolean(SMOOTHING_KEY));
}
}

_updateClampMode() {
// Applies only to the first zoom region.
if (this._zoomRegions.length) {
Expand Down Expand Up @@ -763,6 +794,7 @@ var ZoomRegion = class ZoomRegion {
this._mouseTrackingMode = MouseTrackingMode.NONE;
this._clampScrollingAtEdges = false;
this._lensMode = false;
this._smoothing = true;
this._screenPosition = ScreenPosition.FULL_SCREEN;
this._lensShape = LensShape.NONE;
this._magView = null;
Expand Down Expand Up @@ -821,7 +853,7 @@ var ZoomRegion = class ZoomRegion {
setMagFactor(xMagFactor, yMagFactor) {
this._changeROI({ xMagFactor: xMagFactor,
yMagFactor: yMagFactor,
redoCursorTracking: this._followingCursor });
redoCursorTracking: this._mouseTrackingMode != MouseTrackingMode.NONE });
}

/**
Expand Down Expand Up @@ -922,6 +954,28 @@ var ZoomRegion = class ZoomRegion {
return this._lensMode;
}

/**
* setSmoothing:
* Toggle linear (smooth) vs nearest-neighbor (true pixel) filtering of the
* magnified content.
* @smoothing: Boolean; true = smooth interpolation, false = nearest pixel.
*/
setSmoothing(smoothing) {
this._smoothing = smoothing;
let filter = smoothing ? Clutter.ScalingFilter.LINEAR
: Clutter.ScalingFilter.NEAREST;
let redirect = smoothing ? Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY
: Clutter.OffscreenRedirect.ALWAYS;
if (this._magClip) {
this._magClip.set_offscreen_redirect(redirect);
this._magClip.set_content_scaling_filters(filter, filter);
}
if (this._magnifier._mouseSprite)
this._magnifier._mouseSprite.set_offscreen_redirect(redirect);
if (this._mouseActor)
this._mouseActor.set_content_scaling_filters(filter, filter);
}

/**
* setClampScrollingAtEdges:
* Stop vs. allow scrolling of the magnified contents when it scroll beyond
Expand Down Expand Up @@ -1076,6 +1130,26 @@ var ZoomRegion = class ZoomRegion {
}
}

/**
* refreshGeometry:
* Re-sync the zoom region with the current screen dimensions after a
* resolution or scale change. Re-applying the screen position recomputes
* the viewport from the new global.screen_width/height; if the region is
* active, the actors (magnified view, uiGroup clone, background) are
* rebuilt at the new size by cycling activation, which preserves the
* current magnification factor.
*/
refreshGeometry() {
let wasActive = this.isActive();
if (wasActive)
this.setActive(false);

this.setScreenPosition(this._screenPosition);

if (wasActive)
this.setActive(true);
}

/**
* setLensShape:
* Sets the shape of the zoom lens
Expand Down Expand Up @@ -1187,10 +1261,16 @@ var ZoomRegion = class ZoomRegion {
});
mainGroup.add_child(background);

// Clone the group that contains all of UI on the screen. This is the
// chrome, the windows, etc.
// Clone the group that contains all of UI on the screen (the chrome,
// the windows, etc.). The clone is wrapped in a screen-sized,
// clip-to-allocation actor (_magClip) which carries the magnification
// transform and, in nearest-pixel mode, the offscreen redirect.
this._magClip = new Clutter.Actor({ clip_to_allocation: true,
width: global.screen_width,
height: global.screen_height });
mainGroup.add_child(this._magClip);
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
mainGroup.add_child(this._uiGroupClone);
this._magClip.add_child(this._uiGroupClone);
Main.uiGroup.set_size(global.screen_width, global.screen_height);

// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
Expand All @@ -1201,6 +1281,9 @@ var ZoomRegion = class ZoomRegion {
this._mouseActor = this._mouseSourceActor;
mainGroup.add_child(this._mouseActor);

// Apply the configured scaling filter (smooth vs nearest-pixel).
this.setSmoothing(this._smoothing);

if (this._crossHairs)
this._crossHairsActor = this._crossHairs.addToZoomRegion(this, this._mouseActor);
else
Expand All @@ -1213,8 +1296,12 @@ var ZoomRegion = class ZoomRegion {
if (this._crossHairs)
this._crossHairs.removeFromParent(this._crossHairsActor);

if (this._magnifier._mouseSprite)
this._magnifier._mouseSprite.set_offscreen_redirect(Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);

this._magView.destroy();
this._magView = null;
this._magClip = null;
this._uiGroupClone = null;
this._mouseActor = null;
this._crossHairsActor = null;
Expand Down Expand Up @@ -1270,7 +1357,7 @@ var ZoomRegion = class ZoomRegion {
[params.xCenter, params.yCenter] = this._centerFromMousePosition();
}

if (this._clampScrollingAtEdges) {
if (this._clampScrollingAtEdges || this._isFullScreen()) {
let roiWidth = this._viewPortWidth / this._xMagFactor;
let roiHeight = this._viewPortHeight / this._yMagFactor;

Expand Down Expand Up @@ -1411,11 +1498,11 @@ var ZoomRegion = class ZoomRegion {
if (!this.isActive())
return;

this._uiGroupClone.set_scale(this._xMagFactor, this._yMagFactor);
this._magClip.set_scale(this._xMagFactor, this._yMagFactor);
this._mouseActor.set_scale(this._xMagFactor, this._yMagFactor);

let [x, y] = this._screenToViewPort(0, 0);
this._uiGroupClone.set_position(x, y);
this._magClip.set_position(x, y);

this._updateMousePosition();
}
Expand Down
Loading