fusuma-plugin-wmctrl 0.4.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37b4a5e6419c6747eabf01018d034c02b5cca98ffb7b523fe1d33f7cce03859a
4
- data.tar.gz: bc8c76aef630cbed08ad068af3cac600dc105821cd8b18ae75477ae2dc7ae35a
3
+ metadata.gz: 260a70ddbdd31218d0e43a7c354482b44d1cc17aaf7ece9fe3800ce7bf156c72
4
+ data.tar.gz: 0a15ae0fbe6c080fccc5e460400a3b77e062079e00f0a90dabdfb43d3c5d4dd2
5
5
  SHA512:
6
- metadata.gz: 4e4a0404a5be2a300a6b1cf9ac40a8fbb0d5061173530d5e24a255b18b741bb0687b580b016f54930676bbe2af20842aa09aa07e0065d3cfbf5fb0bc6958e64e
7
- data.tar.gz: 98afa73285943a1bef00cbe0bba092fd35cab401cd2b1503926981fd404271d6c05b73e4164e65e0f98a3623b6da61b089619455dcb7f44af4d447d0c82bd9d2
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 ```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)
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.3' # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=main
25
+ spec.required_ruby_version = '>= 2.5.1' # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=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
- require 'singleton'
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.configure(wrap_navigation: config_params(:'wrap-navigation'))
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
- direction = Config.search(index)
63
- return unless direction.is_a?(String)
64
-
65
- Workspace.move_command(direction: direction)
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
- Window.move_command(direction: property)
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
- Window.fullscreen(method: 'toggle')
95
+ @window.fullscreen(method: 'toggle')
79
96
  when 'maximized'
80
- Window.maximized(method: 'toggle')
97
+ @window.maximized(method: 'toggle')
81
98
  when 'close'
82
- Window.close
99
+ @window.close
83
100
  when Hash
84
101
  if property[:fullscreen]
85
- Window.fullscreen(method: property[:fullscreen])
102
+ @window.fullscreen(method: property[:fullscreen])
86
103
  elsif property[:maximized]
87
- Window.maximized(method: property[:maximized])
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
@@ -3,7 +3,7 @@
3
3
  module Fusuma
4
4
  module Plugin
5
5
  module Wmctrl
6
- VERSION = '0.4.3'
6
+ VERSION = '1.0.0'
7
7
  end
8
8
  end
9
9
  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
- .to receive(:spawn).with(@executor.search_command(@event))
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(@executor.search_command(@event))
83
- .to match(/wmctrl -s #{@default_workspace_num - 1}/)
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(@executor.search_command(@event))
123
- .to match(/wmctrl -r :ACTIVE: -t #{@default_workspace_num - 1}/)
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
- context "when workspace: 'prev' and current workspace 0" do
342
- around do |example|
343
- ConfigHelper.load_config_yml = <<~CONFIG
344
- dummy:
345
- 1:
346
- direction:
347
- workspace: 'prev'
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
- allow(WmctrlExecutor::Workspace)
395
- .to receive(:workspace_values)
396
- .and_return([current_workspace, total_workspaces])
314
+ example.run
397
315
 
398
- expect(@executor.search_command(@event))
399
- .to match(/wmctrl -s 0/)
400
- end
316
+ Config.custom_path = nil
401
317
  end
402
318
 
403
- context "when window: 'prev' and current workspace has index 0" do
404
- around do |example|
405
- ConfigHelper.load_config_yml = <<~CONFIG
406
- dummy:
407
- 1:
408
- direction:
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
- context "when window: 'next' and current workspace is last" do
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: 'next'
335
+ window: 'right'
443
336
  plugin:
444
337
  executors:
445
338
  wmctrl_executor:
446
- wrap-navigation: true
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 first workspace' do
455
- current_workspace = 4
456
- total_workspaces = 5
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.3
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-04-20 00:00:00.000000000 Z
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: '2.3'
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