Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GNOME 46 #341

Merged
merged 11 commits into from
Feb 27, 2024
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
matrix:
version:
- "39"
#- "rawhide"
- "rawhide"
session:
- "gnome-xsession"
- "gnome-wayland-nested"
Expand Down
11 changes: 10 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,18 @@ SPDX-License-Identifier: CC-BY-4.0

#### Enhancements

- The extension has been updated to work with GNOME 46. Some refactoring was required, so please report any issues you encounter!
- Instead of an always out-of-date list of sponsors, the main menu of the preferences dialog now contains a link to the new [list of all donors](https://schneegans.github.io/sponsors/). This list is semi-automatically updated whenever a new donation is received. Thanks to all the donors!
- Several translation updates. Thanks to all the translators!
- All CI jobs are now executed for GNOME 45 as well.
- All CI jobs are now executed for GNOME 45 and GNOME 46 as well.

#### Changes

- Due to the removal of `Clutter.Canvas` in GNOME 46, the icons of the menu are now drawn with a `St.DrawingArea`. This brings some subtle changes for the menu item transitions when hovering or selecting items.

#### Bug Fixes

- Fixed a regression which caused an error when trying to load theme presets in the settings dialog.

## [Fly-Pie 24](https://github.com/schneegans/fly-pie/releases/tag/v24)

Expand Down
5 changes: 3 additions & 2 deletions metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
"gettext-domain": "flypie",
"settings-schema": "org.gnome.shell.extensions.flypie",
"shell-version": [
"45"
"45",
"46"
],
"url": "https://github.com/Schneegans/Fly-Pie",
"version": 24
"version": 25
}
12 changes: 10 additions & 2 deletions src/extension/Background.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,16 @@ class Background extends Clutter.Actor {
width: 100,
layout_manager: new Clutter.BoxLayout(boxLayoutParams)
});
box.add_actor(icon);
box.add_actor(label);

// Starting from GNOME 46, the add_actor method is removed. We need to use add_child
// instead.
if (box.add_actor) {
box.add_actor(icon);
box.add_actor(label);
} else {
box.add_child(icon);
box.add_child(label);
}

const button = new St.Button({style_class: 'app-well-app'});
button.set_child(box);
Expand Down
62 changes: 29 additions & 33 deletions src/extension/MenuItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Pango from 'gi://Pango';
import PangoCairo from 'gi://PangoCairo';
import GdkPixbuf from 'gi://GdkPixbuf';
import Cairo from 'gi://cairo';
import St from 'gi://St';

import * as utils from '../common/utils.js';

