diff --git a/.gitignore b/.gitignore
index a9b274e..fc25d01 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ gschemas.compiled
.flatpak-builder/
out/
*.po~
+gnome-44-max/
diff --git a/bin/package_gnome b/bin/package_gnome
index 1f9dd0f..9a5dd7f 100755
--- a/bin/package_gnome
+++ b/bin/package_gnome
@@ -10,9 +10,25 @@ echo "Building Breezy GNOME for $ARCH"
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
ROOT_DIR=$(realpath $SCRIPT_DIR/..)
VULKAN_DIR=$ROOT_DIR/vulkan
-GNOME_DIR=$ROOT_DIR/gnome
+
+# if GNOME_44_MAX is not set
+if [ -z "$GNOME_44_MAX" ]; then
+ GNOME_DIR=$ROOT_DIR/gnome
+ BUILD_FILE_NAME=breezyGNOME-$ARCH.tar.gz
+else
+ # use a special directory for the GNOME 44 max build, ignored by git
+ GNOME_DIR=$ROOT_DIR/gnome-44-max
+ rm -rf $GNOME_DIR
+ mkdir $GNOME_DIR
+ BUILD_FILE_NAME=breezyGNOME.44-max.$ARCH.tar.gz
+
+ # copy the GNOME extension source code to the new directory and apply
+ # a patch that makes it compatible with GNOME 44 and below
+ cp -ra $ROOT_DIR/gnome/* $GNOME_DIR
+ rm -rf $GNOME_DIR/build
+ git apply gnome-44-max.patch
+fi
GNOME_BUILD_DIR=$GNOME_DIR/build
-BUILD_FILE_NAME=breezyGNOME-$ARCH.tar.gz
mkdir -p $GNOME_BUILD_DIR
if [ -e "$GNOME_BUILD_DIR/$BUILD_FILE_NAME" ]; then
diff --git a/gnome-44-max.patch b/gnome-44-max.patch
new file mode 100644
index 0000000..ce9b4bf
--- /dev/null
+++ b/gnome-44-max.patch
@@ -0,0 +1,427 @@
+diff --git a/gnome-44-max/bin/setup b/gnome-44-max/bin/setup
+index 7ee291a..3bd001b 100755
+--- a/gnome-44-max/bin/setup
++++ b/gnome-44-max/bin/setup
+@@ -11,6 +11,7 @@ check_command() {
+
+ check_command "flatpak"
+ check_command "gnome-extensions"
++check_command "glib-compile-schemas"
+
+ # This script gets packaged with the release and should do the bulk of the setup work. This allows this setup to be tied
+ # to a specific release of the code, and guarantees it will never run along-side newer or older binaries.
+@@ -78,8 +79,10 @@ echo "Copying the manifest file to ${DATA_DIR}"
+ mkdir -p $DATA_DIR
+ cp manifest $DATA_DIR
+
+-echo "Installing the breezydesktop@xronlinux.com GNOME extension"
+-gnome-extensions install --force breezydesktop@xronlinux.com.shell-extension.zip
++EXTENSION_UUID="breezydesktop@xronlinux.com"
++echo "Installing the $EXTENSION_UUID GNOME extension"
++gnome-extensions install --force "$EXTENSION_UUID.shell-extension.zip"
++glib-compile-schemas "$GNOME_SHELL_DATA_DIR/extensions/$EXTENSION_UUID/schemas"
+
+ echo "Installing the Breezy Desktop UI Flatpak (this may take a couple minutes the first time)"
+ flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
+diff --git a/gnome-44-max/src/cursor.js b/gnome-44-max/src/cursor.js
+index 36ad7ee..41102a0 100644
+--- a/gnome-44-max/src/cursor.js
++++ b/gnome-44-max/src/cursor.js
+@@ -15,11 +15,11 @@
+ // You should have received a copy of the GNU General Public License
+ // along with this program. If not, see .
+
+-import Clutter from 'gi://Clutter';
+-import GObject from 'gi://GObject';
++const Clutter = imports.gi.Clutter;
++const GObject = imports.gi.GObject;
+
+ // Copied almost verbatim from ui/magnifier.js.
+-export const MouseSpriteContent = GObject.registerClass({
++var MouseSpriteContent = GObject.registerClass({
+ Implements: [Clutter.Content],
+ }, class MouseSpriteContent extends GObject.Object {
+ _init() {
+diff --git a/gnome-44-max/src/cursormanager.js b/gnome-44-max/src/cursormanager.js
+index 44b3f5f..fa65a4a 100644
+--- a/gnome-44-max/src/cursormanager.js
++++ b/gnome-44-max/src/cursormanager.js
+@@ -1,11 +1,15 @@
+-import Clutter from 'gi://Clutter';
+-import Meta from 'gi://Meta';
+-import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js';
+-import { MouseSpriteContent } from './cursor.js';
+-import Globals from './globals.js';
++const Clutter = imports.gi.Clutter;
++const Meta = imports.gi.Meta;
++const PointerWatcher = imports.ui.pointerWatcher;
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++
++const Globals = Me.imports.globals;
++const { MouseSpriteContent } = Me.imports.cursor;
+
+ // Taken from https://github.com/jkitching/soft-brightness-plus
+-export class CursorManager {
++var CursorManager = class CursorManager {
+ constructor(mainActor, refreshRate) {
+ this._mainActor = mainActor;
+ this._refreshRate = refreshRate;
+@@ -208,7 +212,7 @@ export class CursorManager {
+
+ _queueVisibilityUpdate() {
+ this._queued_visibility_update = true;
+- this._cursorTrackerSetPointerVisibleBound(false);
++ if (this._cursorTrackerSetPointerVisibleBound) this._cursorTrackerSetPointerVisibleBound(false);
+ this._queueSpriteUpdate();
+ }
+
+diff --git a/gnome-44-max/src/extension.js b/gnome-44-max/src/extension.js
+index cd17162..435154d 100644
+--- a/gnome-44-max/src/extension.js
++++ b/gnome-44-max/src/extension.js
+@@ -1,19 +1,21 @@
+-import Clutter from 'gi://Clutter'
+-import Gio from 'gi://Gio';
+-import GLib from 'gi://GLib';
+-import Meta from 'gi://Meta';
+-import Shell from 'gi://Shell';
+-import St from 'gi://St';
+-
+-import { CursorManager } from './cursormanager.js';
+-import Globals from './globals.js';
+-import { Logger } from './logger.js';
+-import { MonitorManager } from './monitormanager.js';
+-import { isValidKeepAlive } from './time.js';
+-import { IPC_FILE_PATH, XREffect } from './xrEffect.js';
+-
+-import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
+-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
++const Clutter = imports.gi.Clutter;
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const Meta = imports.gi.Meta;
++const Shell = imports.gi.Shell;
++const St = imports.gi.St;
++
++const Main = imports.ui.main;
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++
++const Globals = Me.imports.globals;
++const { CursorManager } = Me.imports.cursormanager;
++const { Logger } = Me.imports.logger;
++const { MonitorManager } = Me.imports.monitormanager;
++const { isValidKeepAlive } = Me.imports.time;
++const { IPC_FILE_PATH, XREffect } = Me.imports.xrEffect;
+
+ const NESTED_MONITOR_PRODUCT = 'MetaMonitor';
+ const SUPPORTED_MONITOR_PRODUCTS = [
+@@ -29,11 +31,10 @@ const SUPPORTED_MONITOR_PRODUCTS = [
+ NESTED_MONITOR_PRODUCT
+ ];
+
+-export default class BreezyDesktopExtension extends Extension {
+- constructor(metadata, uuid) {
+- super(metadata, uuid);
+-
+- this.settings = this.getSettings();
++class BreezyDesktopExtension {
++ constructor(extensionPath) {
++ this.path = extensionPath;
++ this.settings = ExtensionUtils.getSettings();
+
+ // Set/destroyed by enable/disable
+ this._cursor_manager = null;
+@@ -593,6 +594,6 @@ export default class BreezyDesktopExtension extends Extension {
+ }
+ }
+
+-function init() {
+- return new Extension();
++function init(meta) {
++ return new BreezyDesktopExtension(meta.path);
+ }
+diff --git a/gnome-44-max/src/globals.js b/gnome-44-max/src/globals.js
+index 124d2e1..79a3a87 100644
+--- a/gnome-44-max/src/globals.js
++++ b/gnome-44-max/src/globals.js
+@@ -2,5 +2,4 @@ const Globals = {
+ logger: null,
+ ipc_file: null, // Gio.File instance, file exists if set
+ extension_dir: null // string path
+-}
+-export default Globals;
+\ No newline at end of file
++}
+\ No newline at end of file
+diff --git a/gnome-44-max/src/ipc.js b/gnome-44-max/src/ipc.js
+index a729368..d5f7ab0 100644
+--- a/gnome-44-max/src/ipc.js
++++ b/gnome-44-max/src/ipc.js
+@@ -1,30 +1,30 @@
+-export const UINT8_SIZE = 1;
+-export const BOOL_SIZE = UINT8_SIZE;
+-export const UINT_SIZE = 4;
+-export const FLOAT_SIZE = 4;
++var UINT8_SIZE = 1;
++var BOOL_SIZE = UINT8_SIZE;
++var UINT_SIZE = 4;
++var FLOAT_SIZE = 4;
+
+-export const DATA_VIEW_INFO_OFFSET_INDEX = 0;
+-export const DATA_VIEW_INFO_SIZE_INDEX = 1;
+-export const DATA_VIEW_INFO_COUNT_INDEX = 2;
++var DATA_VIEW_INFO_OFFSET_INDEX = 0;
++var DATA_VIEW_INFO_SIZE_INDEX = 1;
++var DATA_VIEW_INFO_COUNT_INDEX = 2;
+
+ // computes the end offset, exclusive
+-export function dataViewEnd(dataViewInfo) {
++function dataViewEnd(dataViewInfo) {
+ return dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX] + dataViewInfo[DATA_VIEW_INFO_SIZE_INDEX] * dataViewInfo[DATA_VIEW_INFO_COUNT_INDEX];
+ }
+
+-export function dataViewUint8(dataView, dataViewInfo) {
++function dataViewUint8(dataView, dataViewInfo) {
+ return dataView.getUint8(dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX]);
+ }
+
+-export function dataViewUint(dataView, dataViewInfo) {
++function dataViewUint(dataView, dataViewInfo) {
+ return dataView.getUint32(dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX], true);
+ }
+
+-export function dataViewBigUint(dataView, dataViewInfo) {
++function dataViewBigUint(dataView, dataViewInfo) {
+ return Number(dataView.getBigUint64(dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX], true));
+ }
+
+-export function dataViewUint32Array(dataView, dataViewInfo) {
++function dataViewUint32Array(dataView, dataViewInfo) {
+ const uintArray = []
+ let offset = dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX];
+ for (let i = 0; i < dataViewInfo[DATA_VIEW_INFO_COUNT_INDEX]; i++) {
+@@ -34,7 +34,7 @@ export function dataViewUint32Array(dataView, dataViewInfo) {
+ return uintArray;
+ }
+
+-export function dataViewUint8Array(dataView, dataViewInfo) {
++function dataViewUint8Array(dataView, dataViewInfo) {
+ const uintArray = []
+ let offset = dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX];
+ for (let i = 0; i < dataViewInfo[DATA_VIEW_INFO_SIZE_INDEX] * dataViewInfo[DATA_VIEW_INFO_COUNT_INDEX]; i++) {
+@@ -44,11 +44,11 @@ export function dataViewUint8Array(dataView, dataViewInfo) {
+ return uintArray;
+ }
+
+-export function dataViewFloat(dataView, dataViewInfo) {
++function dataViewFloat(dataView, dataViewInfo) {
+ return dataView.getFloat32(dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX], true);
+ }
+
+-export function dataViewFloatArray(dataView, dataViewInfo) {
++function dataViewFloatArray(dataView, dataViewInfo) {
+ const floatArray = []
+ let offset = dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX];
+ for (let i = 0; i < dataViewInfo[DATA_VIEW_INFO_COUNT_INDEX]; i++) {
+diff --git a/gnome-44-max/src/logger.js b/gnome-44-max/src/logger.js
+index 50450c1..8b307fc 100644
+--- a/gnome-44-max/src/logger.js
++++ b/gnome-44-max/src/logger.js
+@@ -14,15 +14,15 @@
+ // You should have received a copy of the GNU General Public License
+ // along with this program. If not, see .
+
+-import * as Config from 'resource:///org/gnome/shell/misc/config.js';
+-import Gio from 'gi://Gio';
+-import GLib from 'gi://GLib';
+-import GObject from 'gi://GObject';
+-import System from 'system';
++const Config = imports.misc.config;
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const GObject = imports.gi.GObject;
++const System = imports.system;
+
+ const LOG_DIR_NAME = 'breezy_gnome/logs/gjs';
+
+-export const Logger = GObject.registerClass({
++var Logger = GObject.registerClass({
+ GTypeName: 'Logger',
+ Properties: {
+ 'title': GObject.ParamSpec.string(
+diff --git a/gnome-44-max/src/math.js b/gnome-44-max/src/math.js
+index 497274e..6c98cdb 100644
+--- a/gnome-44-max/src/math.js
++++ b/gnome-44-max/src/math.js
+@@ -1,3 +1,3 @@
+-export function degreeToRadian(degree) {
++function degreeToRadian(degree) {
+ return degree * Math.PI / 180;
+ }
+\ No newline at end of file
+diff --git a/gnome-44-max/src/metadata.json b/gnome-44-max/src/metadata.json
+index b9b5ebf..c888f94 100644
+--- a/gnome-44-max/src/metadata.json
++++ b/gnome-44-max/src/metadata.json
+@@ -5,7 +5,7 @@
+ "settings-schema": "com.xronlinux.BreezyDesktop",
+ "session-modes": ["user", "unlock-dialog"],
+ "shell-version": [
+- "45", "46"
++ "42", "43", "44"
+ ],
+ "url": "https://github.com/wheaney/breezy-desktop"
+ }
+\ No newline at end of file
+diff --git a/gnome-44-max/src/monitormanager.js b/gnome-44-max/src/monitormanager.js
+index ca8a6a5..075ba63 100644
+--- a/gnome-44-max/src/monitormanager.js
++++ b/gnome-44-max/src/monitormanager.js
+@@ -16,12 +16,15 @@
+ // You should have received a copy of the GNU General Public License
+ // along with this program. If not, see .
+
+-import Gio from 'gi://Gio';
+-import GObject from 'gi://GObject';
++const Gio = imports.gi.Gio;
++const GObject = imports.gi.GObject;
+
+-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
++const Main = imports.ui.main;
+
+-import Globals from './globals.js';
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++
++const Globals = Me.imports.globals;
+
+ let cachedDisplayConfigProxy = null;
+
+@@ -43,7 +46,7 @@ function getDisplayConfigProxy(extPath) {
+ return cachedDisplayConfigProxy;
+ }
+
+-export function newDisplayConfig(extPath, callback) {
++function newDisplayConfig(extPath, callback) {
+ const DisplayConfigProxy = getDisplayConfigProxy(extPath);
+ new DisplayConfigProxy(
+ Gio.DBus.session,
+@@ -243,7 +246,7 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
+ }
+
+ // Monitor change handling
+-export const MonitorManager = GObject.registerClass({
++var MonitorManager = GObject.registerClass({
+ Properties: {
+ 'use-optimal-monitor-config': GObject.ParamSpec.boolean(
+ 'use-optimal-monitor-config',
+diff --git a/gnome-44-max/src/shader.js b/gnome-44-max/src/shader.js
+index f70c96d..352be40 100644
+--- a/gnome-44-max/src/shader.js
++++ b/gnome-44-max/src/shader.js
+@@ -1,6 +1,6 @@
+-import Gio from 'gi://Gio';
++const Gio = imports.gi.Gio;
+
+-export function getShaderSource(path) {
++function getShaderSource(path) {
+ const file = Gio.file_new_for_path(path);
+ const data = file.load_contents(null);
+
+diff --git a/gnome-44-max/src/time.js b/gnome-44-max/src/time.js
+index 7883b9b..5478d2a 100644
+--- a/gnome-44-max/src/time.js
++++ b/gnome-44-max/src/time.js
+@@ -1,11 +1,11 @@
+-export function getEpochSec() {
++function getEpochSec() {
+ return toSec(Date.now());
+ }
+
+-export function toSec(milliseconds) {
++function toSec(milliseconds) {
+ return Math.floor(milliseconds / 1000);
+ }
+
+-export function isValidKeepAlive(dateSec, strictCheck = false) {
++function isValidKeepAlive(dateSec, strictCheck = false) {
+ return Math.abs(toSec(Date.now()) - dateSec) <= (strictCheck ? 1 : 5);
+ }
+\ No newline at end of file
+diff --git a/gnome-44-max/src/xrEffect.js b/gnome-44-max/src/xrEffect.js
+index 2680cae..bfb036f 100644
+--- a/gnome-44-max/src/xrEffect.js
++++ b/gnome-44-max/src/xrEffect.js
+@@ -1,13 +1,15 @@
+-import Clutter from 'gi://Clutter';
+-import Cogl from 'gi://Cogl';
+-import GdkPixbuf from 'gi://GdkPixbuf';
+-import GLib from 'gi://GLib';
+-import GObject from 'gi://GObject';
+-import Shell from 'gi://Shell';
+-
+-import Globals from './globals.js';
+-
+-import {
++const Clutter = imports.gi.Clutter;
++const Cogl = imports.gi.Cogl;
++const GdkPixbuf = imports.gi.GdkPixbuf;
++const GLib = imports.gi.GLib;
++const GObject = imports.gi.GObject;
++const Shell = imports.gi.Shell;
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++
++const Globals = Me.imports.globals;
++const {
+ dataViewEnd,
+ dataViewUint8,
+ dataViewBigUint,
+@@ -21,12 +23,12 @@ import {
+ FLOAT_SIZE,
+ UINT_SIZE,
+ UINT8_SIZE
+-} from "./ipc.js";
+-import { degreeToRadian } from "./math.js";
+-import { getShaderSource } from "./shader.js";
+-import { isValidKeepAlive, toSec } from "./time.js";
++} = Me.imports.ipc;
++const { degreeToRadian } = Me.imports.math;
++const { getShaderSource } = Me.imports.shader;
++const { isValidKeepAlive, toSec } = Me.imports.time;
+
+-export const IPC_FILE_PATH = "/dev/shm/breezy_desktop_imu";
++var IPC_FILE_PATH = "/dev/shm/breezy_desktop_imu";
+
+ // the driver should be using the same data layout version
+ const DATA_LAYOUT_VERSION = 3;
+@@ -220,7 +222,7 @@ function checkParityByte(dataView) {
+ return parityByte === parity;
+ }
+
+-export const XREffect = GObject.registerClass({
++var XREffect = GObject.registerClass({
+ Properties: {
+ 'supported-device-detected': GObject.ParamSpec.boolean(
+ 'supported-device-detected',
+@@ -360,8 +362,13 @@ export const XREffect = GObject.registerClass({
+ if (!this._initialized) {
+ this.set_uniform_float(this.get_uniform_location('uDesktopTexture'), 1, [0]);
+
+- this.get_pipeline().set_layer_texture(1, calibratingImage.get_texture());
+- this.get_pipeline().set_layer_texture(2, customBannerImage.get_texture());
++ try {
++ // this can break in GNOME 42
++ this.get_pipeline().set_layer_texture(1, calibratingImage.get_texture());
++ this.get_pipeline().set_layer_texture(2, customBannerImage.get_texture());
++ } catch (e) {
++ Globals.logger.log(`ERROR: xrEffect.js vfunc_paint_target ${e.message}\n${e.stack}`);
++ }
+ this.get_pipeline().set_uniform_1i(this.get_uniform_location('uCalibratingTexture'), 1);
+ this.get_pipeline().set_uniform_1i(this.get_uniform_location('uCustomBannerTexture'), 2);
+