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
@@ -1 +1,3 @@
build
notes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What creates the notes file? I tend to have the code short, if it is unlikely the notes will be created on other machines, I prefer to put such things info .git/info/exclude instead

*.compiled
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,12 @@ You can combine multiple modes by appending a colon. On the first hit, we regist
```
<Super>i:raise-or-register:move-window-to-active-workspace
```

#### `match-cmdline`
Use the launch command to match a windows to a shortcut. Some applications do not honor WM_CLASS or keep a consistent window title. For example, Firefox installed via Snap on Ubuntu will not be distinguishable using traditional matching. Using match-cmdline allows you to differentiate between Firefox profiles as seen below.
```
<Super>w:match-cmdline,firefox -P work -no-remote,,
<Super>p:match-cmdline,firefox -P personal -no-remote,,
```
#### `isolate-workspace`
Switch windows on the active workspace only
```
Expand Down
30 changes: 30 additions & 0 deletions lib/action.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Mode } from './mode.js'
import Gio from 'gi://Gio'
import GLib from 'gi://GLib'
import Mtk from 'gi://Mtk'
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the Main is not used in your code, what's the purpose here?


export class Action {

Expand Down Expand Up @@ -90,6 +91,28 @@ export class Action {
return global.display.get_tab_list(0, active_workspace)
}

get_window_cmdline(window) {
const pid = window.get_pid();

if (!pid) return "";

const file = Gio.File.new_for_path(`/proc/${pid}/cmdline`);
const [ok, contents] = file.load_contents(null);
if (!ok) return "";

try {
const file = Gio.File.new_for_path(`/proc/${pid}/cmdline`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two lines (which might be perfomance-inefficient) are run twice. Is it on purpose?

const [ok, contents] = file.load_contents(null);
if (ok && contents) {
// contents is a ByteArray — decode it manually, replacing nulls with spaces
return new TextDecoder().decode(contents.map(b => b !== 0 ? b : 32));
}
} catch (e) {
log(`Error fetching cmdline for pid ${pid}: ${e}`);
}

return "";
}

is_conforming(window) {
const [command, wmNeedle, wmFn, title, titleFn] = [this.command, this.wm_class, this.wmFn, this.title, this.titleFn]
Expand All @@ -99,6 +122,13 @@ export class Action {
const window_title = window.get_title() || ''

// check if the current window is conforming to the search criteria
if (this.mode.get(Mode.MATCH_CMDLINE)) {
const normalize = str => str.trim().replace(/\s+/g, ' ');
const cmdline = this.get_window_cmdline(window);
if (!cmdline || !command) return false;
return normalize(cmdline).endsWith(normalize(command));
}

if (wmNeedle) { // seek by (wm_class_name or wm_class_instance) AND if set, title must match
if (
(window_instance[wmFn](wmNeedle) > -1 ||
Expand Down
1 change: 1 addition & 0 deletions lib/mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class Mode {
static RAISE = "raise"
/** if nothing registered yet, register current */
static RAISE_OR_REGISTER = "raise-or-register"
static MATCH_CMDLINE = "match-cmdline"
static VERBOSE = "verbose"

/**
Expand Down
Binary file removed schemas/gschemas.compiled
Binary file not shown.
9 changes: 9 additions & 0 deletions schemas/org.gnome.shell.extensions.run-on-raise.gschema.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="gnome-shell-extensions">
<schema path="/org/gnome/shell/extensions/run-or-raise/" id="org.gnome.shell.extensions.run-or-raise">
<key type="b" name="match-cmdline">
<default>false</default>
<summary>Use the launch command to match a window to raise.</summary>
<description>Useful for applications that do not honor WM_CLASS or keep a consistent window title.
For example, Firefox profiles running via Snap on Ubuntu will not be distinguishable
using either MW_CLASS or a window title. Using match-cmdline allows you to
match "firefox -P work -no-remote,," vs "firefox -P personal -no-remote,,"
</description>
</key>
<key type="b" name="dbus">
<default>false</default>
<summary>Listen on DBus</summary>
Expand Down
9 changes: 9 additions & 0 deletions shortcuts.default
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@

# Go to https://github.com/CZ-NIC/run-or-raise/blob/main/README.md for
# documentation of additional functionality you can use below.

# Here you list all the shortcuts. To reload, turn the extension off and on.
#
# The shortcuts may be defined in two ways:
Expand All @@ -22,6 +26,11 @@
# This line cycles any open gnome-terminal (matched by wm_class = Gnome-terminal on Ubuntu 17.10) OR if not found, launches new one.
# If you're using Arch, you may want to match by wm_class = gnome-terminal-server , just check yourself by Alt+F2/lg/Windows
<Super>r,gnome-terminal,Gnome-terminal,
# These lines match based on the full command line used to launch the window.
# Useful for profile switching with Firefox on Snap implementations (such as Ubuntu) since they ignore wm_class and dynamically
# change the title.
<Super>w:match-cmdline,firefox -P work -no-remote,,
<Super>p:match-cmdline,firefox -P personal -no-remote,,


# You may use regular expression in title or wm_class.
Expand Down