Initial
This commit is contained in:
224
kutu.rb
Executable file
224
kutu.rb
Executable file
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require "ffi"
|
||||
|
||||
module X
|
||||
extend FFI::Library
|
||||
ffi_lib "/home/syed/main/kutu/X-kutu.so"
|
||||
|
||||
typedef :uint32, :window_id
|
||||
typedef :pointer, :goemetry_array
|
||||
|
||||
class Geometry < FFI::Struct
|
||||
layout :x, :int16,
|
||||
:y, :int16,
|
||||
:width, :uint16,
|
||||
:height, :uint16
|
||||
end
|
||||
|
||||
class Event < FFI::Struct
|
||||
layout :type, :int32,
|
||||
:window, :window_id,
|
||||
:override_redirect, :int8,
|
||||
:btn, :uint32,
|
||||
:x, :int32,
|
||||
:y, :int32,
|
||||
:height, :uint32,
|
||||
:width, :uint32,
|
||||
:state, :uint32,
|
||||
:is_root, :int8
|
||||
end
|
||||
|
||||
attach_function :deploy, [], :int
|
||||
attach_function :add_keybind, [:int], :void
|
||||
attach_function :add_mousebind, [:int], :void
|
||||
attach_function :cleanup, [], :void
|
||||
attach_function :focus, [:window_id], :void
|
||||
attach_function :get_focus, [], :window_id
|
||||
attach_function :subscribe, [:window_id], :void
|
||||
attach_function :kill, [:window_id], :void
|
||||
attach_function :show, [:window_id], :void
|
||||
attach_function :hide, [:window_id], :void
|
||||
attach_function :send_to_top, [:window_id], :void
|
||||
attach_function :xrandr_get_monitors, [], :goemetry_array
|
||||
attach_function :free_geometry, [:goemetry_array], :void
|
||||
attach_function :get_geometry, [:window_id], Geometry.by_value
|
||||
attach_function :get_pointer, [], Geometry.by_value
|
||||
attach_function :get_screen, [], Geometry.by_value
|
||||
attach_function :warp_pointer, [:window_id, :int, :int], :void
|
||||
attach_function :move_window, [:window_id, :int, :int], :void
|
||||
attach_function :resize_window, [:window_id, :int, :int], :void
|
||||
attach_function :wait_for_event, [], Event.by_value
|
||||
|
||||
def self.get_monitors
|
||||
ptr = xrandr_get_monitors
|
||||
return [] if ptr.null?
|
||||
monitors = []
|
||||
2.times do |i|
|
||||
geom_ptr = ptr + i * Geometry.size
|
||||
geom = Geometry.new(geom_ptr)
|
||||
break if geom[:width] == 0 || geom[:height] == 0
|
||||
monitors << geom
|
||||
end
|
||||
free_geometry(ptr)
|
||||
monitors
|
||||
end
|
||||
end
|
||||
|
||||
if X.deploy < 0
|
||||
raise "Failed to deploy X"
|
||||
exit 1
|
||||
end
|
||||
|
||||
at_exit { X.cleanup }
|
||||
|
||||
$monitors = X.get_monitors
|
||||
|
||||
$monitors.each do |monitor|
|
||||
puts "Monitor: #{monitor[:x]} #{monitor[:y]} #{monitor[:width]} #{monitor[:height]}"
|
||||
end
|
||||
|
||||
$workspaces = {}
|
||||
$windows = {}
|
||||
|
||||
class Window
|
||||
attr_reader :window_id
|
||||
|
||||
def initialize(window_id)
|
||||
@window_id = window_id
|
||||
end
|
||||
end
|
||||
|
||||
class Workspace
|
||||
attr_reader :windows, :name, :screen
|
||||
|
||||
def initialize(name)
|
||||
@windows = {}
|
||||
@name = name
|
||||
@screen = :main
|
||||
end
|
||||
|
||||
def add(window_id)
|
||||
@windows[window_id] = Window.new(window_id)
|
||||
$windows[window_id] = self
|
||||
end
|
||||
|
||||
def remove(window_id)
|
||||
@windows.delete window_id
|
||||
$windows.delete window_id
|
||||
end
|
||||
|
||||
def close_all
|
||||
@windows.each_key do |window|
|
||||
X.kill window
|
||||
self.remove window
|
||||
end
|
||||
end
|
||||
|
||||
def hide
|
||||
@windows.each_key do |window|
|
||||
X.hide window
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@windows.each_key do |window|
|
||||
X.show window
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
EVENT_TYPES = {
|
||||
0 => :unused,
|
||||
1 => :create,
|
||||
2 => :close,
|
||||
3 => :enter,
|
||||
4 => :show,
|
||||
5 => :mouse_press,
|
||||
6 => :mouse_drag,
|
||||
7 => :mouse_release,
|
||||
8 => :key_press,
|
||||
9 => :key_release,
|
||||
10 => :configured
|
||||
}.freeze
|
||||
|
||||
$workspaces[:main] = Workspace.new(:main)
|
||||
|
||||
X.add_keybind 24
|
||||
X.add_keybind 25
|
||||
X.add_keybind 26
|
||||
X.add_mousebind 1
|
||||
X.add_mousebind 3
|
||||
|
||||
$mouse_state = -1
|
||||
$mouse_window = -1
|
||||
|
||||
loop do
|
||||
event = X.wait_for_event
|
||||
case EVENT_TYPES[event[:type]]
|
||||
when :create
|
||||
if event[:override_redirect] == 0
|
||||
X.subscribe event[:window]
|
||||
X.focus event[:window]
|
||||
$workspaces[:main].add event[:window]
|
||||
end
|
||||
when :close
|
||||
X.kill event[:window]
|
||||
$windows[event[:window]].remove event[:window]
|
||||
when :enter
|
||||
X.focus event[:window]
|
||||
X.send_to_top event[:window]
|
||||
when :show
|
||||
X.show event[:window]
|
||||
X.focus event[:window]
|
||||
when :mouse_press
|
||||
next if event[:is_root] != 0
|
||||
X.send_to_top event[:window]
|
||||
$mouse_state = event[:btn]
|
||||
$mouse_window = event[:window]
|
||||
$mouse_pos_start = X.get_pointer
|
||||
$geom_start = X.get_geometry event[:window]
|
||||
when :mouse_drag
|
||||
screen_bounds = $monitors[0]
|
||||
mouse_pos = X.get_pointer
|
||||
dx = mouse_pos[:x] - $mouse_pos_start[:x]
|
||||
dy = mouse_pos[:y] - $mouse_pos_start[:y]
|
||||
if $mouse_state == 1
|
||||
new_x = [[$geom_start[:x] + dx, screen_bounds[:x]].max,
|
||||
screen_bounds[:x] + screen_bounds[:width] - $geom_start[:width]].min
|
||||
new_y = [[$geom_start[:y] + dy, screen_bounds[:y]].max,
|
||||
screen_bounds[:y] + screen_bounds[:height] - $geom_start[:height]].min
|
||||
X.move_window $mouse_window, new_x, new_y
|
||||
elsif $mouse_state == 3
|
||||
X.resize_window $mouse_window,
|
||||
[$geom_start[:width] + dx, 50].max,
|
||||
[$geom_start[:height] + dy, 50].max
|
||||
end
|
||||
when :mouse_release
|
||||
if [1, 3].include?($mouse_state)
|
||||
X.focus $mouse_window
|
||||
X.send_to_top $mouse_window
|
||||
$mouse_state = -1
|
||||
$mouse_window = -1
|
||||
$mouse_pos_start = { x: -1, y: -1 }
|
||||
$geom_start = nil
|
||||
end
|
||||
when :key_press
|
||||
case event[:btn]
|
||||
when 24
|
||||
X.kill event[:window]
|
||||
when 25
|
||||
pid = spawn("kitty")
|
||||
Process.detach pid
|
||||
when 26
|
||||
$workspaces.each_value do |workspace|
|
||||
workspace.close_all
|
||||
end
|
||||
exit 1
|
||||
end
|
||||
when :key_release
|
||||
# TODO
|
||||
when :configured
|
||||
# TODO
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user