diff --git a/package.json b/package.json
index 292d246..788e59c 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "gnome-gradienttopbar",
"title": "Gradient Top Bar",
"description": "Makes GNOME's panel's background gradient. You can edit the colour scheme from the extension's settings in Gnome 45.",
- "version": "22",
+ "version": "23-rc",
"engines": {
"gnome": ">=47"
},
diff --git a/src/config.js b/src/config.js
index d65f836..1013447 100644
--- a/src/config.js
+++ b/src/config.js
@@ -20,6 +20,7 @@ export const MAXIMIZED_COLORS = 'maximized-colors';
* @returns {Object} The complete configuration object
*/
export const getConfig = settings => {
+ const maximizationType = settings.get_string('maximization-type');
const maximizedBehavior = settings.get_string(MAXIMIZED_BEHAVIOR);
const colors = settings.get_value(COLORS).deep_unpack();
const gradientDirection = settings.get_string(GRADIENT_DIRECTION);
@@ -28,6 +29,7 @@ export const getConfig = settings => {
return {
maximizedBehavior,
+ maximizationType,
gradientDirection,
colors: {
start: colors[0],
@@ -152,6 +154,7 @@ export const saveMaximizedColors = (settings, startRgba, endRgba) => {
export const attachSettingsListeners = (settings, listener) => {
settings.connect(`changed::${GRADIENT_DIRECTION}`, listener);
settings.connect(`changed::${MAXIMIZED_BEHAVIOR}`, listener);
+ settings.connect('changed::maximization-type', listener);
settings.connect(`changed::${COLORS}`, listener);
settings.connect(`changed::${MAXIMIZED_COLORS}`, listener);
settings.connect(`changed::${MAXIMIZED_GRADIENT_DIRECTION}`, listener);
@@ -166,6 +169,7 @@ export const attachSettingsListeners = (settings, listener) => {
export const detachSettingsListeners = (settings, listener) => {
settings.disconnect(`changed::${GRADIENT_DIRECTION}`, listener);
settings.disconnect(`changed::${MAXIMIZED_BEHAVIOR}`, listener);
+ settings.disconnect('changed::maximization-type', listener);
settings.disconnect(`changed::${COLORS}`, listener);
settings.disconnect(`changed::${MAXIMIZED_COLORS}`, listener);
settings.disconnect(`changed::${MAXIMIZED_GRADIENT_DIRECTION}`, listener);
diff --git a/src/constants.js b/src/constants.js
index 4e99d52..d43964b 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -9,6 +9,14 @@ export const MAXIMIZED_BEHAVIOR = {
APPLY_STYLE: 'apply-style'
};
+// Maximization type constants
+export const MAXIMIZATION_TYPE = {
+ BOTH: 'both',
+ VERTICAL: 'vertical',
+ HORIZONTAL: 'horizontal',
+ ANY: 'any'
+};
+
// Gradient directions
export const GRADIENT_DIRECTION = {
VERTICAL: 'vertical',
diff --git a/src/events/windowEvents.js b/src/events/windowEvents.js
index d85b4f0..5f43ea1 100644
--- a/src/events/windowEvents.js
+++ b/src/events/windowEvents.js
@@ -3,8 +3,9 @@ import { overview } from 'resource:///org/gnome/shell/ui/main.js';
import EventManager from './eventManager.js';
import { areSameState } from './states.js';
+import { MAXIMIZATION_TYPE } from '../constants.js';
-const { VERTICAL, BOTH } = Meta.MaximizeFlags;
+const { VERTICAL, HORIZONTAL, BOTH } = Meta.MaximizeFlags;
const SIZE_CHANGE_EVENT = 'size-changed';
const WORKSPACE_CHANGE_EVENT = 'workspace-switched';
@@ -24,26 +25,37 @@ const OVERVIEW_HIDING = 'hiding';
// FIXME: this causes the overview to close on login
const isDesktopIconsNG = window => window.customJS_ding !== undefined; // this is to ignore "Desktop Icons NG"'s window hacks
+// Check if window is full screen or monitor sized
+const isFullScreen = window => window.is_monitor_sized() || window.is_screen_sized();
+
/**
* Determines if a window is maximized or full-screen
*
* @param {Meta.Window} window - The window to check
+ * @param {string} maximizationType - Maximization type definition
* @returns {boolean} True if the window is maximized or full-screen
*/
-const isMaximized = window => {
+const isMaximized = (window, maximizationType = MAXIMIZATION_TYPE.BOTH) => {
// Ignore Desktop Icons NG windows
if (isDesktopIconsNG(window))
return false;
-
- // Check if window is full-screen
- if (window.is_monitor_sized() || window.is_screen_sized())
- return true;
-
-
- // Check if window is maximized (either vertically or both dimensions)
- const maximizeFlags = window.get_maximized();
- return [BOTH, VERTICAL].includes(maximizeFlags);
+ const windowMaximizeState = window.get_maximized();
+
+ switch (maximizationType) {
+ case MAXIMIZATION_TYPE.BOTH:
+ return windowMaximizeState === BOTH || isFullScreen(window);
+ case MAXIMIZATION_TYPE.VERTICAL:
+ return windowMaximizeState === VERTICAL || windowMaximizeState === BOTH;
+ case MAXIMIZATION_TYPE.HORIZONTAL:
+ return windowMaximizeState === HORIZONTAL || windowMaximizeState === BOTH;
+ case MAXIMIZATION_TYPE.ANY:
+ return windowMaximizeState === VERTICAL ||
+ windowMaximizeState === HORIZONTAL ||
+ windowMaximizeState === BOTH || isFullScreen(window);
+ default:
+ return windowMaximizeState === BOTH;
+ }
};
/**
@@ -70,6 +82,7 @@ export default class WindowEvents {
this.workspace = null;
this.inOverview = false;
this.maximizedWindows = new Set();
+ this.maximizationType = MAXIMIZATION_TYPE.BOTH; // Default value
this.lastState = null;
}
@@ -82,6 +95,23 @@ export default class WindowEvents {
this.stateChangeCallback = callback;
}
+ setMaximizationType(type) {
+ this.maximizationType = type;
+ this.forceStateUpdate();
+ }
+
+ forceStateUpdate() {
+ // Update the maximized windows set based on the current maximization type
+ this.maximizedWindows = this.getMaximizedWindowIds();
+
+ // Force a state change emission
+ this.stateChangeCallback({
+ maximizedWindows: this.maximizedWindows,
+ currentWorkspace: this.workspace,
+ inOverview: this.inOverview
+ });
+ }
+
/**
* Gets the current window state
*
@@ -130,7 +160,7 @@ export default class WindowEvents {
* @param {Meta.Window} window - The window that changed size
*/
const onWindowSizeChange = window => {
- if (isMaximized(window))
+ if (isMaximized(window, this.maximizationType))
this.maximizedWindows.add(window.get_id());
else
this.maximizedWindows.delete(window.get_id());
@@ -179,7 +209,7 @@ export default class WindowEvents {
);
}
- if (isMaximized(window))
+ if (isMaximized(window, this.maximizationType))
this.maximizedWindows.add(window.get_id());
this.eventManager.attachWindowEventOnce(
@@ -209,11 +239,13 @@ export default class WindowEvents {
*/
const onWindowRaise = (_, windowActor) => {
const window = windowActor.get_meta_window();
- if (isMaximized(window))
+ if (isMaximized(window, this.maximizationType))
this.maximizedWindows.add(window.get_id());
this.emitStateChange();
};
+ const forceStateChangeEmission = () => emitStateChange(true);
+
this.workspace = this.workspaceManager.get_active_workspace();
// TODO: what if the window starts as maximized dimensions but is not "snapped"?
@@ -310,7 +342,7 @@ export default class WindowEvents {
return new Set(
this.display
.list_all_windows()
- .filter(isMaximized)
+ .filter(window => isMaximized(window, this.maximizationType))
.map(window => window.get_id())
);
}
diff --git a/src/extension.js b/src/extension.js
index 0a2139d..616e897 100755
--- a/src/extension.js
+++ b/src/extension.js
@@ -23,6 +23,15 @@ export default class GradientTopBar extends Extension {
const config = getConfig(settings);
applyGradientStyle(config, this.path);
+ // For other behaviors, we need to track window states
+ if (!this.windowEvents) {
+ // If window events were not initialized, initialize them now
+ this.initializeWindowEvents();
+ }
+ // Update maximization type if it changed
+ if (this.windowEvents)
+ this.windowEvents.setMaximizationType(config.maximizationType);
+
const maximizedBehavior = getMaximizedBehavior(settings);
// If set to keep-gradient, disable window events to save resources
@@ -34,12 +43,9 @@ export default class GradientTopBar extends Extension {
return;
}
- // For other behaviors, we need to track window states
- if (!this.windowEvents) {
- // If window events were not initialized, initialize them now
- this.initializeWindowEvents();
- }
this.windowEvents.enable();
+
+ // Force update to apply the current behavior
this.windowEvents.forceStateUpdate();
};
}
@@ -62,6 +68,10 @@ export default class GradientTopBar extends Extension {
global.window_manager,
global.get_workspace_manager()
);
+ const config = getConfig(this._settings);
+
+ // Set the maximization type from settings
+ this.windowEvents.setMaximizationType(config.maximizationType);
this.windowEvents.setStateChangeCallback(
({ maximizedWindows, currentWorkspace, inOverview }) => {
@@ -134,6 +144,7 @@ export default class GradientTopBar extends Extension {
this.toggleGradient(false);
detachSettingsListeners(this._settings, this.onSettingsChanged);
+ this.windowEvents = null;
this.isEffectApplied = false;
this._settings = null;
}
diff --git a/src/metadata.json b/src/metadata.json
index c7bd787..bafb49c 100644
--- a/src/metadata.json
+++ b/src/metadata.json
@@ -9,7 +9,7 @@
},
"shell-version": ["47", "48"],
"url": "https://github.com/petar-v/gradienttopbar",
- "version": 22,
+ "version": 23,
"gettext-domain": "org.pshow.gradienttopbar",
"settings-schema": "org.gnome.shell.extensions.org.pshow.gradienttopbar",
"hasPrefs": true
diff --git a/src/schemas/gschemas.compiled b/src/schemas/gschemas.compiled
index 1d9ebc6..d63b810 100644
Binary files a/src/schemas/gschemas.compiled and b/src/schemas/gschemas.compiled differ
diff --git a/src/schemas/org.gnome.shell.extensions.org.pshow.gradienttopbar.gschema.xml b/src/schemas/org.gnome.shell.extensions.org.pshow.gradienttopbar.gschema.xml
index 90cd266..27963f8 100644
--- a/src/schemas/org.gnome.shell.extensions.org.pshow.gradienttopbar.gschema.xml
+++ b/src/schemas/org.gnome.shell.extensions.org.pshow.gradienttopbar.gschema.xml
@@ -9,12 +9,23 @@
+
+
+
+
+
+
'keep-gradient'
Behavior when windows are maximized
Determines what style to apply to the top bar when there is a maximized window: keep the normal gradient, use the default theme, or apply a custom style.
+
+ 'both'
+ Definition of a maximized window
+ Determines what constitutes a maximized window: both horizontally and vertically maximized, only vertically maximized, only horizontally maximized, or any of these.
+
["rgba(0, 0, 0, 1)", "rgba(0, 0, 0, 0)"]
Array of the gradient colours
diff --git a/src/settings/behavioursPage.js b/src/settings/behavioursPage.js
index ccc4a56..6c375ec 100644
--- a/src/settings/behavioursPage.js
+++ b/src/settings/behavioursPage.js
@@ -12,6 +12,7 @@ import {
getMaximizedBehavior,
setMaximizedBehavior
} from '../config.js';
+import { MAXIMIZED_BEHAVIOR, MAXIMIZATION_TYPE } from '../constants.js';
import { MAXIMIZED_BEHAVIOR } from '../constants.js';
@@ -41,6 +42,32 @@ const MaximizedBehavior = GObject.registerClass(
}
);
+const MaximizationType = GObject.registerClass(
+ {
+ Properties: {
+ name: GObject.ParamSpec.string(
+ 'name',
+ 'name',
+ 'name',
+ GObject.ParamFlags.READWRITE,
+ null
+ ),
+ value: GObject.ParamSpec.string(
+ 'value',
+ 'value',
+ 'value',
+ GObject.ParamFlags.READWRITE,
+ null
+ )
+ }
+ },
+ class MaximizationType extends GObject.Object {
+ _init(name, value) {
+ super._init({ name, value });
+ }
+ }
+);
+
class Behavior extends Adw.PreferencesPage {
_init(window, settings) {
super._init({
@@ -90,18 +117,88 @@ class Behavior extends Adw.PreferencesPage {
// Set initial value
setMaximizedBehaviorOnRow(maximizedBehaviorRow, getMaximizedBehavior(this._settings));
- // Connect to changes
+ // Create a group for maximization detection settings
+ const maximizationDetectionGroup = new Adw.PreferencesGroup({
+ title: gettext('Maximization Detection')
+ });
+
+ // Create model for maximization type dropdown
+ const maximizationTypeModel = new Gio.ListStore({
+ item_type: MaximizationType
+ });
+
+ [
+ new MaximizationType(gettext('Both horizontally and vertically'), MAXIMIZATION_TYPE.BOTH),
+ new MaximizationType(gettext('Vertically only'), MAXIMIZATION_TYPE.VERTICAL),
+ new MaximizationType(gettext('Horizontally only'), MAXIMIZATION_TYPE.HORIZONTAL),
+ new MaximizationType(gettext('Any of these'), MAXIMIZATION_TYPE.ANY)
+ ].forEach(type => maximizationTypeModel.append(type));
+
+ // Create dropdown for maximization type
+ const maximizationTypeRow = new Adw.ComboRow({
+ title: gettext('Definition of a maximized window'),
+ subtitle: gettext(
+ 'Choose what constitutes a maximized window for the extension'
+ ),
+ model: maximizationTypeModel,
+ expression: new Gtk.PropertyExpression(MaximizationType, null, 'name')
+ });
+
+ // Set the selected item based on the current setting
+ const setMaximizationTypeOnRow = (row, typeValue) => {
+ const { model } = row;
+ for (let i = 0; i < model.get_n_items(); i++) {
+ if (model.get_item(i).value === typeValue) {
+ row.set_selected(i);
+ break;
+ }
+ }
+ };
+
+ // Set initial value
+ setMaximizationTypeOnRow(maximizationTypeRow, this._settings.get_string('maximization-type'));
+
+ // Function to update the sensitivity of maximization detection settings
+ const updateMaximizationDetectionSensitivity = () => {
+ const maximizedBehavior = settings.get_string('maximized-behavior');
+ // Only enable the maximization detection settings if we're not using 'keep-gradient'
+ const needsMaximizationDetection = maximizedBehavior !== MAXIMIZED_BEHAVIOR.KEEP_GRADIENT;
+
+ // Keep the group visible but set sensitivity based on the setting
+ maximizationDetectionGroup.set_sensitive(needsMaximizationDetection);
+ };
+
+ // Set initial sensitivity
+ updateMaximizationDetectionSensitivity();
+
+ // Connect to changes in maximized behavior
maximizedBehaviorRow.connect('notify::selected', () => {
const { selectedItem } = maximizedBehaviorRow;
setMaximizedBehavior(this._settings, selectedItem.value);
});
+ // Listen for changes to maximized-behavior setting
+ settings.connect('changed::maximized-behavior', updateMaximizationDetectionSensitivity);
+
+ // Connect to changes in maximization type
+ maximizationTypeRow.connect('notify::selected', () => {
+ const { selectedItem } = maximizationTypeRow;
+ settings.set_string('maximization-type', selectedItem.value);
+ });
+
+ // Add rows to groups
behaviorGroup.add(maximizedBehaviorRow);
+ maximizationDetectionGroup.add(maximizationTypeRow);
+
+ // Add groups to page
this.add(behaviorGroup);
+ this.add(maximizationDetectionGroup);
const onSettingsChanged = s => {
const config = getConfig(s);
setMaximizedBehaviorOnRow(maximizedBehaviorRow, config.maximizedBehavior);
+ setMaximizationTypeOnRow(maximizationTypeRow, config.maximizationType);
+ updateMaximizationDetectionSensitivity();
};
attachSettingsListeners(settings, onSettingsChanged);
window.connect('close-request', () => {