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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea/
*.DotSettings.user
40 changes: 22 additions & 18 deletions extension.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"use strict";

const { Shell, Meta, Gio, GObject } = imports.gi;
const Main = imports.ui.main;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
import Shell from "gi://Shell";
import Meta from "gi://Meta";
import Gio from "gi://Gio";
import GObject from "gi://GObject";
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';

const SETTINGS_ID = "org.gnome.shell.extensions.focus-window";
const SETTINGS_KEY = "app-settings";
Expand Down Expand Up @@ -71,8 +73,9 @@ const KeyboardShortcuts = GObject.registerClass(
}
);

class Extension {
constructor() {
export default class FocusWindowExtensions extends Extension {
constructor(metadata) {
super(metadata);
this.shortcuts = null;
this.settingsListener = null;
this.settings = null;
Expand All @@ -81,7 +84,7 @@ class Extension {
enable() {
this.shortcuts = new KeyboardShortcuts();

this.settings = ExtensionUtils.getSettings(SETTINGS_ID);
this.settings = this.getSettings(SETTINGS_ID);

this.settingsListener = this.settings.connect(
`changed::${SETTINGS_KEY}`,
Expand Down Expand Up @@ -158,25 +161,26 @@ class Extension {
return appWindows[0].minimize();
}


// Draw focus to the window if it is not already focused
if (appWindows.length === 1) {
// Get the currently active workspace
const appWindow = appWindows[0];
const activeWorkspace = global.workspace_manager.get_active_workspace();
const windowWorkspaceIndex = appWindow.get_workspace().index();
// If the window is not in the active workspace, move it
// Move the window to the active workspace
if (activeWorkspace.index() !== windowWorkspaceIndex){
appWindow.change_workspace(activeWorkspace);
if (setting.moveToCurrentDesktop){
// Get the currently active workspace
const activeWorkspace = global.workspace_manager.get_active_workspace();
const windowWorkspaceIndex = appWindow.get_workspace().index();
// If the window is not in the active workspace, move it
// Move the window to the active workspace
if (activeWorkspace.index() !== windowWorkspaceIndex){
appWindow.change_workspace(activeWorkspace);
}
}

return Main.activateWindow(appWindow);
}

return false;
} catch (error) {
log("setting trigger failed: ");
log(error);
}
});
}
Expand All @@ -194,5 +198,5 @@ class Extension {
}

function init() {
return new Extension();
return new FocusWindowExtensions();
}
8 changes: 5 additions & 3 deletions metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
"description": "This extension allows one to create various shortcuts for applications, enabling the ability to have one shortcut that triggers both the launch and focus of an application window.",
"uuid": "focus-window@chris.al",
"shell-version": [
"42",
"43",
"44"
"45",
"46",
"47",
"48",
"49"
],
"url": "https://github.com/pcbowers/focus-window",
"version": 1
Expand Down
187 changes: 103 additions & 84 deletions prefs.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
const { GObject, GLib, Gio, Adw, Gtk, Gdk } = imports.gi;
import Adw from "gi://Adw";
import Gtk from "gi://Gtk";
import Gdk from "gi://Gdk";
import GLib from "gi://GLib";
import Gio from "gi://Gio";
import GObject from "gi://GObject";

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
import {ExtensionPreferences} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';

const SETTINGS_ID = "org.gnome.shell.extensions.focus-window";
const SETTINGS_KEY = "app-settings";
Expand Down Expand Up @@ -95,13 +99,14 @@ function init() {}
const FocusWidget = GObject.registerClass(
{
GTypeName: "FocusWidget",
Template: Me.dir.get_child("prefs.ui").get_uri(),
Template: GLib.uri_resolve_relative(import.meta.url, './prefs.ui', GLib.UriFlags.NONE),
InternalChildren: [
"application_to_focus",
"application_list",
"title_to_match",
"exact_title_match",
"launch_application",
"move_to_current_desktop",
"command_line_arguments",
"keyboard_shortcut_row",
"keyboard_shortcut",
Expand All @@ -119,6 +124,7 @@ const FocusWidget = GObject.registerClass(
titleToMatch: "",
exactTitleMatch: false,
launchApplication: true,
moveToCurrentDesktop: true,
commandLineArguments: "",
keyboardShortcut: "",
},
Expand All @@ -136,6 +142,7 @@ const FocusWidget = GObject.registerClass(
this.titleToMatch = this._title_to_match;
this.exactTitleMatch = this._exact_title_match;
this.launchApplication = this._launch_application;
this.moveToCurrentDesktop = this._move_to_current_desktop;
this.commandLineArguments = this._command_line_arguments;
this.keyboardShortcutRow = this._keyboard_shortcut_row;
this.keyboardShortcut = this._keyboard_shortcut;
Expand All @@ -158,6 +165,7 @@ const FocusWidget = GObject.registerClass(
this.titleToMatch.set_text(this.settings.titleToMatch);
this.exactTitleMatch.set_active(this.settings.exactTitleMatch);
this.launchApplication.set_active(this.settings.launchApplication);
this.moveToCurrentDesktop.set_active(this.settings.moveToCurrentDesktop);
this.commandLineArguments.set_text(this.settings.commandLineArguments);
this.keyboardShortcut.set_accelerator(this.settings.keyboardShortcut);
}
Expand Down Expand Up @@ -323,6 +331,14 @@ const FocusWidget = GObject.registerClass(
this.settings.launchApplication = !!active;
this.saveSettings();
}

// saves launch application state
// bound by signal in UI
onMoveToCurrentDesktopToggled(swtch) {
const active = swtch.get_active();
this.settings.moveToCurrentDesktop = !!active;
this.saveSettings();
}

// saves written command lines
// bound by signal in UI
Expand Down Expand Up @@ -372,88 +388,91 @@ const FocusWidget = GObject.registerClass(
}
);

function fillPreferencesWindow(window) {
// stores all focusWidgets
const focusWidgets = [];

// get settings
const extensionSettings = ExtensionUtils.getSettings(SETTINGS_ID);
const { getAllSettings, setSettings } = generateSettings(extensionSettings);

// create preference pages
const page = new Adw.PreferencesPage();
const group = new Adw.PreferencesGroup();
page.add(group);
window.add(page);
window.set_margin_bottom(10);
window.set_margin_top(10);
window.set_margin_start(5);
window.set_margin_end(5);

// generate 'Add Application' button
const button = new Gtk.Button({ valign: Gtk.Align.CENTER });
const buttonContent = new Adw.ButtonContent({
"icon-name": "list-add-symbolic",
label: "Add Application",
});
button.add_css_class("suggested-action");
group.set_header_suffix(button);
button.set_child(buttonContent);

// sets the title and description of group
const setTitleAndDescription = () => {
group.set_title(
`${focusWidgets.length} Shortcut${
focusWidgets.length === 1 ? "" : "s Created"
}`
);

const configured = focusWidgets.filter(
(item) =>
item.widget.settings &&
item.widget.settings.applicationToFocus &&
item.widget.settings.keyboardShortcut
).length;

group.set_description(
`${
configured === focusWidgets.length ? "All" : configured
} of which are fully configured`
);
};
export default class FocusWindowPreferences extends ExtensionPreferences {
fillPreferencesWindow(window) {
// stores all focusWidgets
const focusWidgets = [];

// get settings
const extensionSettings = this.getSettings(SETTINGS_ID);
console.error(JSON.stringify(extensionSettings));
const {getAllSettings, setSettings} = generateSettings(extensionSettings);

// create preference pages
const page = new Adw.PreferencesPage();
const group = new Adw.PreferencesGroup();
page.add(group);
window.add(page);
window.set_margin_bottom(10);
window.set_margin_top(10);
window.set_margin_start(5);
window.set_margin_end(5);

// generate 'Add Application' button
const button = new Gtk.Button({valign: Gtk.Align.CENTER});
const buttonContent = new Adw.ButtonContent({
"icon-name": "list-add-symbolic",
label: "Add Application",
});
button.add_css_class("suggested-action");
group.set_header_suffix(button);
button.set_child(buttonContent);

// sets the title and description of group
const setTitleAndDescription = () => {
group.set_title(
`${focusWidgets.length} Shortcut${
focusWidgets.length === 1 ? "" : "s Created"
}`
);

// removes focus widget from page and memory, updates count label
const onDelete = (id) => () => {
const index = focusWidgets.findIndex((i) => i.id === id);
if (index < 0) return;
const configured = focusWidgets.filter(
(item) =>
item.widget.settings &&
item.widget.settings.applicationToFocus &&
item.widget.settings.keyboardShortcut
).length;

group.set_description(
`${
configured === focusWidgets.length ? "All" : configured
} of which are fully configured`
);
};

// removes focus widget from page and memory, updates count label
const onDelete = (id) => () => {
const index = focusWidgets.findIndex((i) => i.id === id);
if (index < 0) return;

group.remove(focusWidgets[index].widget);
focusWidgets.splice(index, 1);
setTitleAndDescription();
};

// add focus widgets from settings
getAllSettings().forEach((settings) => {
const newWidget = new FocusWidget(
{"margin-top": 0},
setSettings(settings.id),
onDelete(settings.id),
settings.id,
settings,
false
);
focusWidgets.push({id: settings.id, widget: newWidget});
group.add(newWidget);
});

group.remove(focusWidgets[index].widget);
focusWidgets.splice(index, 1);
setTitleAndDescription();
};

// add focus widgets from settings
getAllSettings().forEach((settings) => {
const newWidget = new FocusWidget(
{ "margin-top": 0 },
setSettings(settings.id),
onDelete(settings.id),
settings.id,
settings,
false
);
focusWidgets.push({ id: settings.id, widget: newWidget });
group.add(newWidget);
});

setTitleAndDescription();

// add focus widgets when 'Add Application' button is clicked
button.connect("clicked", () => {
const id = createId();
const newWidget = new FocusWidget({}, setSettings(id), onDelete(id), id);
focusWidgets.push({ id, widget: newWidget });
group.add(newWidget);
setTitleAndDescription();
});
// add focus widgets when 'Add Application' button is clicked
button.connect("clicked", () => {
const id = createId();
const newWidget = new FocusWidget({}, setSettings(id), onDelete(id), id);
focusWidgets.push({id, widget: newWidget});
group.add(newWidget);
setTitleAndDescription();
});
}
}
14 changes: 14 additions & 0 deletions prefs.ui
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,19 @@ Press Esc to cancel or Backspace to unbind the shortcut.</property>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title">Move to current Desktop</property>
<property name="subtitle">Toggle this on if you want to move the </property>
<property name="activatable-widget">move_to_current_desktop</property>
<child>
<object class="GtkSwitch" id="move_to_current_desktop">
<property name="valign">center</property>
<property name="active">true</property>
<signal name="notify::active" handler="onMoveToCurrentDesktopToggled" swapped="no" />
</object>
</child>
</object>
</child>
</template>
</interface>