commit
ee31ea8b75
|
@ -0,0 +1 @@
|
|||
swayfocus
|
|
@ -0,0 +1,13 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
|
@ -0,0 +1,19 @@
|
|||
ifeq ($(PREFIX),)
|
||||
PREFIX := /usr/local
|
||||
endif
|
||||
|
||||
all: release
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f swayfocus
|
||||
|
||||
.PHONY: run
|
||||
run:
|
||||
crystal run src/swayfocus.cr
|
||||
|
||||
release:
|
||||
crystal build --release --no-debug src/swayfocus.cr
|
||||
|
||||
install:
|
||||
install swayfocus $(PREFIX)/bin/
|
|
@ -0,0 +1,28 @@
|
|||
# SWAYFOCUS - Window Switching Tool For Sway
|
||||
|
||||
A tool to focus a specific window in sway, useful for run or raise scripts that would have used xdotool or wmctrl under Xorg.
|
||||
Uses swaymsg to communicate. Windows hidden to the system tray don't show up in the get_tree command, so they can't be raised with this.
|
||||
|
||||
## Usage
|
||||
```
|
||||
Usage: swayfocus [OPTIONS]
|
||||
-v, --version Show Version
|
||||
-h, --help Show Help
|
||||
-p, --print Print window names and exit
|
||||
-c, --cycle Cycle through all matching windows in order, instead of selecting the first in the list
|
||||
-n WNAME, --name=WNAME Match against window name
|
||||
-m WMARK, --mark=WMARK Match against window mark
|
||||
-t WTYPE, --type=WTYPE Match against window type (app_id for wayland, class for xwayland)
|
||||
```
|
||||
Select at least one matching option.
|
||||
|
||||
## Examples
|
||||
```
|
||||
swayfocus -p | sort -u | bemenu | xargs swayfocus -c --name=
|
||||
# simple window switcher
|
||||
```
|
||||
|
||||
## Installation
|
||||
```
|
||||
make && sudo make install
|
||||
```
|
|
@ -0,0 +1,125 @@
|
|||
require "json"
|
||||
require "option_parser"
|
||||
|
||||
version = "0.1"
|
||||
puts ""
|
||||
|
||||
class Window
|
||||
JSON.mapping({
|
||||
id: UInt32,
|
||||
name: String,
|
||||
wtype: {type: String, key: "type"},
|
||||
app_id: {type: String, default: ""},
|
||||
wclass: {type: String, key: "class", default: ""},
|
||||
marks: {type: Array(String), default: [] of String},
|
||||
nodes: {type: Array(Window), default: [] of Window},
|
||||
focused: {type: Bool, default: false}
|
||||
})
|
||||
|
||||
def clear_nodes
|
||||
@nodes = [] of Window
|
||||
end
|
||||
end
|
||||
|
||||
def node_loop (root : Window)
|
||||
list = [] of Window
|
||||
root.nodes.each do |node|
|
||||
if(node.wtype == "con")
|
||||
list << node
|
||||
elsif(node.nodes != [] of Window)
|
||||
list.concat(node_loop(node))
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
client_tree = Window.from_json(`swaymsg -t get_tree`)
|
||||
|
||||
if(client_tree.wtype != "root")
|
||||
puts "Malformed client tree."
|
||||
exit(1)
|
||||
end
|
||||
|
||||
window_list = node_loop(client_tree)
|
||||
|
||||
def parse_marks(marks : Array(String), mark : String)
|
||||
res : Bool = false
|
||||
marks.each do |cm|
|
||||
if(cm.includes? mark)
|
||||
res = true
|
||||
end
|
||||
end
|
||||
return !res
|
||||
end
|
||||
|
||||
def check_type
|
||||
end
|
||||
|
||||
cycle = false
|
||||
OptionParser.parse do |parser|
|
||||
parser.banner = "Usage: swayfocus [OPTIONS]"
|
||||
|
||||
parser.on "-v", "--version", "Show Version" do
|
||||
puts version
|
||||
exit(0)
|
||||
end
|
||||
|
||||
parser.on "-h", "--help", "Show Help" do
|
||||
puts parser
|
||||
exit(0)
|
||||
end
|
||||
|
||||
parser.on "-p", "--print", "Print window names and exit" do
|
||||
window_list.each do |win|
|
||||
puts win.name
|
||||
end
|
||||
exit(0)
|
||||
end
|
||||
|
||||
parser.on "-c", "--cycle", "Cycle through all matching windows in order, instead of selecting the first in the list" do
|
||||
cycle = true
|
||||
end
|
||||
|
||||
parser.on "-n WNAME", "--name=WNAME", "Match against window name" do |wname|
|
||||
window_list.reject! {|w| !w.name.includes? wname}
|
||||
end
|
||||
|
||||
parser.on "-m WMARK", "--mark=WMARK", "Match against window mark" do |wmark|
|
||||
window_list.reject! {|w| parse_marks(w.marks, wmark)}
|
||||
end
|
||||
|
||||
parser.on "-t WTYPE", "--type=WTYPE", "Match against window type (app_id for wayland, class for xwayland)" do |wtype|
|
||||
window_list.reject! {|w| !(w.app_id.includes?(wtype) || w.wclass.includes?(wtype))}
|
||||
end
|
||||
|
||||
parser.invalid_option do |flag|
|
||||
STDERR.puts "#{flag} is not a valid option"
|
||||
STDERR.puts ""
|
||||
STDERR.puts parser
|
||||
exit(1)
|
||||
end
|
||||
|
||||
parser.missing_option do |flag|
|
||||
STDERR.puts "#{flag} requires an argument"
|
||||
STDERR.puts ""
|
||||
STDERR.puts parser
|
||||
exit(1)
|
||||
end
|
||||
|
||||
parser.unknown_args do
|
||||
exit(0)
|
||||
end
|
||||
end
|
||||
|
||||
if(window_list == [] of Window)
|
||||
puts "No matching window."
|
||||
exit(1)
|
||||
end
|
||||
if(cycle)
|
||||
while(!window_list[window_list.size - 1].focused)
|
||||
window_list.push window_list[0]
|
||||
window_list.delete_at(0)
|
||||
end
|
||||
end
|
||||
|
||||
Process.exec("swaymsg", [%<[con_id=>+window_list[0].id.to_s+%<]>,"focus"])
|
Loading…
Reference in New Issue