Add remote commands support
This commit is contained in:
17
kutu-run.rb
Executable file
17
kutu-run.rb
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
require "socket"
|
||||||
|
|
||||||
|
SOCK_PATH = "/tmp/kutu.sock"
|
||||||
|
|
||||||
|
client = Socket.new(:UNIX, :DGRAM)
|
||||||
|
|
||||||
|
cli_addr_path = "/tmp/kutu_client#{Process.pid}.sock"
|
||||||
|
File.delete(cli_addr_path) if File.exist?(cli_addr_path)
|
||||||
|
client.bind(Socket.pack_sockaddr_un(cli_addr_path))
|
||||||
|
|
||||||
|
client.send(ARGV.join(" "), 0, Socket.pack_sockaddr_un(SOCK_PATH))
|
||||||
|
|
||||||
|
data, = client.recvfrom(1024)
|
||||||
|
|
||||||
|
puts data
|
||||||
49
kutu.rb
49
kutu.rb
@@ -5,6 +5,12 @@
|
|||||||
require_relative "./src/ruby/X-kutu"
|
require_relative "./src/ruby/X-kutu"
|
||||||
|
|
||||||
|
|
||||||
|
# Require dependencies
|
||||||
|
|
||||||
|
require 'json'
|
||||||
|
require 'socket'
|
||||||
|
|
||||||
|
|
||||||
# Initialize X
|
# Initialize X
|
||||||
|
|
||||||
if X.deploy >= 0
|
if X.deploy >= 0
|
||||||
@@ -14,13 +20,14 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Require modules
|
# Require submodules
|
||||||
|
|
||||||
load File.join(__dir__, "./src/ruby/utils.rb")
|
require_relative "./src/ruby/utils"
|
||||||
load File.join(__dir__, "./src/ruby/controller.rb")
|
require_relative "./src/ruby/controller"
|
||||||
load File.join(__dir__, "./src/ruby/window.rb")
|
require_relative "./src/ruby/window"
|
||||||
load File.join(__dir__, "./src/ruby/workspace.rb")
|
require_relative "./src/ruby/workspace"
|
||||||
load File.join(__dir__, "./src/ruby/events.rb")
|
require_relative "./src/ruby/events"
|
||||||
|
require_relative "./src/ruby/commands"
|
||||||
|
|
||||||
|
|
||||||
# Cleanup on exit
|
# Cleanup on exit
|
||||||
@@ -36,11 +43,15 @@ end
|
|||||||
$monitors = {}
|
$monitors = {}
|
||||||
$windows = {}
|
$windows = {}
|
||||||
|
|
||||||
|
$all_windows = []
|
||||||
|
|
||||||
$keybind_actions = {}
|
$keybind_actions = {}
|
||||||
$mousebind_actions = {}
|
$mousebind_actions = {}
|
||||||
|
|
||||||
$mouse_data = {}
|
$mouse_data = {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$root = X.get_root
|
$root = X.get_root
|
||||||
$rect = {}
|
$rect = {}
|
||||||
|
|
||||||
@@ -60,9 +71,31 @@ run File.join(__dir__, "./src/shell/startup.sh")
|
|||||||
load File.join(__dir__, "./src/ruby/bindings.rb")
|
load File.join(__dir__, "./src/ruby/bindings.rb")
|
||||||
|
|
||||||
|
|
||||||
|
# Setup unix socket
|
||||||
|
|
||||||
|
SOCK_PATH = "/tmp/kutu.sock"
|
||||||
|
File.delete(SOCK_PATH) if File.exist?(SOCK_PATH)
|
||||||
|
|
||||||
|
$socket = Socket.new(:UNIX, :DGRAM)
|
||||||
|
$socket.bind(Socket.pack_sockaddr_un(SOCK_PATH))
|
||||||
|
|
||||||
|
|
||||||
# Main loop
|
# Main loop
|
||||||
|
|
||||||
loop do
|
loop do
|
||||||
event = X.wait_for_event
|
if IO.select([$socket], nil, nil, 0)
|
||||||
handle_event event
|
command, sender = $socket.recvfrom(1024)
|
||||||
|
reply = handle_command(command)
|
||||||
|
$socket.send(JSON.generate(reply), 0, sender)
|
||||||
|
end
|
||||||
|
|
||||||
|
event_pointer = X.next_event
|
||||||
|
if !event_pointer.null?
|
||||||
|
event = X.translate_event(event_pointer)
|
||||||
|
handle_event(event)
|
||||||
|
end
|
||||||
|
|
||||||
|
X.flush
|
||||||
|
|
||||||
|
sleep 0.001
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ xcb_screen_t *scr;
|
|||||||
// Currently focused window
|
// Currently focused window
|
||||||
xcb_window_t focuswin;
|
xcb_window_t focuswin;
|
||||||
|
|
||||||
|
// Flush
|
||||||
|
void flush(void) { xcb_flush(conn); }
|
||||||
|
|
||||||
// Cleanup function to close the X connection on exit
|
// Cleanup function to close the X connection on exit
|
||||||
void cleanup(void) {
|
void cleanup(void) {
|
||||||
if (conn != NULL)
|
if (conn != NULL)
|
||||||
@@ -81,34 +84,21 @@ void subscribe(xcb_window_t win) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Kill a window
|
// Kill a window
|
||||||
void kill(xcb_window_t window) {
|
void kill(xcb_window_t window) { xcb_kill_client(conn, window); }
|
||||||
xcb_kill_client(conn, window);
|
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy a window
|
// Destroy a window
|
||||||
void destroy(xcb_window_t win) {
|
void destroy(xcb_window_t win) { xcb_destroy_window(conn, win); }
|
||||||
xcb_destroy_window(conn, win);
|
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show a window
|
// Show a window
|
||||||
void show(xcb_window_t window) {
|
void show(xcb_window_t window) { xcb_map_window(conn, window); }
|
||||||
xcb_map_window(conn, window);
|
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide a window
|
// Hide a window
|
||||||
void hide(xcb_window_t window) {
|
void hide(xcb_window_t window) { xcb_unmap_window(conn, window); }
|
||||||
xcb_unmap_window(conn, window);
|
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bring a window to the top of the stack
|
// Bring a window to the top of the stack
|
||||||
void send_to_top(xcb_window_t win) {
|
void send_to_top(xcb_window_t win) {
|
||||||
uint32_t values[1] = {XCB_STACK_MODE_ABOVE};
|
uint32_t values[1] = {XCB_STACK_MODE_ABOVE};
|
||||||
xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_STACK_MODE, values);
|
xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_STACK_MODE, values);
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the geometry of a window
|
// Get the geometry of a window
|
||||||
@@ -139,7 +129,6 @@ Geometry get_screen(void) {
|
|||||||
// the center)
|
// the center)
|
||||||
void warp_pointer(xcb_window_t win, int x, int y) {
|
void warp_pointer(xcb_window_t win, int x, int y) {
|
||||||
xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0, x, y);
|
xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0, x, y);
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move a window to a specific position
|
// Move a window to a specific position
|
||||||
@@ -147,7 +136,6 @@ void move_window(xcb_window_t win, int x, int y) {
|
|||||||
uint32_t values[2] = {x, y};
|
uint32_t values[2] = {x, y};
|
||||||
xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
|
xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
|
||||||
values);
|
values);
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize a window to specific dimensions
|
// Resize a window to specific dimensions
|
||||||
@@ -155,7 +143,6 @@ void resize_window(xcb_window_t win, int width, int height) {
|
|||||||
uint32_t values[2] = {width, height};
|
uint32_t values[2] = {width, height};
|
||||||
xcb_configure_window(
|
xcb_configure_window(
|
||||||
conn, win, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
|
conn, win, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_size_hints_t get_wm_n_hints(xcb_window_t win) {
|
xcb_size_hints_t get_wm_n_hints(xcb_window_t win) {
|
||||||
@@ -200,8 +187,6 @@ void set_wm_state(xcb_window_t win, int state) {
|
|||||||
|
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, WM_STATE, WM_STATE, 32,
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, WM_STATE, WM_STATE, 32,
|
||||||
2, data);
|
2, data);
|
||||||
|
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_window_t draw_rectangle(int x, int y, int width, int height,
|
xcb_window_t draw_rectangle(int x, int y, int width, int height,
|
||||||
@@ -242,9 +227,6 @@ xcb_window_t draw_rectangle(int x, int y, int width, int height,
|
|||||||
xcb_rectangle_t rect = {0, 0, width, height}; // relative to window
|
xcb_rectangle_t rect = {0, 0, width, height}; // relative to window
|
||||||
xcb_poly_fill_rectangle(conn, win, gc, 1, &rect);
|
xcb_poly_fill_rectangle(conn, win, gc, 1, &rect);
|
||||||
|
|
||||||
// Flush the connection to send commands to the server
|
|
||||||
xcb_flush(conn);
|
|
||||||
|
|
||||||
return win;
|
return win;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,25 +239,18 @@ void grab_pointer(xcb_window_t win) {
|
|||||||
XCB_EVENT_MASK_POINTER_MOTION_HINT,
|
XCB_EVENT_MASK_POINTER_MOTION_HINT,
|
||||||
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE,
|
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE,
|
||||||
XCB_CURRENT_TIME);
|
XCB_CURRENT_TIME);
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ungrab_pointer(void) {
|
void ungrab_pointer(void) { xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); }
|
||||||
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
|
|
||||||
xcb_flush(conn);
|
xcb_generic_event_t *next_event(void) { return xcb_poll_for_event(conn); }
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for an event and return it as an Event structure
|
// Wait for an event and return it as an Event structure
|
||||||
// This function is blocking
|
// This function is blocking
|
||||||
// The event is sent by value, so no need to free anything
|
// The event is sent by value, so no need to free anything
|
||||||
Event wait_for_event(void) {
|
Event translate_event(xcb_generic_event_t *ev) {
|
||||||
Event ret = {0};
|
Event ret = {0};
|
||||||
|
|
||||||
xcb_flush(conn);
|
|
||||||
|
|
||||||
xcb_generic_event_t *ev;
|
|
||||||
ev = xcb_wait_for_event(conn);
|
|
||||||
|
|
||||||
if (!ev)
|
if (!ev)
|
||||||
errx(1, "xcb connection broken");
|
errx(1, "xcb connection broken");
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ typedef struct Event {
|
|||||||
} Event;
|
} Event;
|
||||||
|
|
||||||
// Function prototypes
|
// Function prototypes
|
||||||
|
void flush(void);
|
||||||
int deploy(void);
|
int deploy(void);
|
||||||
void cleanup(void);
|
void cleanup(void);
|
||||||
|
|
||||||
@@ -89,6 +90,7 @@ xcb_window_t draw_rectangle(int x, int y, int width, int height,
|
|||||||
void grab_pointer(xcb_window_t win);
|
void grab_pointer(xcb_window_t win);
|
||||||
void ungrab_pointer(void);
|
void ungrab_pointer(void);
|
||||||
|
|
||||||
Event wait_for_event(void);
|
xcb_generic_event_t *next_event(void);
|
||||||
|
Event translate_event(xcb_generic_event_t *ev);
|
||||||
|
|
||||||
#endif // X_KUTU_H
|
#endif // X_KUTU_H
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ module X
|
|||||||
:window_group, :xcb_window_t
|
:window_group, :xcb_window_t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attach_function :flush, [], :void
|
||||||
attach_function :deploy, [], :int
|
attach_function :deploy, [], :int
|
||||||
attach_function :add_keybind, [:int, :int], :void
|
attach_function :add_keybind, [:int, :int], :void
|
||||||
attach_function :add_mousebind, [:int, :int], :void
|
attach_function :add_mousebind, [:int, :int], :void
|
||||||
@@ -79,7 +80,8 @@ module X
|
|||||||
attach_function :warp_pointer, [:xcb_window_t, :int, :int], :void
|
attach_function :warp_pointer, [:xcb_window_t, :int, :int], :void
|
||||||
attach_function :move_window, [:xcb_window_t, :int, :int], :void
|
attach_function :move_window, [:xcb_window_t, :int, :int], :void
|
||||||
attach_function :resize_window, [:xcb_window_t, :int, :int], :void
|
attach_function :resize_window, [:xcb_window_t, :int, :int], :void
|
||||||
attach_function :wait_for_event, [], Event.by_value
|
attach_function :translate_event, [:pointer], Event.by_value
|
||||||
|
attach_function :next_event, [], :pointer
|
||||||
attach_function :get_wm_name, [:xcb_window_t], :string
|
attach_function :get_wm_name, [:xcb_window_t], :string
|
||||||
attach_function :get_wm_n_hints, [:xcb_window_t], SizeHints.by_value
|
attach_function :get_wm_n_hints, [:xcb_window_t], SizeHints.by_value
|
||||||
attach_function :get_wm_hints, [:xcb_window_t], WMHints.by_value
|
attach_function :get_wm_hints, [:xcb_window_t], WMHints.by_value
|
||||||
|
|||||||
@@ -1,71 +1,115 @@
|
|||||||
keybind(23) do |_event|
|
keybind 23 do |_event|
|
||||||
run "firefox"
|
run "firefox"
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(24) do |event|
|
keybind 24 do |event|
|
||||||
X.kill event[:window]
|
X.kill event[:window]
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(25) do |_event|
|
keybind 25 do |_event|
|
||||||
run "kitty"
|
run "kitty"
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(26) do |_event|
|
keybind 26 do |_event|
|
||||||
# run "~/dotfiles/scripts/power.sh"
|
run "~/dotfiles/scripts/power.sh"
|
||||||
exit 1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(38) do |_event|
|
keybind 123, 0 do |_event|
|
||||||
|
run "pactl set-sink-volume @DEFAULT_SINK@ +5%;vol=$(pactl get-sink-volume @DEFAULT_SINK@ | grep -o '[0-9]\+%' | head -n1);dunstify 'Volume Adjusted' '' -h int:value:$vol -r 997"
|
||||||
|
end
|
||||||
|
|
||||||
|
keybind 122, 0 do |_event|
|
||||||
|
run "pactl set-sink-volume @DEFAULT_SINK@ -5%;vol=$(pactl get-sink-volume @DEFAULT_SINK@ | grep -o '[0-9]\+%' | head -n1);dunstify 'Volume Adjusted' '' -h int:value:$vol -r 997"
|
||||||
|
end
|
||||||
|
|
||||||
|
keybind 121, 0 do |_event|
|
||||||
|
run "pactl set-sink-mute @DEFAULT_SINK@ toggle;vol=$(pactl get-sink-volume @DEFAULT_SINK@ | grep -o '[0-9]\+%' | head -n1);dunstify 'Volume Adjusted' '' -h int:value:$vol -r 997"
|
||||||
|
end
|
||||||
|
|
||||||
|
keybind 38 do |_event|
|
||||||
run "maim -c 0.3,0.5,1.0,0.8 -s | tee /tmp/screenshot_temp.png | xclip -selection clipboard -t image/png && if [ -s '/tmp/screenshot_temp.png' ]; then mv /tmp/screenshot_temp.png ~/screenshots/$(date +%Y-%m-%d_%H:%M:%S).png; fi"
|
run "maim -c 0.3,0.5,1.0,0.8 -s | tee /tmp/screenshot_temp.png | xclip -selection clipboard -t image/png && if [ -s '/tmp/screenshot_temp.png' ]; then mv /tmp/screenshot_temp.png ~/screenshots/$(date +%Y-%m-%d_%H:%M:%S).png; fi"
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(54) do |_event|
|
keybind 54 do |_event|
|
||||||
run "kitty -e fish -c \"y\""
|
run "kitty -e fish -c \"y\""
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(53) do |_event|
|
keybind 53 do |_event|
|
||||||
run "kitty -e fish -c \"editor\""
|
run "kitty -e fish -c \"editor\""
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(40) do |_event|
|
keybind 40 do |_event|
|
||||||
run "~/dotfiles/scripts/run.sh"
|
run "~/dotfiles/scripts/run.sh"
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(33) do |_event|
|
keybind 33 do |_event|
|
||||||
run "~/.config/polybar/launch.sh"
|
run "~/.config/polybar/launch.sh"
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(56) do |_event|
|
keybind 45 do |_event|
|
||||||
|
run "~/dotfiles/scripts/caffiene.sh"
|
||||||
|
end
|
||||||
|
|
||||||
|
keybind 56 do |_event|
|
||||||
monitor = current_monitor
|
monitor = current_monitor
|
||||||
create_workspace monitor
|
create_workspace monitor
|
||||||
persistence_path = File.join(__dir__, ".num.json")
|
persistence_path = File.join(__dir__, ".num.json")
|
||||||
persistence = File.exist?(persistence_path) ?
|
persistence = File.exist?(persistence_path) ?
|
||||||
JSON.parse(File.read(persistence_path), symbolize_names: true) :
|
JSON.parse(File.read(persistence_path), symbolize_names: true) :
|
||||||
{}
|
{}
|
||||||
persistence[$monitors.key(monitor)] = monitor[:workspaces].length
|
persistence[$monitors.key(monitor)] ||= {}
|
||||||
|
persistence[$monitors.key(monitor)][:length] = monitor[:workspaces].length
|
||||||
File.write(persistence_path, JSON.pretty_generate(persistence))
|
File.write(persistence_path, JSON.pretty_generate(persistence))
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(57) do |_event|
|
keybind 57 do |_event|
|
||||||
monitor = current_monitor
|
monitor = current_monitor
|
||||||
delete_workspace monitor[:workspaces].length - 1, monitor
|
delete_workspace monitor[:workspaces].length - 1, monitor
|
||||||
persistence_path = File.join(__dir__, ".num.json")
|
persistence_path = File.join(__dir__, ".num.json")
|
||||||
persistence = File.exist?(persistence_path) ?
|
persistence = File.exist?(persistence_path) ?
|
||||||
JSON.parse(File.read(persistence_path), symbolize_names: true) :
|
JSON.parse(File.read(persistence_path), symbolize_names: true) :
|
||||||
{}
|
{}
|
||||||
persistence[$monitors.key(monitor)] = monitor[:workspaces].length
|
persistence[$monitors.key(monitor)] ||= {}
|
||||||
|
persistence[$monitors.key(monitor)][:length] = monitor[:workspaces].length
|
||||||
File.write(persistence_path, JSON.pretty_generate(persistence))
|
File.write(persistence_path, JSON.pretty_generate(persistence))
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(112, 0) do |_event|
|
keybind 110, 0 do |_event|
|
||||||
|
run "dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause;" \
|
||||||
|
"dbus-send --print-reply --dest=$(busctl --user list | grep -oP 'org.mpris.MediaPlayer2.firefox.instance_1_\d+') /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause"
|
||||||
|
end
|
||||||
|
|
||||||
|
keybind 110 do |_event|
|
||||||
monitor = current_monitor
|
monitor = current_monitor
|
||||||
next_ws = (monitor[:selected_workspace] + 1) % monitor[:workspaces].length
|
persistence_path = File.join(__dir__, ".num.json")
|
||||||
|
persistence = File.exist?(persistence_path) ?
|
||||||
|
JSON.parse(File.read(persistence_path), symbolize_names: true) :
|
||||||
|
{}
|
||||||
|
if monitor[:selected_workspace] == 0
|
||||||
|
select_workspace persistence[$monitors.key(monitor)]&.[](:saved) || 1, monitor
|
||||||
|
else
|
||||||
|
persistence[$monitors.key(monitor)] ||= {}
|
||||||
|
persistence[$monitors.key(monitor)][:saved] = monitor[:selected_workspace]
|
||||||
|
File.write(persistence_path, JSON.pretty_generate(persistence))
|
||||||
|
select_workspace 0, monitor
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
keybind 118, 0 do |_event|
|
||||||
|
run "dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause"
|
||||||
|
end
|
||||||
|
|
||||||
|
keybind 117, 0 do |_event|
|
||||||
|
monitor = current_monitor
|
||||||
|
next if monitor[:selected_workspace].zero?
|
||||||
|
next_ws = (monitor[:selected_workspace] % (monitor[:workspaces].length - 1)) + 1
|
||||||
select_workspace next_ws, monitor
|
select_workspace next_ws, monitor
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(112) do |_event|
|
keybind 117 do |_event|
|
||||||
monitor = current_monitor
|
|
||||||
pointer = X.get_pointer
|
pointer = X.get_pointer
|
||||||
|
monitor = current_monitor pointer
|
||||||
|
next if monitor[:selected_workspace].zero?
|
||||||
|
|
||||||
window = monitor[:workspaces][monitor[:selected_workspace]].windows.find do |w|
|
window = monitor[:workspaces][monitor[:selected_workspace]].windows.find do |w|
|
||||||
pointer[:x] >= w.x &&
|
pointer[:x] >= w.x &&
|
||||||
@@ -74,19 +118,21 @@ keybind(112) do |_event|
|
|||||||
pointer[:y] < w.y + w.height
|
pointer[:y] < w.y + w.height
|
||||||
end
|
end
|
||||||
|
|
||||||
next_ws = (monitor[:selected_workspace] + 1) % monitor[:workspaces].length
|
next_ws = (monitor[:selected_workspace] % (monitor[:workspaces].length - 1)) + 1
|
||||||
monitor[:workspaces][next_ws].drop monitor[:workspaces][next_ws].tiled_windows.length, window if window
|
monitor[:workspaces][next_ws].drop monitor[:workspaces][next_ws].tiled_windows.length, window if window
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(117, 0) do |_event|
|
keybind 112, 0 do |_event|
|
||||||
monitor = current_monitor
|
monitor = current_monitor
|
||||||
next_ws = (monitor[:selected_workspace] - 1) % monitor[:workspaces].length
|
next if monitor[:selected_workspace].zero?
|
||||||
|
next_ws = ((monitor[:selected_workspace] - 2) % (monitor[:workspaces].length - 1)) + 1
|
||||||
select_workspace next_ws, monitor
|
select_workspace next_ws, monitor
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(117) do |_event|
|
keybind 112 do |_event|
|
||||||
monitor = current_monitor
|
|
||||||
pointer = X.get_pointer
|
pointer = X.get_pointer
|
||||||
|
monitor = current_monitor pointer
|
||||||
|
next if monitor[:selected_workspace].zero?
|
||||||
|
|
||||||
window = monitor[:workspaces][monitor[:selected_workspace]].windows.find do |w|
|
window = monitor[:workspaces][monitor[:selected_workspace]].windows.find do |w|
|
||||||
pointer[:x] >= w.x &&
|
pointer[:x] >= w.x &&
|
||||||
@@ -95,21 +141,22 @@ keybind(117) do |_event|
|
|||||||
pointer[:y] < w.y + w.height
|
pointer[:y] < w.y + w.height
|
||||||
end
|
end
|
||||||
|
|
||||||
next_ws = (monitor[:selected_workspace] - 1) % monitor[:workspaces].length
|
next_ws = ((monitor[:selected_workspace] - 2) % (monitor[:workspaces].length - 1)) + 1
|
||||||
monitor[:workspaces][next_ws].drop monitor[:workspaces][next_ws].tiled_windows.length, window if window
|
monitor[:workspaces][next_ws].drop monitor[:workspaces][next_ws].tiled_windows.length, window if window
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(27) do |_event|
|
keybind 27 do |_event|
|
||||||
|
load File.join(__dir__, "./bindings.rb")
|
||||||
monitor = current_monitor
|
monitor = current_monitor
|
||||||
return unless monitor
|
next unless monitor
|
||||||
monitor[:workspaces][monitor[:selected_workspace]].switch_direction
|
monitor[:workspaces][monitor[:selected_workspace]].switch_direction
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(55) do |_event|
|
keybind 55 do |_event|
|
||||||
run "rofi -modi 'clipboard:greenclip print' -show clipboard -run-command '{cmd}'"
|
run "rofi -modi 'clipboard:greenclip print' -show clipboard -run-command '{cmd}'"
|
||||||
end
|
end
|
||||||
|
|
||||||
keybind(39) do |event|
|
keybind 39 do |event|
|
||||||
window = $windows[event[:window]]
|
window = $windows[event[:window]]
|
||||||
window.toggle_floating if window
|
window.toggle_floating if window
|
||||||
end
|
end
|
||||||
@@ -119,36 +166,17 @@ mousebind 1
|
|||||||
|
|
||||||
mousebind 3
|
mousebind 3
|
||||||
|
|
||||||
mousebind(8, 0) do |_event|
|
mousebind 9, 0 do |_event|
|
||||||
monitor = current_monitor
|
monitor = current_monitor
|
||||||
next_ws = (monitor[:selected_workspace] + 1) % monitor[:workspaces].length
|
next if monitor[:selected_workspace].zero?
|
||||||
select_workspace next_ws, monitor
|
next_ws = (monitor[:selected_workspace] % (monitor[:workspaces].length - 1)) + 1
|
||||||
end
|
|
||||||
|
|
||||||
mousebind 8 do |_event|
|
|
||||||
monitor = current_monitor
|
|
||||||
pointer = X.get_pointer
|
|
||||||
|
|
||||||
window = monitor[:workspaces][monitor[:selected_workspace]].windows.find do |w|
|
|
||||||
pointer[:x] >= w.x &&
|
|
||||||
pointer[:x] < w.x + w.width &&
|
|
||||||
pointer[:y] >= w.y &&
|
|
||||||
pointer[:y] < w.y + w.height
|
|
||||||
end
|
|
||||||
|
|
||||||
next_ws = (monitor[:selected_workspace] + 1) % monitor[:workspaces].length
|
|
||||||
monitor[:workspaces][next_ws].drop monitor[:workspaces][next_ws].tiled_windows.length, window if window
|
|
||||||
end
|
|
||||||
|
|
||||||
mousebind(9, 0) do |_event|
|
|
||||||
monitor = current_monitor
|
|
||||||
next_ws = (monitor[:selected_workspace] - 1) % monitor[:workspaces].length
|
|
||||||
select_workspace next_ws, monitor
|
select_workspace next_ws, monitor
|
||||||
end
|
end
|
||||||
|
|
||||||
mousebind 9 do |_event|
|
mousebind 9 do |_event|
|
||||||
monitor = current_monitor
|
|
||||||
pointer = X.get_pointer
|
pointer = X.get_pointer
|
||||||
|
monitor = current_monitor pointer
|
||||||
|
next if monitor[:selected_workspace].zero?
|
||||||
|
|
||||||
window = monitor[:workspaces][monitor[:selected_workspace]].windows.find do |w|
|
window = monitor[:workspaces][monitor[:selected_workspace]].windows.find do |w|
|
||||||
pointer[:x] >= w.x &&
|
pointer[:x] >= w.x &&
|
||||||
@@ -157,6 +185,29 @@ mousebind 9 do |_event|
|
|||||||
pointer[:y] < w.y + w.height
|
pointer[:y] < w.y + w.height
|
||||||
end
|
end
|
||||||
|
|
||||||
next_ws = (monitor[:selected_workspace] - 1) % monitor[:workspaces].length
|
next_ws = (monitor[:selected_workspace] % (monitor[:workspaces].length - 1)) + 1
|
||||||
|
monitor[:workspaces][next_ws].drop monitor[:workspaces][next_ws].tiled_windows.length, window if window
|
||||||
|
end
|
||||||
|
|
||||||
|
mousebind 8, 0 do |_event|
|
||||||
|
monitor = current_monitor
|
||||||
|
next if monitor[:selected_workspace].zero?
|
||||||
|
next_ws = ((monitor[:selected_workspace] - 2) % (monitor[:workspaces].length - 1)) + 1
|
||||||
|
select_workspace next_ws, monitor
|
||||||
|
end
|
||||||
|
|
||||||
|
mousebind 8 do |_event|
|
||||||
|
pointer = X.get_pointer
|
||||||
|
monitor = current_monitor pointer
|
||||||
|
next if monitor[:selected_workspace].zero?
|
||||||
|
|
||||||
|
window = monitor[:workspaces][monitor[:selected_workspace]].windows.find do |w|
|
||||||
|
pointer[:x] >= w.x &&
|
||||||
|
pointer[:x] < w.x + w.width &&
|
||||||
|
pointer[:y] >= w.y &&
|
||||||
|
pointer[:y] < w.y + w.height
|
||||||
|
end
|
||||||
|
|
||||||
|
next_ws = ((monitor[:selected_workspace] - 2) % (monitor[:workspaces].length - 1)) + 1
|
||||||
monitor[:workspaces][next_ws].drop monitor[:workspaces][next_ws].tiled_windows.length, window if window
|
monitor[:workspaces][next_ws].drop monitor[:workspaces][next_ws].tiled_windows.length, window if window
|
||||||
end
|
end
|
||||||
|
|||||||
29
src/ruby/commands.rb
Normal file
29
src/ruby/commands.rb
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
def handle_command(command)
|
||||||
|
reply = {}
|
||||||
|
|
||||||
|
command_parts = command.split(" ")
|
||||||
|
command = command_parts[0]
|
||||||
|
args = command_parts[1..-1]
|
||||||
|
|
||||||
|
case command
|
||||||
|
when "get-ws"
|
||||||
|
monitor = args[0] ? $monitors[args[0].to_sym] : current_monitor
|
||||||
|
return reply if monitor.nil?
|
||||||
|
reply[:workspace] = monitor[:selected_workspace]
|
||||||
|
reply[:monitor] = $monitors.key(monitor)
|
||||||
|
reply[:count] = monitor[:workspaces].length
|
||||||
|
when "set-ws"
|
||||||
|
monitor = args[1] ? $monitors[args[1].to_sym] : current_monitor
|
||||||
|
return reply if monitor.nil?
|
||||||
|
select_workspace args[0].to_i, monitor
|
||||||
|
reply[:workspace] = monitor[:selected_workspace]
|
||||||
|
reply[:monitor] = $monitors.key(monitor)
|
||||||
|
reply[:count] = monitor[:workspaces].length
|
||||||
|
when "topped"
|
||||||
|
reply[:topped] = $topped_windows
|
||||||
|
when "stop"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
reply
|
||||||
|
end
|
||||||
@@ -4,7 +4,7 @@ def create_workspace(monitor)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def delete_workspace(n, monitor)
|
def delete_workspace(n, monitor)
|
||||||
return if monitor[:workspaces].length <= 1
|
return if monitor[:workspaces].length <= 2
|
||||||
monitor[:workspaces][n].windows.each { |w| monitor[:workspaces][(n - 1) % monitor[:workspaces].length].drop 0, w }
|
monitor[:workspaces][n].windows.each { |w| monitor[:workspaces][(n - 1) % monitor[:workspaces].length].drop 0, w }
|
||||||
monitor[:workspaces].delete_at n
|
monitor[:workspaces].delete_at n
|
||||||
if monitor[:selected_workspace] >= n
|
if monitor[:selected_workspace] >= n
|
||||||
@@ -13,6 +13,11 @@ def delete_workspace(n, monitor)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def select_workspace(n, monitor)
|
def select_workspace(n, monitor)
|
||||||
|
if n >= monitor[:workspaces].length
|
||||||
|
select_workspace monitor[:workspaces].length - 1, monitor
|
||||||
|
elsif n < 0
|
||||||
|
select_workspace 1, monitor
|
||||||
|
end
|
||||||
monitor[:workspaces].each { |w| w.hide if w != monitor[:workspaces][n] }
|
monitor[:workspaces].each { |w| w.hide if w != monitor[:workspaces][n] }
|
||||||
monitor[:selected_workspace] = n
|
monitor[:selected_workspace] = n
|
||||||
monitor[:workspaces][n].show
|
monitor[:workspaces][n].show
|
||||||
|
|||||||
@@ -20,12 +20,15 @@ def handle_event(event)
|
|||||||
|
|
||||||
|
|
||||||
when :create
|
when :create
|
||||||
|
$all_windows << event[:window]
|
||||||
return unless event[:override_redirect].zero?
|
return unless event[:override_redirect].zero?
|
||||||
X.subscribe event[:window]
|
X.subscribe event[:window]
|
||||||
|
|
||||||
|
|
||||||
when :closed
|
when :closed
|
||||||
|
$all_windows.delete event[:window]
|
||||||
$windows[event[:window]]&.delete
|
$windows[event[:window]]&.delete
|
||||||
|
X.focus $root
|
||||||
|
|
||||||
|
|
||||||
when :enter
|
when :enter
|
||||||
@@ -37,6 +40,10 @@ def handle_event(event)
|
|||||||
if $windows[event[:window]].nil?
|
if $windows[event[:window]].nil?
|
||||||
monitor[:workspaces][monitor[:selected_workspace]].create event[:window]
|
monitor[:workspaces][monitor[:selected_workspace]].create event[:window]
|
||||||
X.show event[:window]
|
X.show event[:window]
|
||||||
|
$all_windows.each do |window|
|
||||||
|
above = `xprop -id #{window} _NET_WM_STATE`
|
||||||
|
X.send_to_top window if above.include?("ABOVE")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'json'
|
|
||||||
|
|
||||||
def keybind(key, mod = 1, &block)
|
def keybind(key, mod = 1, &block)
|
||||||
X.add_keybind key, mod
|
X.add_keybind key, mod
|
||||||
$keybind_actions[[key, mod]] = block if block
|
$keybind_actions[[key, mod]] = block if block
|
||||||
@@ -31,7 +29,11 @@ def load_monitors!
|
|||||||
next unless line =~ /(\d+)x(\d+)\+(\d+)\+(\d+)/
|
next unless line =~ /(\d+)x(\d+)\+(\d+)\+(\d+)/
|
||||||
w, h, x, y = $1.to_i, $2.to_i, $3.to_i, $4.to_i
|
w, h, x, y = $1.to_i, $2.to_i, $3.to_i, $4.to_i
|
||||||
key = index.zero? ? :primary : :secondary
|
key = index.zero? ? :primary : :secondary
|
||||||
$monitors[key] = { x: x, y: y, width: w, height: h, workspaces: Array.new(persistence[key] || 1) { Workspace.new(key) }, selected_workspace: 0 }
|
$monitors[key] = {
|
||||||
|
x: x, y: y, width: w, height: h,
|
||||||
|
workspaces: Array.new(persistence[key]&.[](:length) || 2) { Workspace.new(key) },
|
||||||
|
selected_workspace: 1
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -22,12 +22,7 @@ class Window
|
|||||||
apply_geometry!
|
apply_geometry!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
wm_hints = X.get_wm_hints(window_id)
|
|
||||||
if wm_hints
|
|
||||||
if wm_hints[:flags] & 1 != 0 && wm_hints[:initial_state] == 3
|
|
||||||
X.set_wm_state window_id, 1
|
X.set_wm_state window_id, 1
|
||||||
end
|
|
||||||
end
|
|
||||||
transient_for = X.get_wm_transient_for(window_id)
|
transient_for = X.get_wm_transient_for(window_id)
|
||||||
unless transient_for.zero?
|
unless transient_for.zero?
|
||||||
@floating = true
|
@floating = true
|
||||||
|
|||||||
@@ -144,10 +144,17 @@ class Workspace
|
|||||||
end
|
end
|
||||||
|
|
||||||
def hide
|
def hide
|
||||||
self.windows.each { |window| X.hide window.window_id }
|
self.windows.each do |window|
|
||||||
|
X.hide window.window_id
|
||||||
|
X.set_wm_state window.window_id, 3
|
||||||
|
end
|
||||||
|
X.focus $root
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
self.windows.each { |window| X.show window.window_id }
|
self.windows.each do |window|
|
||||||
|
X.show window.window_id
|
||||||
|
X.set_wm_state window.window_id, 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
picom --config ~/.config/i3/picom.conf &
|
picom --config ~/.config/i3/picom.conf &
|
||||||
greenclip daemon &
|
greenclip daemon &
|
||||||
xss-lock --transfer-sleep-lock -- ~/dotfiles/scripts/lock.sh &
|
# xss-lock --transfer-sleep-lock -- ~/dotfiles/scripts/lock.sh &
|
||||||
dunst -config ~/.config/dunst/dunstrc &
|
dunst -config ~/.config/dunst/dunstrc &
|
||||||
|
|
||||||
bluetoothctl power off
|
bluetoothctl power off
|
||||||
@@ -13,5 +13,3 @@ xsetroot -cursor_name left_ptr
|
|||||||
|
|
||||||
xrdb ~/.Xresources
|
xrdb ~/.Xresources
|
||||||
setxkbmap us
|
setxkbmap us
|
||||||
|
|
||||||
~/.config/polybar/launch.sh special &>>"$LOGFILE" &
|
|
||||||
|
|||||||
Reference in New Issue
Block a user