Expand Down Expand Up @@ -633,16 +634,6 @@ class MenuItem extends Clutter.Actor {
updateOpacity(MenuItemState.GRANDCHILD);
updateOpacity(MenuItemState.GRANDCHILD_HOVERED);

// Now update the size of the icon container. As there is a layout manager in action,
// all icons will update their size accordingly.
this._iconContainer.set_easing_duration(easingDuration);
this._iconContainer.set_easing_mode(MenuItemSettings.easingMode);

const size2 = Math.floor(settings.size / 2);
this._iconContainer.set_translation(-size2, -size2, 0);
this._iconContainer.set_size(100, 100);
this._iconContainer.set_scale(settings.size / 100, settings.size / 100);

// Now we update the trace line to the active child if we are in a parent state.
if (this._state == MenuItemState.PARENT ||
this._state == MenuItemState.PARENT_HOVERED) {
Expand Down Expand Up @@ -702,10 +693,11 @@ class MenuItem extends Clutter.Actor {
// We need to create the _trace actor if it's not there yet.
if (this._trace == undefined) {
this._traceContainer = new Clutter.Actor();
this._trace = new Clutter.Actor({width: 1});
this._trace = new St.DrawingArea({width: 1});
this._trace.connect('repaint', (canvas) => {
const ctx = canvas.get_context();
const [width, height] = canvas.get_surface_size();

const canvas = new Clutter.Canvas();
canvas.connect('draw', (canvas, ctx, width, height) => {
ctx.setOperator(Cairo.Operator.CLEAR);
ctx.paint();
ctx.setOperator(Cairo.Operator.OVER);
Expand All @@ -725,7 +717,6 @@ class MenuItem extends Clutter.Actor {
ctx.$dispose();
});

this._trace.set_content(canvas);
this.insert_child_below(this._traceContainer, null);
this._traceContainer.add_child(this._trace);
}
Expand Down Expand Up @@ -829,15 +820,20 @@ class MenuItem extends Clutter.Actor {
return null;
}

// This creates a Clutter.Actor with an attached Clutter.Canvas containing an image of
// this MenuItem's icon. It's static so that others can use this to create similar icons
// (for example the touch buttons).
// This creates a Clutter.Actor containing an image of this MenuItem's icon. It's static
// so that others can use this to create similar icons (for example the touch buttons).
static createIcon(
backgroundColor, backgroundImage, backgroundSize, iconName, iconScale, iconCrop,
iconOpacity, label, labelScale, textColor, font, labelFont) {

const canvas = new Clutter.Canvas({height: backgroundSize, width: backgroundSize});
canvas.connect('draw', (c, ctx, width, height) => {
const actor = new St.DrawingArea({
height: backgroundSize,
width: backgroundSize,
});

actor.connect('repaint', (canvas) => {
const ctx = canvas.get_context();

// Clear any previous content.
ctx.setOperator(Cairo.Operator.CLEAR);
ctx.paint();
Expand Down Expand Up @@ -975,20 +971,6 @@ class MenuItem extends Clutter.Actor {
ctx.$dispose();
});

// Apply HiDPI scaling and trigger an initial 'draw' signal emission. The call to
// set_scale_factor() will automatically invalidate the canvas.
if (utils.getHDPIResourceScale() != 1) {
canvas.set_scale_factor(utils.getHDPIResourceScale());
} else {
canvas.invalidate();
}

// Create a new actor and set the icon canvas to be its content.
const actor = new Clutter.Actor();
actor.set_content(canvas);
actor.set_x_expand(true);
actor.set_y_expand(true);

return actor;
}

Expand Down Expand Up @@ -1032,6 +1014,20 @@ class MenuItem extends Clutter.Actor {
this._trace.get_content().invalidate();
}

// Compute the icon container's size and position. We use the maximum size of all icon
// variants.
const maxSize = Math.max(
MenuItemSettings.state.get(MenuItemState.CENTER).size,
MenuItemSettings.state.get(MenuItemState.CENTER_HOVERED).size,
MenuItemSettings.state.get(MenuItemState.CHILD).size,
MenuItemSettings.state.get(MenuItemState.CHILD_HOVERED).size,
MenuItemSettings.state.get(MenuItemState.GRANDCHILD).size,
MenuItemSettings.state.get(MenuItemState.GRANDCHILD_HOVERED).size);

const size2 = Math.floor(maxSize / 2);
this._iconContainer.set_size(maxSize, maxSize);
this._iconContainer.set_translation(-size2, -size2, 0);

// Finally, call this recursively for all children.
this._childrenContainer.get_children().forEach(child => child._onSettingsChange());
}
Expand Down
21 changes: 6 additions & 15 deletions src/extension/MouseHighlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Clutter from 'gi://Clutter';
import Cairo from 'gi://cairo';
import St from 'gi://St';

import * as utils from '../common/utils.js';

Expand All @@ -38,7 +39,7 @@ export var MouseHighlight = GObject.registerClass({
Properties: {},
Signals: {}
},
class MouseHighlight extends Clutter.Actor {
class MouseHighlight extends St.DrawingArea {
// clang-format on

// ------------------------------------------------------------ constructor /
Expand All @@ -52,8 +53,9 @@ class MouseHighlight extends Clutter.Actor {
this._mods = 0;

// The pointer is drawn to this canvas.
this._canvas = new Clutter.Canvas();
this._canvas.connect('draw', (canvas, ctx, width, height) => {
this.connect('repaint', (canvas) => {
const ctx = canvas.get_context();

ctx.setOperator(Cairo.Operator.CLEAR);
ctx.paint();
ctx.setOperator(Cairo.Operator.OVER);
Expand Down Expand Up @@ -126,21 +128,10 @@ class MouseHighlight extends Clutter.Actor {
ctx.$dispose();
});

this._canvas.set_size(size, size);

// Apply HiDPI scaling and trigger an initial 'draw' signal emission. The call to
// set_scale_factor() will automatically invalidate the canvas.
if (utils.getHDPIResourceScale() != 1) {
this._canvas.set_scale_factor(utils.getHDPIResourceScale());
} else {
this._canvas.invalidate();
}

// Set the size of the anchor. For some reason a small offset is required to make
// it exactly match the original mouse pointer's position.
this.set_size(size, size);
this.set_translation(-3, -3, 0);
this.set_content(this._canvas);

// Update the position of the pointer at 100 Hz.
this._updateTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 10, () => {
Expand All @@ -149,7 +140,7 @@ class MouseHighlight extends Clutter.Actor {

if (this._mods != mods) {
this._mods = mods;
this._canvas.invalidate();
this.queue_repaint();
}

return true;
Expand Down
70 changes: 34 additions & 36 deletions src/extension/SelectionWedges.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import GLib from 'gi://GLib';
import Clutter from 'gi://Clutter';
import GObject from 'gi://GObject';
import Cairo from 'gi://cairo';
import St from 'gi://St';

import * as utils from '../common/utils.js';

Expand Down Expand Up @@ -162,33 +163,6 @@ class SelectionWedges extends Clutter.Actor {
this._wedgeActor.add_effect(this._wedgeShader);
this.add_child(this._wedgeActor);

// Now we create the Clutter.Canvas which will be used by the separator actors. It
// just contains a simple line with a gradient.
this._separatorCanvas = new Clutter.Canvas();
this._separatorCanvas.connect('draw', (canvas, ctx, width, height) => {
ctx.setOperator(Cairo.Operator.CLEAR);
ctx.paint();
ctx.setOperator(Cairo.Operator.OVER);

const gradient =
new Cairo.LinearGradient(this._settings.wedgeInnerRadius, 0, width, 0);
const color = this._settings.wedgeSeparatorColor;
gradient.addColorStopRGBA(
0, color.red / 255, color.green / 255, color.blue / 255, color.alpha / 255);
gradient.addColorStopRGBA(
1, color.red / 255, color.green / 255, color.blue / 255, 0);

ctx.setLineWidth(this._settings.wedgeSeparatorWidth);
ctx.setLineCap(Cairo.LineCap.ROUND);
ctx.moveTo(this._settings.wedgeInnerRadius, height / 2);
ctx.lineTo(width, height / 2);
ctx.setSource(gradient);
ctx.stroke();

// Explicitly tell Cairo to free the context memory. Is this really necessary?
ctx.$dispose();
});

// This actor acts as a group for all separators so that we can easily iterate
// over them and destroy them once we're done.
this._separators = new Clutter.Actor();
Expand Down Expand Up @@ -226,18 +200,13 @@ class SelectionWedges extends Clutter.Actor {
this._wedgeActor.set_size(outerRadius * 2, outerRadius * 2);
this._wedgeActor.set_translation(-outerRadius, -outerRadius, 0);

// Update and re-draw the separator canvas.
this._separatorCanvas.set_size(
this._settings.wedgeInnerRadius + this._settings.wedgeWidth,
this._settings.wedgeSeparatorWidth + 5);
this._separatorCanvas.invalidate();

// Update the size and position of all separator actors.
this._separators.get_children().forEach(child => {
child.set_size(
this._settings.wedgeInnerRadius + this._settings.wedgeWidth,
this._settings.wedgeSeparatorWidth + 5);
child.translation_y = -child.height / 2;
child.queue_repaint();
});

// This could be shortened if we could set vec4's as uniforms...
Expand Down Expand Up @@ -338,17 +307,46 @@ class SelectionWedges extends Clutter.Actor {
const separatorAngle = (startAngle + endAngle) / 2;
this._separatorAngles.push(separatorAngle);

// Now create the separator actor and rotate it according to the angle.
const separator = new Clutter.Actor({
// Now create the separator actor and rotate it according to the angle. It
// just contains a simple line with a gradient.
const separator = new St.DrawingArea({
width: this._settings.wedgeInnerRadius + this._settings.wedgeWidth,
height: this._settings.wedgeSeparatorWidth + 5
});

separator.connect('repaint', (canvas) => {
const ctx = canvas.get_context();
const [width, height] = canvas.get_surface_size();

ctx.setOperator(Cairo.Operator.CLEAR);
ctx.paint();
ctx.setOperator(Cairo.Operator.OVER);

const gradient =
new Cairo.LinearGradient(this._settings.wedgeInnerRadius, 0, width, 0);
const color = this._settings.wedgeSeparatorColor;
gradient.addColorStopRGBA(
0, color.red / 255, color.green / 255, color.blue / 255,
color.alpha / 255);
gradient.addColorStopRGBA(
1, color.red / 255, color.green / 255, color.blue / 255, 0);

ctx.setLineWidth(this._settings.wedgeSeparatorWidth);
ctx.setLineCap(Cairo.LineCap.ROUND);
ctx.moveTo(this._settings.wedgeInnerRadius, height / 2);
ctx.lineTo(width, height / 2);
ctx.setSource(gradient);
ctx.stroke();

// Explicitly tell Cairo to free the context memory. Is this really
// necessary?
ctx.$dispose();
});

// Turn by 90° as 0° is up in our case.
separator.rotation_angle_z = separatorAngle - 90;
separator.translation_y = -separator.height / 2;
separator.set_pivot_point(0, 0.5);
separator.set_content(this._separatorCanvas);
this._separators.add_child(separator);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/prefs/Preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import Gio from 'gi://Gio';
import Gdk from 'gi://Gdk';

import * as utils from '../common/utils.js';

//////////////////////////////////////////////////////////////////////////////////////////
// Presets of Fly-Pie are stored in the JSON format. These files contain values for a //
// subset of Fly-Pie's settings. The subset is defined in the presetKeys list below. //
Expand Down
2 changes: 1 addition & 1 deletion tests/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ do_in_pod 'echo "export GSK_RENDERER=cairo" >> .bash_profile'
# ----------------------------------------------------- wait for the container to start up

echo "Waiting for D-Bus."
do_in_pod wait-user-bus.sh > /dev/null 2>&1
sleep 5


# ----------------------------------------------------- install the to-be-tested extension
Expand Down
Loading