fusuma-plugin-wmctrl 0.4.3 → 1.0.0
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/README.md +55 -1
- data/fusuma-plugin-wmctrl.gemspec +2 -1
- data/lib/fusuma/plugin/executors/wmctrl_executor.rb +34 -107
- data/lib/fusuma/plugin/wmctrl/version.rb +1 -1
- data/lib/fusuma/plugin/wmctrl/window.rb +18 -0
- data/lib/fusuma/plugin/wmctrl/workspace.rb +153 -0
- data/spec/fusuma/plugin/plugin/executors/wmctrl_executor_spec.rb +45 -160
- data/spec/fusuma/plugin/plugin/wmctrl/workspace_spec.rb +236 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 260a70ddbdd31218d0e43a7c354482b44d1cc17aaf7ece9fe3800ce7bf156c72
|
4
|
+
data.tar.gz: 0a15ae0fbe6c080fccc5e460400a3b77e062079e00f0a90dabdfb43d3c5d4dd2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e07ea3be6ceed205615ba3f22e57519b3dfad5e3fba29c099fffc35afa542bb33eef7c2143962cd1c987127b13472780c45f99f03d3f07e5e0ce9afda6e63178
|
7
|
+
data.tar.gz: a0fa6b1ba117356a3062a30e11c2f3969a2382c4adbd2b0327c03dbb404f89d9ed71d4564dbde8588d798b5297af46ad429efa7f64517ec807bbc5e57babf80b
|
data/README.md
CHANGED
@@ -29,7 +29,7 @@ sudo pacman -S wmctrl
|
|
29
29
|
This plugin requires [Fusuma](https://github.com/iberianpig/fusuma#update) version 1.0 or later.
|
30
30
|
|
31
31
|
|
32
|
-
**Note For Arch Based Distros:** By default in Arch Linux, when running
|
32
|
+
**Note For Arch Based Distros:** By default in Arch Linux, when running `gem`, gems are installed per-user (into `~/.gem/ruby/`), instead of system-wide (into `/usr/lib/ruby/gems/`). This is considered the best way to manage gems on Arch, because otherwise they might interfere with gems installed by Pacman. (From Arch Wiki)
|
33
33
|
|
34
34
|
To install gems system-wide, see any of the methods listed on [Arch Wiki](https://wiki.archlinux.org/index.php/ruby#Installing_gems_system-wide)
|
35
35
|
|
@@ -46,6 +46,7 @@ Values following are available for `workspace`.
|
|
46
46
|
|
47
47
|
* `prev` is value to switch current workspace to previous workspace.
|
48
48
|
* `next` is value to switch current workspace to next workspace.
|
49
|
+
* [**[For grid-style workspaces only](#support-grid-style-workspace)**] `up` / `down` / `left` / `right` navigate to the workspace in the direction.
|
49
50
|
|
50
51
|
### `window:` property
|
51
52
|
Add `window:` property in `~/.config/fusuma/config.yml`.
|
@@ -54,6 +55,7 @@ Values following are available for `window`.
|
|
54
55
|
|
55
56
|
* `prev` is value to move active window to previous workspace.
|
56
57
|
* `next` is value to move active window to next workspace.
|
58
|
+
* [**[For grid-style workspaces only](#support-grid-style-workspace)**] `up` / `down` / `left` / `right` move window to the workspace in the direction.
|
57
59
|
* `fullscreen` is value to toggle fullscreen
|
58
60
|
* `fullscreen: toggle` toggles the active window to fullscreen.
|
59
61
|
```yml
|
@@ -111,6 +113,8 @@ swipe:
|
|
111
113
|
|
112
114
|
## Configuration
|
113
115
|
|
116
|
+
### Wrap navigation
|
117
|
+
|
114
118
|
The plugin allows to enable (disabled by default) circular navigation between workspaces. To enable it set the following in your config file `~/.config/fusuma/config.yml`.
|
115
119
|
|
116
120
|
```yaml
|
@@ -120,6 +124,56 @@ plugin:
|
|
120
124
|
wrap-navigation: true
|
121
125
|
```
|
122
126
|
|
127
|
+
### Support grid-style workspace
|
128
|
+
|
129
|
+
For grid-style workspace users, Fusuma has an option to move workspace up, down, left or right.
|
130
|
+
To enable this option, set `matrix-col-size`.
|
131
|
+
|
132
|
+
For example, for a 3x2 workspace, set `matrix-col-size: 3` to wmctrl_executor option.
|
133
|
+
```yaml
|
134
|
+
plugin:
|
135
|
+
executors:
|
136
|
+
wmctrl_executor:
|
137
|
+
matrix-col-size: 3
|
138
|
+
```
|
139
|
+
|
140
|
+
With this setting, the `up`/`down`/`left`/`right` properties will be enabled on `workspace:` and `window:`.
|
141
|
+
|
142
|
+
#### Example
|
143
|
+
|
144
|
+
```yaml
|
145
|
+
swipe:
|
146
|
+
4:
|
147
|
+
up:
|
148
|
+
workspace: down
|
149
|
+
keypress:
|
150
|
+
LEFTSHIFT:
|
151
|
+
window: down
|
152
|
+
down:
|
153
|
+
workspace: up
|
154
|
+
keypress:
|
155
|
+
LEFTSHIFT:
|
156
|
+
window: up
|
157
|
+
left:
|
158
|
+
workspace: right
|
159
|
+
keypress:
|
160
|
+
LEFTSHIFT:
|
161
|
+
window: right
|
162
|
+
right:
|
163
|
+
workspace: left
|
164
|
+
keypress:
|
165
|
+
LEFTSHIFT:
|
166
|
+
window: left
|
167
|
+
|
168
|
+
plugin:
|
169
|
+
executors:
|
170
|
+
wmctrl_executor:
|
171
|
+
matrix-col-size: 3
|
172
|
+
```
|
173
|
+
|
174
|
+
NOTE: `keypress:` property is enabled with fusuma-plugin-keypress
|
175
|
+
https://github.com/iberianpig/fusuma-plugin-keypress
|
176
|
+
|
123
177
|
|
124
178
|
## Contributing
|
125
179
|
|
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ['lib']
|
24
24
|
|
25
|
-
spec.required_ruby_version = '>= 2.
|
25
|
+
spec.required_ruby_version = '>= 2.5.1' # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all§ion=main
|
26
|
+
# support bionic (18.04LTS) 2.5.1
|
26
27
|
spec.add_dependency 'fusuma', '~> 2.0.0'
|
27
28
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative '../wmctrl/window'
|
4
|
+
require_relative '../wmctrl/workspace'
|
4
5
|
|
5
6
|
module Fusuma
|
6
7
|
module Plugin
|
@@ -15,13 +16,18 @@ module Fusuma
|
|
15
16
|
|
16
17
|
def config_param_types
|
17
18
|
{
|
18
|
-
'wrap-navigation': [TrueClass, FalseClass]
|
19
|
+
'wrap-navigation': [TrueClass, FalseClass],
|
20
|
+
'matrix-col-size': [Integer]
|
19
21
|
}
|
20
22
|
end
|
21
23
|
|
22
24
|
def initialize
|
23
25
|
super()
|
24
|
-
Workspace.
|
26
|
+
@workspace = Workspace.new(
|
27
|
+
wrap_navigation: config_params(:'wrap-navigation'),
|
28
|
+
matrix_col_size: config_params(:'matrix-col-size')
|
29
|
+
)
|
30
|
+
@window = Window.new
|
25
31
|
end
|
26
32
|
|
27
33
|
# execute wmctrl command
|
@@ -49,6 +55,9 @@ module Fusuma
|
|
49
55
|
# @return [NilClass]
|
50
56
|
def search_command(event)
|
51
57
|
search_workspace_command(event) || search_window_command(event)
|
58
|
+
rescue Workspace::InvalidOption => e
|
59
|
+
MultiLogger.error(e.message)
|
60
|
+
exit 1
|
52
61
|
end
|
53
62
|
|
54
63
|
private
|
@@ -59,10 +68,16 @@ module Fusuma
|
|
59
68
|
def search_workspace_command(event)
|
60
69
|
index = Config::Index.new([*event.record.index.keys, :workspace])
|
61
70
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
71
|
+
case property = Config.search(index)
|
72
|
+
when 'prev', 'next'
|
73
|
+
@workspace.move_command(direction: property)
|
74
|
+
when 'left', 'right', 'up', 'down'
|
75
|
+
@workspace.move_command_for_matrix(direction: property)
|
76
|
+
when nil
|
77
|
+
nil
|
78
|
+
else
|
79
|
+
raise "#{property} is invalid key"
|
80
|
+
end
|
66
81
|
end
|
67
82
|
|
68
83
|
# @param event [Event]
|
@@ -73,113 +88,25 @@ module Fusuma
|
|
73
88
|
|
74
89
|
case property = Config.search(index)
|
75
90
|
when 'prev', 'next'
|
76
|
-
|
91
|
+
@workspace.move_window_command(direction: property)
|
92
|
+
when 'left', 'right', 'up', 'down'
|
93
|
+
@workspace.move_window_command_for_matrix(direction: property)
|
77
94
|
when 'fullscreen'
|
78
|
-
|
95
|
+
@window.fullscreen(method: 'toggle')
|
79
96
|
when 'maximized'
|
80
|
-
|
97
|
+
@window.maximized(method: 'toggle')
|
81
98
|
when 'close'
|
82
|
-
|
99
|
+
@window.close
|
83
100
|
when Hash
|
84
101
|
if property[:fullscreen]
|
85
|
-
|
102
|
+
@window.fullscreen(method: property[:fullscreen])
|
86
103
|
elsif property[:maximized]
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# Manage workspace
|
93
|
-
class Workspace
|
94
|
-
include Singleton
|
95
|
-
|
96
|
-
attr_accessor :wrap_navigation
|
97
|
-
|
98
|
-
class << self
|
99
|
-
# configure properties of the workspace switcher
|
100
|
-
# @return [NilClass]
|
101
|
-
def configure(wrap_navigation:)
|
102
|
-
instance.wrap_navigation = wrap_navigation
|
103
|
-
end
|
104
|
-
|
105
|
-
# get next workspace number
|
106
|
-
# @return [Integer]
|
107
|
-
def next_workspace_num(step:)
|
108
|
-
current_workspace_num, total_workspace_num = workspace_values
|
109
|
-
|
110
|
-
next_workspace_num = current_workspace_num + step
|
111
|
-
|
112
|
-
return next_workspace_num unless instance.wrap_navigation
|
113
|
-
|
114
|
-
if next_workspace_num.negative?
|
115
|
-
next_workspace_num = total_workspace_num - 1
|
116
|
-
elsif next_workspace_num >= total_workspace_num
|
117
|
-
next_workspace_num = 0
|
118
|
-
else
|
119
|
-
next_workspace_num
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def move_command(direction:)
|
124
|
-
workspace_num = case direction
|
125
|
-
when 'next'
|
126
|
-
next_workspace_num(step: 1)
|
127
|
-
when 'prev'
|
128
|
-
next_workspace_num(step: -1)
|
129
|
-
else
|
130
|
-
raise "#{direction} is invalid key"
|
131
|
-
end
|
132
|
-
"wmctrl -s #{workspace_num}"
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
# get current workspace and total workspace numbers
|
138
|
-
# @return [Integer, Integer]
|
139
|
-
def workspace_values
|
140
|
-
wmctrl_output = `wmctrl -d`.split("\n")
|
141
|
-
|
142
|
-
current_line = wmctrl_output.grep(/\*/).first
|
143
|
-
# NOTE: stderror when failed to get desktop
|
144
|
-
# `Cannot get current desktop properties. (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)`
|
145
|
-
return [0, 1] if current_line.nil?
|
146
|
-
|
147
|
-
current_workspace_num = current_line.chars.first.to_i
|
148
|
-
total_workspace_num = wmctrl_output.length
|
149
|
-
|
150
|
-
[current_workspace_num, total_workspace_num]
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
# Manage Window
|
156
|
-
class Window
|
157
|
-
class << self
|
158
|
-
# @param method [String] "toggle" or "add" or "remove"
|
159
|
-
def maximized(method:)
|
160
|
-
"wmctrl -r :ACTIVE: -b #{method},maximized_vert,maximized_horz"
|
161
|
-
end
|
162
|
-
|
163
|
-
def close
|
164
|
-
'wmctrl -c :ACTIVE:'
|
165
|
-
end
|
166
|
-
|
167
|
-
# @param method [String] "toggle" or "add" or "remove"
|
168
|
-
def fullscreen(method:)
|
169
|
-
"wmctrl -r :ACTIVE: -b #{method},fullscreen"
|
170
|
-
end
|
171
|
-
|
172
|
-
def move_command(direction:)
|
173
|
-
workspace_num = case direction
|
174
|
-
when 'next'
|
175
|
-
Workspace.next_workspace_num(step: 1)
|
176
|
-
when 'prev'
|
177
|
-
Workspace.next_workspace_num(step: -1)
|
178
|
-
else
|
179
|
-
raise "#{direction} is invalid key"
|
180
|
-
end
|
181
|
-
"wmctrl -r :ACTIVE: -t #{workspace_num} ; wmctrl -s #{workspace_num}"
|
104
|
+
@window.maximized(method: property[:maximized])
|
182
105
|
end
|
106
|
+
when nil
|
107
|
+
nil
|
108
|
+
else
|
109
|
+
raise "#{property} is invalid key"
|
183
110
|
end
|
184
111
|
end
|
185
112
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Manage Window
|
4
|
+
class Window
|
5
|
+
# @param method [String] "toggle" or "add" or "remove"
|
6
|
+
def maximized(method:)
|
7
|
+
"wmctrl -r :ACTIVE: -b #{method},maximized_vert,maximized_horz"
|
8
|
+
end
|
9
|
+
|
10
|
+
def close
|
11
|
+
'wmctrl -c :ACTIVE:'
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param method [String] "toggle" or "add" or "remove"
|
15
|
+
def fullscreen(method:)
|
16
|
+
"wmctrl -r :ACTIVE: -b #{method},fullscreen"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Manage workspace
|
4
|
+
class Workspace
|
5
|
+
class InvalidOption < StandardError; end
|
6
|
+
|
7
|
+
def initialize(wrap_navigation: nil, matrix_col_size: nil)
|
8
|
+
@wrap_navigation = wrap_navigation
|
9
|
+
@matrix_col_size = matrix_col_size
|
10
|
+
end
|
11
|
+
|
12
|
+
# get next workspace number
|
13
|
+
# @return [Integer]
|
14
|
+
def next_workspace_num(step:)
|
15
|
+
current_workspace_num, total_workspace_num = workspace_values
|
16
|
+
|
17
|
+
next_workspace_num = current_workspace_num + step
|
18
|
+
|
19
|
+
return next_workspace_num unless @wrap_navigation
|
20
|
+
|
21
|
+
if next_workspace_num.negative?
|
22
|
+
next_workspace_num = total_workspace_num - 1
|
23
|
+
elsif next_workspace_num >= total_workspace_num
|
24
|
+
next_workspace_num = 0
|
25
|
+
else
|
26
|
+
next_workspace_num
|
27
|
+
end
|
28
|
+
next_workspace_num
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Array<Integer>]
|
32
|
+
def matrix_size(total_workspace_num)
|
33
|
+
must_have_matrix_option!
|
34
|
+
col_size = @matrix_col_size
|
35
|
+
row_size = (total_workspace_num / col_size)
|
36
|
+
[row_size.to_i, col_size.to_i]
|
37
|
+
end
|
38
|
+
|
39
|
+
def must_have_matrix_option!
|
40
|
+
return if @matrix_col_size
|
41
|
+
|
42
|
+
warn(<<~ERRRORMESSAGE)
|
43
|
+
Please set matrix-col-size to config.yml
|
44
|
+
|
45
|
+
```config.yaml
|
46
|
+
plugin:
|
47
|
+
executors:
|
48
|
+
wmctrl_executor:
|
49
|
+
matrix-col-size: 2
|
50
|
+
```
|
51
|
+
ERRRORMESSAGE
|
52
|
+
raise InvalidOption, 'You need to set matrix option to config.yml'
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Integer]
|
56
|
+
# @raise RuntimeError
|
57
|
+
def next_workspace_num_for_matrix(direction:)
|
58
|
+
must_have_matrix_option!
|
59
|
+
current_workspace_num, total_workspace_num = workspace_values
|
60
|
+
row_size, col_size = matrix_size(total_workspace_num)
|
61
|
+
x = current_workspace_num % col_size
|
62
|
+
y = current_workspace_num / col_size
|
63
|
+
case direction
|
64
|
+
when 'right'
|
65
|
+
if x < col_size - 1
|
66
|
+
current_workspace_num + 1
|
67
|
+
elsif @wrap_navigation
|
68
|
+
current_workspace_num - (col_size - 1)
|
69
|
+
else
|
70
|
+
current_workspace_num
|
71
|
+
end
|
72
|
+
when 'left'
|
73
|
+
if x.positive?
|
74
|
+
current_workspace_num - 1
|
75
|
+
elsif @wrap_navigation
|
76
|
+
current_workspace_num + (col_size - 1)
|
77
|
+
else
|
78
|
+
current_workspace_num
|
79
|
+
end
|
80
|
+
when 'down'
|
81
|
+
if y < row_size - 1
|
82
|
+
current_workspace_num + col_size
|
83
|
+
elsif @wrap_navigation
|
84
|
+
(current_workspace_num + col_size) - total_workspace_num
|
85
|
+
else
|
86
|
+
current_workspace_num
|
87
|
+
end
|
88
|
+
when 'up'
|
89
|
+
if y.positive?
|
90
|
+
current_workspace_num - col_size
|
91
|
+
elsif @wrap_navigation
|
92
|
+
total_workspace_num + (current_workspace_num - col_size)
|
93
|
+
else
|
94
|
+
current_workspace_num
|
95
|
+
end
|
96
|
+
else
|
97
|
+
raise "#{direction} is invalid key"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def move_command(direction:)
|
102
|
+
workspace_num = case direction
|
103
|
+
when 'next'
|
104
|
+
next_workspace_num(step: 1)
|
105
|
+
when 'prev'
|
106
|
+
next_workspace_num(step: -1)
|
107
|
+
else
|
108
|
+
raise "#{direction} is invalid key"
|
109
|
+
end
|
110
|
+
"wmctrl -s #{workspace_num}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def move_command_for_matrix(direction:)
|
114
|
+
workspace_num = next_workspace_num_for_matrix(direction: direction)
|
115
|
+
"wmctrl -s #{workspace_num}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def move_window_command(direction:)
|
119
|
+
workspace_num = case direction
|
120
|
+
when 'next'
|
121
|
+
next_workspace_num(step: 1)
|
122
|
+
when 'prev'
|
123
|
+
next_workspace_num(step: -1)
|
124
|
+
else
|
125
|
+
raise "#{direction} is invalid key"
|
126
|
+
end
|
127
|
+
"wmctrl -r :ACTIVE: -t #{workspace_num} ; wmctrl -s #{workspace_num}"
|
128
|
+
end
|
129
|
+
|
130
|
+
def move_window_command_for_matrix(direction:)
|
131
|
+
workspace_num = next_workspace_num_for_matrix(direction: direction)
|
132
|
+
"wmctrl -r :ACTIVE: -t #{workspace_num} ; wmctrl -s #{workspace_num}"
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
# get current workspace and total workspace numbers
|
138
|
+
# @return [Integer, Integer]
|
139
|
+
def workspace_values
|
140
|
+
wmctrl_output = `wmctrl -d`.split("\n")
|
141
|
+
|
142
|
+
current_line = wmctrl_output.grep(/\*/).first
|
143
|
+
# NOTE: stderror when failed to get desktop
|
144
|
+
# `Cannot get current desktop properties. \
|
145
|
+
# (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)`
|
146
|
+
return [0, 1] if current_line.nil?
|
147
|
+
|
148
|
+
current_workspace_num = current_line.chars.first.to_i
|
149
|
+
total_workspace_num = wmctrl_output.length
|
150
|
+
|
151
|
+
[current_workspace_num, total_workspace_num]
|
152
|
+
end
|
153
|
+
end
|
@@ -13,15 +13,16 @@ module Fusuma
|
|
13
13
|
module Executors
|
14
14
|
RSpec.describe WmctrlExecutor do
|
15
15
|
before do
|
16
|
+
@workspace = double(Workspace)
|
17
|
+
allow(Workspace)
|
18
|
+
.to receive(:new)
|
19
|
+
.and_return(@workspace)
|
20
|
+
|
16
21
|
index = Config::Index.new([:dummy, 1, :direction])
|
17
22
|
record = Events::Records::IndexRecord.new(index: index)
|
18
23
|
@event = Events::Event.new(tag: 'dummy_detector', record: record)
|
19
24
|
@executor = WmctrlExecutor.new
|
20
|
-
|
21
|
-
@default_workspace_num = 1
|
22
|
-
allow(WmctrlExecutor::Workspace)
|
23
|
-
.to receive(:workspace_values)
|
24
|
-
.and_return(@default_workspace_num)
|
25
|
+
allow(@executor).to receive(:search_command).and_return 'dummy command'
|
25
26
|
end
|
26
27
|
|
27
28
|
around do |example|
|
@@ -40,9 +41,8 @@ module Fusuma
|
|
40
41
|
describe '#execute' do
|
41
42
|
it 'detach' do
|
42
43
|
pid = rand(20)
|
43
|
-
allow(Process)
|
44
|
-
|
45
|
-
.and_return pid
|
44
|
+
allow(Process).to receive(:spawn).with(@executor.search_command(@event))
|
45
|
+
.and_return pid
|
46
46
|
|
47
47
|
expect(Process).to receive(:detach).with(pid)
|
48
48
|
|
@@ -64,6 +64,15 @@ module Fusuma
|
|
64
64
|
end
|
65
65
|
|
66
66
|
describe '#search_command' do
|
67
|
+
before do
|
68
|
+
allow(@executor).to receive(:search_command).and_call_original
|
69
|
+
|
70
|
+
@current_workspace = 1
|
71
|
+
@total_workspaces = 3
|
72
|
+
allow(@workspace)
|
73
|
+
.to receive(:workspace_values)
|
74
|
+
.and_return([@current_workspace, @total_workspaces])
|
75
|
+
end
|
67
76
|
context "when workspace: 'prev'" do
|
68
77
|
around do |example|
|
69
78
|
ConfigHelper.load_config_yml = <<~CONFIG
|
@@ -79,28 +88,8 @@ module Fusuma
|
|
79
88
|
end
|
80
89
|
|
81
90
|
it 'should return wmctrl command' do
|
82
|
-
expect(@
|
83
|
-
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
context "when workspace: 'next'" do
|
88
|
-
around do |example|
|
89
|
-
ConfigHelper.load_config_yml = <<~CONFIG
|
90
|
-
dummy:
|
91
|
-
1:
|
92
|
-
direction:
|
93
|
-
workspace: 'next'
|
94
|
-
CONFIG
|
95
|
-
|
96
|
-
example.run
|
97
|
-
|
98
|
-
Config.custom_path = nil
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'should return wmctrl command' do
|
102
|
-
expect(@executor.search_command(@event))
|
103
|
-
.to match(/wmctrl -s #{@default_workspace_num + 1}/)
|
91
|
+
expect(@workspace).to receive(:move_command).with(direction: 'prev')
|
92
|
+
@executor.search_command(@event)
|
104
93
|
end
|
105
94
|
end
|
106
95
|
|
@@ -119,32 +108,8 @@ module Fusuma
|
|
119
108
|
end
|
120
109
|
|
121
110
|
it 'should return wmctrl command' do
|
122
|
-
expect(@
|
123
|
-
|
124
|
-
expect(@executor.search_command(@event))
|
125
|
-
.to match(/wmctrl -s #{@default_workspace_num - 1}/)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
context "when window: 'next'" do
|
130
|
-
around do |example|
|
131
|
-
ConfigHelper.load_config_yml = <<~CONFIG
|
132
|
-
dummy:
|
133
|
-
1:
|
134
|
-
direction:
|
135
|
-
window: 'next'
|
136
|
-
CONFIG
|
137
|
-
|
138
|
-
example.run
|
139
|
-
|
140
|
-
Config.custom_path = nil
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'should return wmctrl command' do
|
144
|
-
expect(@executor.search_command(@event))
|
145
|
-
.to match(/wmctrl -r :ACTIVE: -t #{@default_workspace_num + 1}/)
|
146
|
-
expect(@executor.search_command(@event))
|
147
|
-
.to match(/wmctrl -s #{@default_workspace_num + 1}/)
|
111
|
+
expect(@workspace).to receive(:move_window_command).with(direction: 'prev')
|
112
|
+
@executor.search_command(@event)
|
148
113
|
end
|
149
114
|
end
|
150
115
|
|
@@ -338,112 +303,40 @@ module Fusuma
|
|
338
303
|
end
|
339
304
|
|
340
305
|
describe 'wrap_navigation: true' do
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
plugin:
|
349
|
-
executors:
|
350
|
-
wmctrl_executor:
|
351
|
-
wrap-navigation: true
|
352
|
-
CONFIG
|
353
|
-
|
354
|
-
example.run
|
355
|
-
|
356
|
-
Config.custom_path = nil
|
357
|
-
end
|
358
|
-
|
359
|
-
it 'should return wmctrl command with an index last workspace' do
|
360
|
-
current_workspace = 0
|
361
|
-
total_workspaces = 3
|
362
|
-
|
363
|
-
allow(WmctrlExecutor::Workspace)
|
364
|
-
.to receive(:workspace_values)
|
365
|
-
.and_return([current_workspace, total_workspaces])
|
366
|
-
|
367
|
-
expect(@executor.search_command(@event))
|
368
|
-
.to match(/wmctrl -s #{total_workspaces - 1}/)
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
context "when workspace: 'next' and current workspace = total - 1" do
|
373
|
-
around do |example|
|
374
|
-
ConfigHelper.load_config_yml = <<~CONFIG
|
375
|
-
dummy:
|
376
|
-
1:
|
377
|
-
direction:
|
378
|
-
workspace: 'next'
|
379
|
-
plugin:
|
380
|
-
executors:
|
381
|
-
wmctrl_executor:
|
382
|
-
wrap-navigation: true
|
383
|
-
CONFIG
|
384
|
-
|
385
|
-
example.run
|
386
|
-
|
387
|
-
Config.custom_path = nil
|
388
|
-
end
|
389
|
-
|
390
|
-
it 'should return wmctrl command with an index of first workspace' do
|
391
|
-
current_workspace = 3
|
392
|
-
total_workspaces = 4
|
306
|
+
around do |example|
|
307
|
+
ConfigHelper.load_config_yml = <<~CONFIG
|
308
|
+
plugin:
|
309
|
+
executors:
|
310
|
+
wmctrl_executor:
|
311
|
+
wrap-navigation: true
|
312
|
+
CONFIG
|
393
313
|
|
394
|
-
|
395
|
-
.to receive(:workspace_values)
|
396
|
-
.and_return([current_workspace, total_workspaces])
|
314
|
+
example.run
|
397
315
|
|
398
|
-
|
399
|
-
.to match(/wmctrl -s 0/)
|
400
|
-
end
|
316
|
+
Config.custom_path = nil
|
401
317
|
end
|
402
318
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
window: 'prev'
|
410
|
-
plugin:
|
411
|
-
executors:
|
412
|
-
wmctrl_executor:
|
413
|
-
wrap-navigation: true
|
414
|
-
CONFIG
|
415
|
-
|
416
|
-
example.run
|
417
|
-
|
418
|
-
Config.custom_path = nil
|
419
|
-
end
|
420
|
-
|
421
|
-
it 'should return wmctrl command with index of last workspace' do
|
422
|
-
current_workspace = 0
|
423
|
-
total_workspaces = 5
|
424
|
-
|
425
|
-
allow(WmctrlExecutor::Workspace)
|
426
|
-
.to receive(:workspace_values)
|
427
|
-
.and_return([current_workspace, total_workspaces])
|
428
|
-
|
429
|
-
expect(@executor.search_command(@event))
|
430
|
-
.to match(/wmctrl -r :ACTIVE: -t #{total_workspaces - 1}/)
|
431
|
-
expect(@executor.search_command(@event))
|
432
|
-
.to match(/wmctrl -s #{total_workspaces - 1}/)
|
433
|
-
end
|
319
|
+
it 'should wrap-navigation mode' do
|
320
|
+
expect(Workspace).to receive(:new).with(
|
321
|
+
wrap_navigation: true,
|
322
|
+
matrix_col_size: nil
|
323
|
+
)
|
324
|
+
WmctrlExecutor.new
|
434
325
|
end
|
326
|
+
end
|
435
327
|
|
436
|
-
|
328
|
+
describe 'matrix-col-size' do
|
329
|
+
context "with matrix-col-size: '3', right" do
|
437
330
|
around do |example|
|
438
331
|
ConfigHelper.load_config_yml = <<~CONFIG
|
439
332
|
dummy:
|
440
333
|
1:
|
441
334
|
direction:
|
442
|
-
window: '
|
335
|
+
window: 'right'
|
443
336
|
plugin:
|
444
337
|
executors:
|
445
338
|
wmctrl_executor:
|
446
|
-
|
339
|
+
matrix-col-size: 3
|
447
340
|
CONFIG
|
448
341
|
|
449
342
|
example.run
|
@@ -451,18 +344,10 @@ module Fusuma
|
|
451
344
|
Config.custom_path = nil
|
452
345
|
end
|
453
346
|
|
454
|
-
it 'should return wmctrl command with index of
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
allow(WmctrlExecutor::Workspace)
|
459
|
-
.to receive(:workspace_values)
|
460
|
-
.and_return([current_workspace, total_workspaces])
|
461
|
-
|
462
|
-
expect(@executor.search_command(@event))
|
463
|
-
.to match(/wmctrl -r :ACTIVE: -t 0/)
|
464
|
-
expect(@executor.search_command(@event))
|
465
|
-
.to match(/wmctrl -s 0/)
|
347
|
+
it 'should return wmctrl command with index of right(next) workspace' do
|
348
|
+
expect(@workspace).to receive(:move_window_command_for_matrix)
|
349
|
+
.with(direction: 'right')
|
350
|
+
@executor.search_command(@event)
|
466
351
|
end
|
467
352
|
end
|
468
353
|
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require './lib/fusuma/plugin/wmctrl/workspace'
|
5
|
+
|
6
|
+
module Fusuma
|
7
|
+
module Plugin
|
8
|
+
module Wmctrl
|
9
|
+
RSpec.describe Workspace do
|
10
|
+
def stub_workspace_values(current:, total:)
|
11
|
+
allow(@workspace).to receive(:workspace_values).and_return([current, total])
|
12
|
+
end
|
13
|
+
|
14
|
+
before { @workspace = Workspace.new }
|
15
|
+
|
16
|
+
describe '#move_command' do
|
17
|
+
before { stub_workspace_values(current: 1, total: 3) }
|
18
|
+
|
19
|
+
context "with 'direction: next'" do
|
20
|
+
before { @direction = 'next' }
|
21
|
+
it 'returns wmctrl command to move NEXT workspace' do
|
22
|
+
expect(@workspace.move_command(direction: @direction))
|
23
|
+
.to match(/wmctrl -s 2/)
|
24
|
+
end
|
25
|
+
it 'calls next_workspace_num' do
|
26
|
+
expect(@workspace).to receive(:next_workspace_num).with(step: 1)
|
27
|
+
@workspace.move_command(direction: @direction)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#move_command_for_matrix' do
|
33
|
+
before do
|
34
|
+
@workspace = Workspace.new(matrix_col_size: 3)
|
35
|
+
stub_workspace_values(current: 0, total: 9)
|
36
|
+
end
|
37
|
+
|
38
|
+
context "with direction: 'right'" do
|
39
|
+
before { @direction = 'right' }
|
40
|
+
|
41
|
+
it 'returns wmctrl command to move RIGHT workspace' do
|
42
|
+
expect(@workspace.move_command_for_matrix(direction: @direction))
|
43
|
+
.to match(/wmctrl -s 1/)
|
44
|
+
end
|
45
|
+
it 'calls next_workspace_num_for_matrix' do
|
46
|
+
expect(@workspace).to receive(:next_workspace_num_for_matrix)
|
47
|
+
.with(direction: @direction)
|
48
|
+
@workspace.move_command_for_matrix(direction: @direction)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
context "with direction: 'down'" do
|
52
|
+
before { @direction = 'down' }
|
53
|
+
|
54
|
+
it 'returns wmctrl command to move workspace to DOWN' do
|
55
|
+
expect(@workspace.move_command_for_matrix(direction: @direction))
|
56
|
+
.to match(/wmctrl -s 3/)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#move_window_command' do
|
62
|
+
before { stub_workspace_values(current: 1, total: 3) }
|
63
|
+
|
64
|
+
context "with direction: 'next'" do
|
65
|
+
before { @direction = 'next' }
|
66
|
+
|
67
|
+
it 'returns wmctrl command to move NEXT workspace' do
|
68
|
+
wmctrl_move_window = /wmctrl -r :ACTIVE: -t 2/
|
69
|
+
wmctrl_move_workspace = /wmctrl -s 2/
|
70
|
+
expect(@workspace.move_window_command(direction: @direction))
|
71
|
+
.to match(wmctrl_move_window)
|
72
|
+
expect(@workspace.move_window_command(direction: @direction))
|
73
|
+
.to match(wmctrl_move_workspace)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "with direction: 'prev'" do
|
78
|
+
before { @direction = 'prev' }
|
79
|
+
|
80
|
+
it 'returns wmctrl command to move NEXT workspace' do
|
81
|
+
wmctrl_move_window = /wmctrl -r :ACTIVE: -t 0/
|
82
|
+
wmctrl_move_workspace = /wmctrl -s 0/
|
83
|
+
expect(@workspace.move_window_command(direction: @direction))
|
84
|
+
.to match(wmctrl_move_window)
|
85
|
+
expect(@workspace.move_window_command(direction: @direction))
|
86
|
+
.to match(wmctrl_move_workspace)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#move_window_command_for_matrix' do
|
92
|
+
before do
|
93
|
+
@workspace = Workspace.new(matrix_col_size: 3)
|
94
|
+
stub_workspace_values(current: 0, total: 9)
|
95
|
+
end
|
96
|
+
|
97
|
+
context "with direction: 'right'" do
|
98
|
+
before { @direction = 'right' }
|
99
|
+
|
100
|
+
it 'returns wmctrl command to move NEXT workspace' do
|
101
|
+
wmctrl_move_window = /wmctrl -r :ACTIVE: -t 1/
|
102
|
+
wmctrl_move_workspace = /wmctrl -s 1/
|
103
|
+
expect(@workspace.move_window_command_for_matrix(direction: @direction))
|
104
|
+
.to match(wmctrl_move_window)
|
105
|
+
expect(@workspace.move_window_command_for_matrix(direction: @direction))
|
106
|
+
.to match(wmctrl_move_workspace)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
context "with direction: 'down'" do
|
110
|
+
before { @direction = 'down' }
|
111
|
+
|
112
|
+
it 'returns wmctrl command to move NEXT workspace' do
|
113
|
+
wmctrl_move_window = /wmctrl -r :ACTIVE: -t 3/
|
114
|
+
wmctrl_move_workspace = /wmctrl -s 3/
|
115
|
+
expect(@workspace.move_window_command_for_matrix(direction: @direction))
|
116
|
+
.to match(wmctrl_move_window)
|
117
|
+
expect(@workspace.move_window_command_for_matrix(direction: @direction))
|
118
|
+
.to match(wmctrl_move_workspace)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#next_workspace_num' do
|
124
|
+
before { stub_workspace_values(current: 1, total: 3) }
|
125
|
+
context 'with step: 1' do
|
126
|
+
before { @step = 1 }
|
127
|
+
it { expect(@workspace.next_workspace_num(step: @step)).to eq 1 + @step }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '#next_workspace_num_for_matrix' do
|
132
|
+
context 'without matrix option' do
|
133
|
+
before { @workspace = Workspace.new(matrix_col_size: nil) }
|
134
|
+
|
135
|
+
it 'raises InvalidOption' do
|
136
|
+
expect do
|
137
|
+
@workspace.next_workspace_num_for_matrix(direction: 'prev')
|
138
|
+
end.to raise_error(Workspace::InvalidOption)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'with matrix_col_size: 3' do
|
143
|
+
# +---+---+---+
|
144
|
+
# | 0 | 1 | 2 |
|
145
|
+
# +---+---+---+
|
146
|
+
# | 3 | 4 | 5 |
|
147
|
+
# +---+---+---+
|
148
|
+
# | 6 | 7 | 8 |
|
149
|
+
# +---+---+---+
|
150
|
+
before do
|
151
|
+
@workspace = Workspace.new(matrix_col_size: 3)
|
152
|
+
stub_workspace_values(current: 1, total: 9)
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'with invalid direction' do
|
156
|
+
before { @direction = 'foo' }
|
157
|
+
it 'raises InvalidOption' do
|
158
|
+
expect do
|
159
|
+
@workspace.next_workspace_num_for_matrix(direction: @direction)
|
160
|
+
end.to raise_error(RuntimeError, "#{@direction} is invalid key")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'with direction: right' do
|
165
|
+
before { @direction = 'right' }
|
166
|
+
it 'next workspace' do
|
167
|
+
expect(
|
168
|
+
@workspace.next_workspace_num_for_matrix(direction: @direction)
|
169
|
+
).to eq 2
|
170
|
+
end
|
171
|
+
context 'when current_workspace is right edge' do
|
172
|
+
before { stub_workspace_values(current: 2, total: 9) }
|
173
|
+
it 'same workspace' do
|
174
|
+
expect(
|
175
|
+
@workspace.next_workspace_num_for_matrix(direction: @direction)
|
176
|
+
).to eq 2
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'with wrap_navigation: true' do
|
180
|
+
before { @workspace.instance_variable_set(:@wrap_navigation, true) }
|
181
|
+
it 'same workspace' do
|
182
|
+
expect(
|
183
|
+
@workspace.next_workspace_num_for_matrix(direction: @direction)
|
184
|
+
).to eq 0
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
context 'with direction: down' do
|
190
|
+
before { @direction = 'down' }
|
191
|
+
it 'next workspace' do
|
192
|
+
expect(
|
193
|
+
@workspace.next_workspace_num_for_matrix(direction: @direction)
|
194
|
+
).to eq 4
|
195
|
+
end
|
196
|
+
context 'when current_workspace is bottom' do
|
197
|
+
before { stub_workspace_values(current: 7, total: 9) }
|
198
|
+
it 'same workspace' do
|
199
|
+
expect(
|
200
|
+
@workspace.next_workspace_num_for_matrix(direction: @direction)
|
201
|
+
).to eq 7
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'with wrap_navigation: true' do
|
205
|
+
before { @workspace.instance_variable_set(:@wrap_navigation, true) }
|
206
|
+
it 'same workspace' do
|
207
|
+
expect(
|
208
|
+
@workspace.next_workspace_num_for_matrix(direction: @direction)
|
209
|
+
).to eq 1
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe '#matrix_size' do
|
218
|
+
context 'with matrix_col_size' do
|
219
|
+
before do
|
220
|
+
@workspace = Workspace.new(matrix_col_size: 3)
|
221
|
+
stub_workspace_values(current: 1, total: 3)
|
222
|
+
end
|
223
|
+
it { expect(@workspace.matrix_size(3)).to eq [1, 3] }
|
224
|
+
end
|
225
|
+
context 'with matrix_col_size' do
|
226
|
+
before do
|
227
|
+
@workspace = Workspace.new(matrix_col_size: nil)
|
228
|
+
stub_workspace_values(current: 1, total: 3)
|
229
|
+
end
|
230
|
+
it { expect { @workspace.matrix_size(3) }.to raise_error Workspace::InvalidOption }
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fusuma-plugin-wmctrl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iberianpig
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fusuma
|
@@ -39,7 +39,10 @@ files:
|
|
39
39
|
- lib/fusuma/plugin/executors/wmctrl_executor.rb
|
40
40
|
- lib/fusuma/plugin/wmctrl.rb
|
41
41
|
- lib/fusuma/plugin/wmctrl/version.rb
|
42
|
+
- lib/fusuma/plugin/wmctrl/window.rb
|
43
|
+
- lib/fusuma/plugin/wmctrl/workspace.rb
|
42
44
|
- spec/fusuma/plugin/plugin/executors/wmctrl_executor_spec.rb
|
45
|
+
- spec/fusuma/plugin/plugin/wmctrl/workspace_spec.rb
|
43
46
|
- spec/fusuma/plugin/wmctrl_spec.rb
|
44
47
|
- spec/helpers/config_helper.rb
|
45
48
|
- spec/spec_helper.rb
|
@@ -55,7 +58,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
58
|
requirements:
|
56
59
|
- - ">="
|
57
60
|
- !ruby/object:Gem::Version
|
58
|
-
version:
|
61
|
+
version: 2.5.1
|
59
62
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
63
|
requirements:
|
61
64
|
- - ">="
|
@@ -67,6 +70,7 @@ signing_key:
|
|
67
70
|
specification_version: 4
|
68
71
|
summary: Wmctrl plugin for Fusuma
|
69
72
|
test_files:
|
73
|
+
- spec/fusuma/plugin/plugin/wmctrl/workspace_spec.rb
|
70
74
|
- spec/fusuma/plugin/plugin/executors/wmctrl_executor_spec.rb
|
71
75
|
- spec/fusuma/plugin/wmctrl_spec.rb
|
72
76
|
- spec/helpers/config_helper.rb
|