wmctile 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/wmctile +5 -0
- data/lib/wmctile/class.rb +13 -0
- data/lib/wmctile/class_with_dmenu.rb +24 -0
- data/lib/wmctile/memory.rb +64 -0
- data/lib/wmctile/router.rb +187 -0
- data/lib/wmctile/settings.rb +56 -0
- data/lib/wmctile/window.rb +69 -0
- data/lib/wmctile/window_manager.rb +174 -0
- data/lib/wmctile/window_tiler.rb +95 -0
- metadata +10 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4216479b45b21cb886179229cc5575b55b3fe1f
|
4
|
+
data.tar.gz: fb6b1145637252d54ba0620ed27ee10bc94dd206
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58ecfd20728f51d591d0b13d241046acae6bf1047ec37b9feb9158ae9275299a6506cfb1b76d9e6785d5be361a43328caed81a31e1eee8b6d6596048c4f77691
|
7
|
+
data.tar.gz: 5d981b8f5400b7fb1762e69797d33e764135a6052074db3073c96e7acd12626fa7ecfb988152a13ed0e8e5ce0959c85c9568fdb5d3cda9b5be98e047c19d0009
|
data/bin/wmctile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class Wmctile::Class
|
2
|
+
def cmd cmd
|
3
|
+
# [0..-2] to strip the last \n
|
4
|
+
`#{ cmd }`[0..-2]
|
5
|
+
end
|
6
|
+
def notify title, string, icon = nil
|
7
|
+
if icon
|
8
|
+
system "notify-send -i '#{ icon }' '#{title}' '#{string}'"
|
9
|
+
else
|
10
|
+
system "notify-send '#{title}' '#{string}'"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'dmenu'
|
2
|
+
|
3
|
+
class Wmctile::ClassWithDmenu < Wmctile::Class
|
4
|
+
def dmenu items
|
5
|
+
a = Dmenu.new
|
6
|
+
# override defaults
|
7
|
+
a.background = '#242424'
|
8
|
+
a.case_insensitive = true
|
9
|
+
a.font = 'Ubuntu Mono-12'
|
10
|
+
a.foreground = 'white'
|
11
|
+
a.lines = 10
|
12
|
+
a.position = :bottom
|
13
|
+
a.selected_background = '#2e557e'
|
14
|
+
# set items
|
15
|
+
a.items = items
|
16
|
+
# run
|
17
|
+
b = a.run()
|
18
|
+
if b.is_a? Dmenu::Item
|
19
|
+
return b.value
|
20
|
+
else
|
21
|
+
return b
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class Wmctile::Memory < Wmctile::Class
|
4
|
+
##################################
|
5
|
+
## init ##########################
|
6
|
+
##################################
|
7
|
+
def initialize
|
8
|
+
@path = File.expand_path '~/.config/wmctile/wmctile-memory.yml'
|
9
|
+
if not File.exist? @path
|
10
|
+
raw_memory = self.create_new_memory
|
11
|
+
end
|
12
|
+
raw_memory ||= File.read @path
|
13
|
+
@memory = YAML.load(raw_memory)
|
14
|
+
end
|
15
|
+
def create_new_memory
|
16
|
+
dir_path = @path[/(.*)\/wmctile-memory.yml/, 1]
|
17
|
+
if not Dir.exists? dir_path
|
18
|
+
Dir.mkdir dir_path
|
19
|
+
end
|
20
|
+
out_file = File.new @path, 'w'
|
21
|
+
# 20 workspaces should suffice
|
22
|
+
20.times do |i|
|
23
|
+
out_file.puts "#{i}:"
|
24
|
+
end
|
25
|
+
out_file.close
|
26
|
+
end
|
27
|
+
def write_memory
|
28
|
+
out_file = File.new @path, 'w'
|
29
|
+
out_file.puts @memory.to_yaml
|
30
|
+
out_file.close
|
31
|
+
end
|
32
|
+
##################################
|
33
|
+
## getters/setters ###############
|
34
|
+
##################################
|
35
|
+
def get workspace = 0, key = nil, key_sub = nil
|
36
|
+
begin
|
37
|
+
a = @memory[workspace]
|
38
|
+
if key.nil?
|
39
|
+
return nil
|
40
|
+
else
|
41
|
+
a = a[key]
|
42
|
+
if key_sub.nil?
|
43
|
+
return a
|
44
|
+
else
|
45
|
+
return a[key_sub]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
rescue Exception => e
|
49
|
+
return nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def set workspace = 0, key, hash
|
53
|
+
hash.merge! 'time' => Time.now.to_i
|
54
|
+
if @memory[workspace].nil?
|
55
|
+
@memory[workspace] = {}
|
56
|
+
end
|
57
|
+
if @memory[workspace][key]
|
58
|
+
@memory[workspace][key] = hash
|
59
|
+
else
|
60
|
+
@memory[workspace].merge! key => hash
|
61
|
+
end
|
62
|
+
self.write_memory
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
class Wmctile::Router < Wmctile::Class
|
2
|
+
##################################
|
3
|
+
## init ##########################
|
4
|
+
##################################
|
5
|
+
def initialize
|
6
|
+
@settings = Wmctile::Settings.new
|
7
|
+
@all_workspaces = false
|
8
|
+
end
|
9
|
+
##################################
|
10
|
+
## main dispatch method ##########
|
11
|
+
##################################
|
12
|
+
def dispatch args = []
|
13
|
+
if args.length
|
14
|
+
main_arg = args[0]
|
15
|
+
if ['--all-workspaces', '-a'].include? main_arg
|
16
|
+
@all_workspaces = true
|
17
|
+
drop = 2
|
18
|
+
main_arg = args[1]
|
19
|
+
else
|
20
|
+
@all_workspaces = false
|
21
|
+
drop = 1
|
22
|
+
end
|
23
|
+
if main_arg and !['dispatch', 'initialize', 'wm', 'wt', 'memory'].include? main_arg and self.respond_to? main_arg
|
24
|
+
self.send main_arg, *args.drop(drop)
|
25
|
+
else
|
26
|
+
self.help
|
27
|
+
end
|
28
|
+
else
|
29
|
+
self.help
|
30
|
+
end
|
31
|
+
end
|
32
|
+
##################################
|
33
|
+
## object getter methods #########
|
34
|
+
##################################
|
35
|
+
def wm
|
36
|
+
@wm || @wm = Wmctile::WindowManager.new(@settings)
|
37
|
+
end
|
38
|
+
def wt
|
39
|
+
# @wm might be nil
|
40
|
+
@wt || @wt = Wmctile::WindowTiler.new(@settings, self.memory, @wm)
|
41
|
+
end
|
42
|
+
def memory
|
43
|
+
@memory || @memory = Wmctile::Memory.new
|
44
|
+
end
|
45
|
+
##################################
|
46
|
+
## actual command-line methods ###
|
47
|
+
##################################
|
48
|
+
def help args = nil
|
49
|
+
puts <<-eos
|
50
|
+
wmctile version 0.1.1
|
51
|
+
|
52
|
+
usage:
|
53
|
+
wmctile [--option1, --option2, ...] <command> ['argument1', 'argument2', ...]
|
54
|
+
|
55
|
+
examples:
|
56
|
+
wmctile snap 'left' 'terminator'
|
57
|
+
wmctile summon --all-workspaces ':ACTIVE:'
|
58
|
+
|
59
|
+
options:
|
60
|
+
--all-workspaces, -a
|
61
|
+
Use all workspaces when searching for windows.
|
62
|
+
|
63
|
+
commands:
|
64
|
+
summon 'window_string'
|
65
|
+
Summons a window matching 'window_str'.
|
66
|
+
|
67
|
+
summon_or_run 'window_string' 'command_to_run'
|
68
|
+
Summons a window matching 'window_string'. If no window is found, the 'command_to_run' is run.
|
69
|
+
|
70
|
+
switch_to 'window_string'
|
71
|
+
Switches to a window matching 'window_string'.
|
72
|
+
|
73
|
+
switch_to_or_run 'window_string' 'command_to_run'
|
74
|
+
Switches to a window matching 'window_string'. If no window is found, the 'command_to_run' is run.
|
75
|
+
|
76
|
+
maximize 'window_string'
|
77
|
+
Maximizes a window matching 'window_string'.
|
78
|
+
|
79
|
+
unmaximize 'window_string'
|
80
|
+
Unmaximizes a window matching 'window_string'.
|
81
|
+
|
82
|
+
shade 'window_string'
|
83
|
+
Shades a window matching 'window_string'.
|
84
|
+
|
85
|
+
unshade 'window_string'
|
86
|
+
Unshades a window matching 'window_string'.
|
87
|
+
|
88
|
+
unshade_last_shaded
|
89
|
+
Unshades the last shaded window on active workspace.
|
90
|
+
|
91
|
+
snap 'where' 'window_string' ['portion']
|
92
|
+
Snaps a window matching 'window_string' to occupy the 'where' 'portion' of the screen.
|
93
|
+
'where' can be one of 'left', 'right', 'top', 'bottom'
|
94
|
+
'portion' is a float number with the default of 0.5
|
95
|
+
|
96
|
+
resize 'where' ['portion']
|
97
|
+
Resizes the last performed action (snap/tile etc.) on active workspace.
|
98
|
+
'where' can be one of 'left', 'right', 'top', 'bottom'
|
99
|
+
The action depends on the previously performed action. When you resize 'left' a previous snap 'left', you're shrinking the window. When you resize 'left' a previous snap 'right', you're increasing the size of the window.
|
100
|
+
'portion' is a float number with the default of 0.01 by which to edit the previous portion of the screen
|
101
|
+
|
102
|
+
resize_snap 'where' ['portion']
|
103
|
+
Resizes the last performed snap on active workspace. Arguments are the same as in resize command.
|
104
|
+
|
105
|
+
additional information:
|
106
|
+
To use the active window, pass ':ACTIVE:' as the 'window_string' argument.
|
107
|
+
eos
|
108
|
+
end
|
109
|
+
def summon window_str
|
110
|
+
window = self.wm.find_in_windows window_str, @all_workspaces
|
111
|
+
if window
|
112
|
+
window.summon
|
113
|
+
return true
|
114
|
+
else
|
115
|
+
return false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
def summon_or_run window_str, cmd_to_run
|
119
|
+
unless self.summon window_str
|
120
|
+
self.cmd "#{ cmd_to_run } > /dev/null &"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
def switch_to window_str
|
124
|
+
window = self.wm.find_in_windows window_str, @all_workspaces
|
125
|
+
if window
|
126
|
+
window.switch_to
|
127
|
+
return true
|
128
|
+
else
|
129
|
+
return false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
def switch_to_or_run window_str, cmd_to_run
|
133
|
+
unless self.switch_to window_str
|
134
|
+
self.cmd "#{ cmd_to_run } > /dev/null &"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
def maximize window_str
|
138
|
+
window = self.wm.get_window window_str
|
139
|
+
if window
|
140
|
+
window.maximize
|
141
|
+
end
|
142
|
+
end
|
143
|
+
def unmaximize window_str
|
144
|
+
window = self.wm.get_window window_str
|
145
|
+
if window
|
146
|
+
window.unmaximize
|
147
|
+
end
|
148
|
+
end
|
149
|
+
def shade window_str
|
150
|
+
window = self.wm.get_window window_str
|
151
|
+
if window
|
152
|
+
window.shade
|
153
|
+
self.memory.set self.wm.workspace, 'shade', {
|
154
|
+
'window_id' => window.id
|
155
|
+
}
|
156
|
+
end
|
157
|
+
end
|
158
|
+
def unshade window_str
|
159
|
+
window = self.wm.get_window window_str
|
160
|
+
if window
|
161
|
+
window.unshade
|
162
|
+
self.memory.set self.wm.workspace, 'unshade', {
|
163
|
+
'window_id' => window.id
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
def unshade_last_shaded
|
168
|
+
win_id = self.memory.get self.wm.workspace, 'shade', 'window_id'
|
169
|
+
window = Wmctile::Window.new win_id, @settings
|
170
|
+
if window
|
171
|
+
window.unshade
|
172
|
+
self.memory.set self.wm.workspace, 'unshade', {
|
173
|
+
'window_id' => window.id
|
174
|
+
}
|
175
|
+
end
|
176
|
+
end
|
177
|
+
def snap where = 'left', window_str = nil, portion = 0.5
|
178
|
+
self.wt.snap where, window_str, portion
|
179
|
+
end
|
180
|
+
def resize where = 'left', portion = 0.01
|
181
|
+
self.wt.resize where, portion
|
182
|
+
end
|
183
|
+
def resize_snap where = 'left', portion = 0.01
|
184
|
+
self.wt.resize_snap where, portion
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class Wmctile::Settings < Wmctile::Class
|
4
|
+
def method_missing sym, *args, &block
|
5
|
+
return false
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
path = File.expand_path '~/.config/wmctile/wmctile-settings.yml'
|
10
|
+
if not File.exist? path
|
11
|
+
raw_settings = self.create_new_settings path
|
12
|
+
end
|
13
|
+
raw_settings ||= File.read path
|
14
|
+
settings = YAML.load(raw_settings)
|
15
|
+
if settings
|
16
|
+
settings.each { |name, value|
|
17
|
+
instance_variable_set("@#{name}", value)
|
18
|
+
self.class.class_eval { attr_reader name.intern }
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_requirements
|
24
|
+
req = ['xrandr', 'wmctrl', 'dmenu']
|
25
|
+
ret = req.reject { |r| self.cmd("which #{ r }").length > 0 }
|
26
|
+
return ret
|
27
|
+
end
|
28
|
+
def create_new_settings path
|
29
|
+
req = self.test_requirements
|
30
|
+
unless req.nil? or req.length == 0
|
31
|
+
puts <<-eos
|
32
|
+
You don't have #{ req.join(', ') } installed. Wmctile can't run without that.
|
33
|
+
|
34
|
+
To fix this on Ubuntu, run:
|
35
|
+
|
36
|
+
sudo apt-get install #{ req.join(' ') }
|
37
|
+
eos
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
dir_path = path[/(.*)\/wmctile-settings.yml/, 1]
|
41
|
+
if not Dir.exists? dir_path
|
42
|
+
Dir.mkdir dir_path
|
43
|
+
end
|
44
|
+
out_file = File.new path, 'w'
|
45
|
+
out_file.puts self.default_settings.to_yaml
|
46
|
+
out_file.close
|
47
|
+
end
|
48
|
+
def default_settings
|
49
|
+
{
|
50
|
+
:window_border => 1,
|
51
|
+
:panel_height => 24,
|
52
|
+
:panel_width => 0,
|
53
|
+
:hostname => self.cmd('hostname')
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class Wmctile::Window < Wmctile::Class
|
2
|
+
attr_accessor :id, :name, :title
|
3
|
+
|
4
|
+
def initialize win_string, settings
|
5
|
+
@default_movement = { :x => 0, :y => 0, :width => '-1', :height => '-1' }
|
6
|
+
@settings = settings
|
7
|
+
@id = win_string[/0x[\d\w]{8}/]
|
8
|
+
self.get_name_and_title win_string
|
9
|
+
end
|
10
|
+
def get_name_and_title win_string
|
11
|
+
if win_string == @id
|
12
|
+
@name = ''
|
13
|
+
@title = ''
|
14
|
+
else
|
15
|
+
after_id_and_workspace = win_string[14..-1].split(/\s+#{ @settings.hostname }\s+/, 2)
|
16
|
+
@name = after_id_and_workspace[0]
|
17
|
+
@title = after_id_and_workspace[1]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
def dmenu_item
|
21
|
+
unless @dmenu_item
|
22
|
+
str = "#{ @id } #{ @name } #{ @title }"
|
23
|
+
@dmenu_item = Dmenu::Item.new str, self
|
24
|
+
end
|
25
|
+
@dmenu_item
|
26
|
+
end
|
27
|
+
def get_name
|
28
|
+
if @name == ''
|
29
|
+
self.get_name_and_title self.cmd('wmctrl -lx | grep ' + @id)
|
30
|
+
end
|
31
|
+
@name
|
32
|
+
end
|
33
|
+
def get_name_length
|
34
|
+
@name.length
|
35
|
+
end
|
36
|
+
def set_name_length name_length
|
37
|
+
@name += ' '*(name_length - @name.length)
|
38
|
+
end
|
39
|
+
def wmctrl wm_cmd = '', summon = false
|
40
|
+
self.cmd "wmctrl -i#{ summon ? 'R' : 'r' } #{ @id } #{ wm_cmd }"
|
41
|
+
return self # return self so that commands can be chained
|
42
|
+
end
|
43
|
+
def move how_to_move = {}
|
44
|
+
how_to_move = @default_movement.merge! how_to_move
|
45
|
+
cmd = "-e 0,#{ how_to_move[:x].to_i },#{ how_to_move[:y].to_i },#{ how_to_move[:width].to_i },#{ how_to_move[:height].to_i }"
|
46
|
+
self.unshade
|
47
|
+
self.unmaximize
|
48
|
+
self.wmctrl cmd
|
49
|
+
end
|
50
|
+
def shade
|
51
|
+
self.wmctrl '-b add,shaded'
|
52
|
+
end
|
53
|
+
def unshade
|
54
|
+
self.wmctrl '-b remove,shaded'
|
55
|
+
end
|
56
|
+
def summon
|
57
|
+
self.wmctrl '', true
|
58
|
+
end
|
59
|
+
def switch_to
|
60
|
+
self.cmd "wmctrl -ia #{ @id }"
|
61
|
+
return self
|
62
|
+
end
|
63
|
+
def maximize
|
64
|
+
self.wmctrl '-b add,maximized_vert,maximized_horz'
|
65
|
+
end
|
66
|
+
def unmaximize
|
67
|
+
self.wmctrl '-b remove,maximized_vert,maximized_horz'
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
class Wmctile::WindowManager < Wmctile::ClassWithDmenu
|
2
|
+
attr_accessor :w, :h, :workspace, :windows
|
3
|
+
##################################
|
4
|
+
## init ##########################
|
5
|
+
##################################
|
6
|
+
def initialize settings
|
7
|
+
@settings = settings
|
8
|
+
self.init_dimensions
|
9
|
+
end
|
10
|
+
def init_dimensions
|
11
|
+
# legacy (but fast) method via wmctrl
|
12
|
+
# dimensions = cmd("wmctrl -d | awk '{ print $9 }' | head -n1").split('x')
|
13
|
+
# xrandr is slower, but offers more information
|
14
|
+
dimensions = cmd("xrandr | grep -E '\sconnected\s[0-9]+x[0-9]+\+0' | awk '{print $3}' | awk -F'+' '{print $1}'").split('x')
|
15
|
+
@w = dimensions[0].to_i - 2*@settings.window_border
|
16
|
+
@h = dimensions[1].to_i - 2*@settings.window_border - @settings.panel_height
|
17
|
+
@workspace = cmd("wmctrl -d | grep '\*' | awk '{ print $1 }'").to_i
|
18
|
+
end
|
19
|
+
##################################
|
20
|
+
## dimension getters #############
|
21
|
+
##################################
|
22
|
+
def width portion = 1
|
23
|
+
@w * portion
|
24
|
+
end
|
25
|
+
def height portion = 1
|
26
|
+
@h * portion
|
27
|
+
end
|
28
|
+
##################################
|
29
|
+
## window getters ################
|
30
|
+
##################################
|
31
|
+
def get_window window_str = nil, all_workspaces = false
|
32
|
+
if window_str.nil?
|
33
|
+
window = self.ask_for_window all_workspaces
|
34
|
+
else
|
35
|
+
if window_str == ':ACTIVE:'
|
36
|
+
window = self.get_active_window
|
37
|
+
else
|
38
|
+
window = self.find_window window_str, all_workspaces
|
39
|
+
unless window
|
40
|
+
# does window_str have an icon bundle in it? (aka evince.Evince)
|
41
|
+
if window_str =~ /[a-z0-9]+\.[a-z0-9]+/i
|
42
|
+
icon = window_str.split('.').first
|
43
|
+
else
|
44
|
+
icon = nil
|
45
|
+
end
|
46
|
+
self.notify 'No window found', "#{ window_str }", icon
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
window
|
51
|
+
end
|
52
|
+
def get_active_window
|
53
|
+
win_id = self.cmd('wmctrl -a :ACTIVE: -v 2>&1').split('Using window: ').last
|
54
|
+
Wmctile::Window.new win_id, @settings
|
55
|
+
end
|
56
|
+
def find_window window_string, all_workspaces = false
|
57
|
+
cmd = "wmctrl -lx | grep -F #{ window_string }"
|
58
|
+
cmd += ' | grep -E \'0x\w+\s+' + @workspace.to_s + '\s+\'' unless all_workspaces
|
59
|
+
window_string = self.cmd cmd
|
60
|
+
window_string = window_string.split("\n").first
|
61
|
+
if window_string.nil?
|
62
|
+
return nil
|
63
|
+
else
|
64
|
+
return Wmctile::Window.new window_string, @settings
|
65
|
+
end
|
66
|
+
end
|
67
|
+
def find_windows window_string, all_workspaces = false
|
68
|
+
cmd = "wmctrl -lx | grep -F #{ window_string }"
|
69
|
+
cmd += ' | grep -E \'0x\w+\s+' + @workspace.to_s + '\s+\'' unless all_workspaces
|
70
|
+
window_strings = self.cmd cmd
|
71
|
+
window_strings = window_strings.split("\n")
|
72
|
+
if window_string.nil?
|
73
|
+
return nil
|
74
|
+
else
|
75
|
+
return window_strings.map { |w| Wmctile::Window.new w, @settings }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
def find_in_windows window_string, all_workspaces = false
|
79
|
+
if window_string.nil?
|
80
|
+
self.ask_for_window all_workspaces
|
81
|
+
else
|
82
|
+
windows = self.find_windows window_string, all_workspaces
|
83
|
+
if windows
|
84
|
+
ids = windows.collect(&:id)
|
85
|
+
active_win = self.get_active_window
|
86
|
+
if ids.include? active_win.id
|
87
|
+
# cycle through the windows
|
88
|
+
i = ids.index active_win.id
|
89
|
+
# try the next one
|
90
|
+
if ids[i+1]
|
91
|
+
window = windows[i+1]
|
92
|
+
# fallback to the first one
|
93
|
+
else
|
94
|
+
window = windows.first
|
95
|
+
end
|
96
|
+
else
|
97
|
+
# switch to the first one
|
98
|
+
window = windows.first
|
99
|
+
end
|
100
|
+
return window
|
101
|
+
end
|
102
|
+
return nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
def ask_for_window all_workspaces = false
|
106
|
+
self.dmenu self.windows.map(&:dmenu_item)
|
107
|
+
end
|
108
|
+
##################################
|
109
|
+
## window lists ##################
|
110
|
+
##################################
|
111
|
+
def build_win_list all_workspaces = false
|
112
|
+
unless all_workspaces
|
113
|
+
variable_name = '@windows_on_workspace'
|
114
|
+
else
|
115
|
+
variable_name = '@windows_all'
|
116
|
+
end
|
117
|
+
unless instance_variable_get(variable_name)
|
118
|
+
unless all_workspaces
|
119
|
+
cmd = "wmctrl -lx | grep \" #{ @workspace } \""
|
120
|
+
else
|
121
|
+
cmd = "wmctrl -lx"
|
122
|
+
end
|
123
|
+
arr = cmd(cmd).split("\n")
|
124
|
+
|
125
|
+
new_list = arr.map { |w| Wmctile::Window.new(w, @settings) }
|
126
|
+
name_length = new_list.map(&:get_name_length).max
|
127
|
+
new_list.each { |w| w.set_name_length(name_length) }
|
128
|
+
|
129
|
+
instance_variable_set(variable_name, new_list)
|
130
|
+
end
|
131
|
+
instance_variable_get(variable_name)
|
132
|
+
end
|
133
|
+
def windows all_workspaces = false
|
134
|
+
unless all_workspaces
|
135
|
+
variable_name = '@windows_on_workspace'
|
136
|
+
else
|
137
|
+
variable_name = '@windows_all'
|
138
|
+
end
|
139
|
+
unless instance_variable_get(variable_name)
|
140
|
+
self.build_win_list all_workspaces
|
141
|
+
else
|
142
|
+
instance_variable_get(variable_name)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
##################################
|
146
|
+
## window size calculators #######
|
147
|
+
##################################
|
148
|
+
def calculate_snap where, portion = 0.5
|
149
|
+
return case where
|
150
|
+
when 'left'
|
151
|
+
{
|
152
|
+
:x => @settings.panel_width, :y => @settings.panel_height,
|
153
|
+
:height => self.height, :width => self.width(portion)
|
154
|
+
}
|
155
|
+
when 'right'
|
156
|
+
{
|
157
|
+
:x => self.width(portion), :y => @settings.panel_height,
|
158
|
+
:height => self.height, :width => self.width(1-portion)
|
159
|
+
}
|
160
|
+
when 'top'
|
161
|
+
{
|
162
|
+
:x => @settings.panel_width, :y => @settings.panel_height,
|
163
|
+
:height => self.height(portion), :width => self.width
|
164
|
+
}
|
165
|
+
when 'bottom'
|
166
|
+
{
|
167
|
+
:x => @settings.panel_width, :y => @settings.panel_height + self.height(1-portion),
|
168
|
+
:height => self.height(portion), :width => self.width
|
169
|
+
}
|
170
|
+
else
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
class Wmctile::WindowTiler < Wmctile::Class
|
2
|
+
##################################
|
3
|
+
## init ##########################
|
4
|
+
##################################
|
5
|
+
def initialize settings, memory, wm = nil
|
6
|
+
@settings = settings
|
7
|
+
@memory = memory
|
8
|
+
@wm = wm
|
9
|
+
end
|
10
|
+
##################################
|
11
|
+
## object getter methods #########
|
12
|
+
##################################
|
13
|
+
def wm
|
14
|
+
@wm || @wm = Wmctile::WindowManager.new(@settings)
|
15
|
+
end
|
16
|
+
def memory
|
17
|
+
@memory || @memory = Wmctile::Memory.new
|
18
|
+
end
|
19
|
+
##################################
|
20
|
+
## actual snapping methods #######
|
21
|
+
##################################
|
22
|
+
def snap where = 'left', window_str = nil, portion = 0.5
|
23
|
+
window = self.wm.get_window window_str
|
24
|
+
if window
|
25
|
+
how_to_move = self.wm.calculate_snap where, portion.to_f
|
26
|
+
if how_to_move
|
27
|
+
window.move how_to_move
|
28
|
+
self.memory.set self.wm.workspace, 'snap', {
|
29
|
+
'where' => where, 'portion' => portion, 'window_id' => window.id
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
def resize where = 'left', portion = 0.01
|
35
|
+
portion = portion.to_f
|
36
|
+
# what are we moving? the last one used from these:
|
37
|
+
methods = ['snap']
|
38
|
+
freshest_meth = nil
|
39
|
+
freshest_time = 0
|
40
|
+
methods.each do |meth|
|
41
|
+
time = self.memory.get self.wm.workspace, meth, 'time'
|
42
|
+
if time > freshest_time
|
43
|
+
freshest_time = time
|
44
|
+
freshest_meth = meth
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# ok, got it, it's freshest_meth
|
48
|
+
self.send "resize_#{ freshest_meth }", where, portion
|
49
|
+
end
|
50
|
+
def resize_snap where = 'left', portion = 0.01
|
51
|
+
portion = portion.to_f
|
52
|
+
info = self.memory.get self.wm.workspace, 'snap'
|
53
|
+
if info.nil?
|
54
|
+
return nil
|
55
|
+
end
|
56
|
+
negative = case info['where']
|
57
|
+
when 'left'
|
58
|
+
if where == 'left'
|
59
|
+
true
|
60
|
+
elsif where == 'right'
|
61
|
+
false
|
62
|
+
else
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
when 'right'
|
66
|
+
if where == 'left'
|
67
|
+
false
|
68
|
+
elsif where == 'right'
|
69
|
+
true
|
70
|
+
else
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
when 'top'
|
74
|
+
if where == 'bottom'
|
75
|
+
false
|
76
|
+
elsif where == 'top'
|
77
|
+
true
|
78
|
+
else
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
when 'bottom'
|
82
|
+
if where == 'top'
|
83
|
+
false
|
84
|
+
elsif where == 'bottom'
|
85
|
+
true
|
86
|
+
else
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
unless negative.nil?
|
91
|
+
portion = -portion if negative
|
92
|
+
self.snap info['where'], info['window_id'], info['portion']+portion
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wmctile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mreq
|
@@ -30,7 +30,16 @@ executables: []
|
|
30
30
|
extensions: []
|
31
31
|
extra_rdoc_files: []
|
32
32
|
files:
|
33
|
+
- bin/wmctile
|
33
34
|
- lib/wmctile.rb
|
35
|
+
- lib/wmctile/class.rb
|
36
|
+
- lib/wmctile/class_with_dmenu.rb
|
37
|
+
- lib/wmctile/memory.rb
|
38
|
+
- lib/wmctile/router.rb
|
39
|
+
- lib/wmctile/settings.rb
|
40
|
+
- lib/wmctile/window.rb
|
41
|
+
- lib/wmctile/window_manager.rb
|
42
|
+
- lib/wmctile/window_tiler.rb
|
34
43
|
homepage: http://mreq.github.io/wmctile
|
35
44
|
licenses:
|
36
45
|
- GPL-2
|