ruby-wmctrl 0.0.7 → 0.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64b85024233d08a600bd914867fcf4e3250aa4c21e8ec45eb7bf31644c3a317c
4
- data.tar.gz: d42e156ef9c64fd3b43664b3cc4738295528541c12cae7dd7d4897c34e9496e4
3
+ metadata.gz: 207ccda9bcf9eef6653853a9cbf21f4ff720348c2e105ed438862b6dbd1d99c0
4
+ data.tar.gz: 59318faac41732c72b002e2aab29e00bbb76c711e058f066a8683fad81ac9607
5
5
  SHA512:
6
- metadata.gz: b83996d39afbf0b47c6b964673f0a147ac6dc10d49670f3dfac051092fb45684e9e114ec07378034e443b04c539fff7bb7cc564773484efc8931dc771b8e134b
7
- data.tar.gz: 412805d6b06f93ba5fad169dc2192204cdfcbb410778c1459421a11c6d3d5891d9f6aab9507f265d96abd4342af2f8603ff6959936448794ad8d56e954e734f7
6
+ metadata.gz: 7839e29f39f10420a359ad6891ce9225ca8d830f9d7ac68dc822cc9519c987cc79ee5097737bb7bac55e13d9017b376c112b09092feee524c48d3828c5429af4
7
+ data.tar.gz: 9c1fa80e1b3e5656f64f80a1908c7a7187b2e27f5f4c456eb263b4d7b9791b073202297f8711a29e1614da435b44f6918f35dee20b8ef66eafbddb41a029e497
data/README.md CHANGED
@@ -31,12 +31,12 @@ We load 'wmctrl' as below;
31
31
 
32
32
  We get desktops and windows as follows;
33
33
 
34
- pp WMCtrl.instance.desktops
35
- pp WMCtrl.instance.windows
34
+ pp WMCtrl.display.desktops
35
+ pp WMCtrl.display.windows
36
36
 
37
37
  We can specify search conditions of windows; for example,
38
38
 
39
- pp WMCtrl.instance.windows(:wm_class => /^emacs/)
39
+ pp WMCtrl.display.windows(:wm_class => /^emacs/)
40
40
 
41
41
  ## Usage (Basic method similar to the command "wmctrl")
42
42
 
@@ -47,7 +47,7 @@ but the author think that these methods may be changed in future release.
47
47
 
48
48
  require 'wmctrl'
49
49
  require 'pp'
50
- wm = WMCtrl.instance
50
+ wm = WMCtrl.display
51
51
  pp wm.list_windows
52
52
 
53
53
  If you want to get properties of windows, you pass true as an argument.
@@ -111,4 +111,4 @@ Copyright (C) 2003
111
111
 
112
112
  ### ruby-wmctrl
113
113
 
114
- Takayuki YAMAGUCHI d@ytak.info Copyright (C) 2011
114
+ Takayuki YAMAGUCHI d@ytak.info Copyright (C) 2011-2019
@@ -143,11 +143,11 @@ MES
143
143
  exit(2)
144
144
  end
145
145
 
146
- wm = WMCtrl.instance
146
+ wm = WMCtrl.display
147
147
 
148
148
  # Return first window specified by arg and options
149
149
  def specify_window(arg, options)
150
- wm = WMCtrl.instance
150
+ wm = WMCtrl.display
151
151
  win = nil
152
152
  if arg == ':ACTIVE:'
153
153
  win = wm.windows(:active => true).first
@@ -32,7 +32,7 @@ static int client_msg(Display *disp, Window win, const char *msg,
32
32
  unsigned long data4);
33
33
  static gchar *get_property (Display *disp, Window win,
34
34
  Atom xa_prop_type, const gchar *prop_name, unsigned long *size);
35
- static Window *get_client_list (Display *disp, unsigned long *size);
35
+ static Window *get_client_list (Display *disp, unsigned long *size, gboolean stacking_order);
36
36
  static gchar *get_window_class (Display *disp, Window win);
37
37
  static gchar *get_window_title (Display *disp, Window win);
38
38
  static VALUE activate_window (Display *disp, Window win, gboolean switch_desktop);
@@ -48,7 +48,7 @@ static Window get_target_window (Display *disp, VALUE obj);
48
48
 
49
49
 
50
50
  static VALUE rb_wmctrl_class, key_id, key_title, key_pid, key_geometry,
51
- key_active, key_class, key_client_machine, key_desktop,
51
+ key_display, key_active, key_class, key_client_machine, key_desktop,
52
52
  key_viewport, key_workarea, key_current, key_showing_desktop, key_name,
53
53
  key_state, key_window_type, key_frame_extents, key_strut, key_exterior_frame;
54
54
 
@@ -60,7 +60,9 @@ static void rb_wmctrl_free (void **ptr)
60
60
  {
61
61
  Display **disp;
62
62
  disp = (Display **) ptr;
63
- XCloseDisplay(*disp);
63
+ if (*disp) {
64
+ XCloseDisplay(*disp);
65
+ }
64
66
  free(ptr);
65
67
  }
66
68
 
@@ -72,14 +74,35 @@ static VALUE rb_wmctrl_alloc(VALUE self)
72
74
 
73
75
  static VALUE rb_wmctrl_initialize(int argc, VALUE *argv, VALUE self)
74
76
  {
77
+ char *display_name = NULL;
75
78
  Display **ptr;
76
79
  Data_Get_Struct(self, Display*, ptr);
77
- if (! (*ptr = XOpenDisplay(NULL))) {
78
- rb_raise(rb_eStandardError, "Cannot open display.\n");
80
+ if (argc > 0) {
81
+ display_name = StringValuePtr(argv[0]);
82
+ }
83
+ if (!(*ptr = XOpenDisplay(display_name))) {
84
+ if (display_name) {
85
+ rb_raise(rb_eStandardError, "Cannot open display %s", display_name);
86
+ } else {
87
+ rb_raise(rb_eStandardError, "Cannot open display");
88
+ }
79
89
  }
80
90
  return self;
81
91
  }
82
92
 
93
+ /*
94
+ Get display name.
95
+
96
+ @return [String] A name of display.
97
+ */
98
+ static VALUE rb_wmctrl_get_display_name (VALUE self) {
99
+ char *display_name;
100
+ Display **ptr;
101
+ Data_Get_Struct(self, Display*, ptr);
102
+ display_name = DisplayString(*ptr);
103
+ return(RB_UTF8_STRING_NEW2(display_name));
104
+ }
105
+
83
106
  static int client_msg(Display *disp, Window win, const char *msg,
84
107
  unsigned long data0, unsigned long data1,
85
108
  unsigned long data2, unsigned long data3,
@@ -107,6 +130,25 @@ static int client_msg(Display *disp, Window win, const char *msg,
107
130
  return True;
108
131
  }
109
132
 
133
+ static VALUE rb_client_msg(VALUE self, VALUE win_id_obj, VALUE msg_obj, VALUE data0_obj, VALUE data1_obj, VALUE data2_obj, VALUE data3_obj, VALUE data4_obj)
134
+ {
135
+ Display **ptr, *disp;
136
+ Window win_id;
137
+ char *msg;
138
+ unsigned long data0, data1, data2, data3, data4;
139
+ win_id = (Window) NUM2LONG(win_id_obj);
140
+ Data_Get_Struct(self, Display*, ptr);
141
+ disp = *ptr;
142
+ msg = StringValuePtr(msg_obj);
143
+ data0 = (Window) NUM2ULONG(data0_obj);
144
+ data1 = (Window) NUM2ULONG(data1_obj);
145
+ data2 = (Window) NUM2ULONG(data2_obj);
146
+ data3 = (Window) NUM2ULONG(data3_obj);
147
+ data4 = (Window) NUM2ULONG(data4_obj);
148
+ client_msg(disp, win_id, msg, data0, data1, data2, data3, data4);
149
+ return Qtrue;
150
+ }
151
+
110
152
  /* Copy from debian package for 64bit support. */
111
153
  static gchar *get_property (Display *disp, Window win,
112
154
  Atom xa_prop_type, const gchar *prop_name, unsigned long *size)
@@ -166,21 +208,23 @@ static gchar *get_property (Display *disp, Window win,
166
208
  return ret;
167
209
  }
168
210
 
169
- static Window *get_client_list (Display *disp, unsigned long *size)
211
+ static Window *get_client_list (Display *disp, unsigned long *size, gboolean stacking_order)
170
212
  {
171
213
  Window *client_list;
172
-
173
- if ((client_list = (Window *)get_property(disp, DefaultRootWindow(disp),
174
- XA_WINDOW, "_NET_CLIENT_LIST", size)) == NULL) {
175
- if ((client_list = (Window *)get_property(disp, DefaultRootWindow(disp),
176
- XA_CARDINAL, "_WIN_CLIENT_LIST", size)) == NULL) {
177
- fputs("Cannot get client list properties. \n"
178
- "(_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"
179
- "\n", stderr);
180
- return NULL;
214
+ if (stacking_order) {
215
+ client_list = (Window *)get_property(disp, DefaultRootWindow(disp), XA_WINDOW, "_NET_CLIENT_LIST_STACKING", size);
216
+ } else {
217
+ client_list = (Window *)get_property(disp, DefaultRootWindow(disp), XA_WINDOW, "_NET_CLIENT_LIST", size);
218
+ if (client_list == NULL) {
219
+ client_list = (Window *)get_property(disp, DefaultRootWindow(disp), XA_CARDINAL, "_WIN_CLIENT_LIST", size);
181
220
  }
182
221
  }
183
-
222
+ if (client_list == NULL) {
223
+ fputs("Cannot get client list properties. \n"
224
+ "(_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"
225
+ "\n", stderr);
226
+ return NULL;
227
+ }
184
228
  return client_list;
185
229
  }
186
230
 
@@ -235,7 +279,7 @@ static gchar *get_window_title (Display *disp, Window win)
235
279
  return title_utf8;
236
280
  }
237
281
 
238
- static VALUE get_window_hash_data (Window win, Display *disp, Window window_active, int get_state)
282
+ static VALUE get_window_hash_data (Window win, Display *disp, Window window_active, int get_state, VALUE display_name)
239
283
  {
240
284
  VALUE window_obj = rb_hash_new();
241
285
  gchar *title_utf8 = get_window_title(disp, win); /* UTF8 */
@@ -250,6 +294,7 @@ static VALUE get_window_hash_data (Window win, Display *disp, Window window_acti
250
294
  rb_hash_aset(window_obj, key_id, INT2NUM(win));
251
295
  rb_hash_aset(window_obj, key_title, (title_utf8 ? RB_UTF8_STRING_NEW2(title_utf8) : Qnil));
252
296
  rb_hash_aset(window_obj, key_class, (class_out ? RB_UTF8_STRING_NEW2(class_out) : Qnil));
297
+ rb_hash_aset(window_obj, key_display, display_name);
253
298
 
254
299
  if (window_active == win) {
255
300
  rb_hash_aset(window_obj, key_active, Qtrue);
@@ -378,7 +423,7 @@ static VALUE get_window_hash_data (Window win, Display *disp, Window window_acti
378
423
  }
379
424
 
380
425
  /*
381
- @overload list_windows(get_state = nil)
426
+ @overload list_windows(get_state = nil, stacking_order = nil)
382
427
 
383
428
  Get list of information of windows.
384
429
  @param get_state [Boolean] If the value is true then we get some properties at the same time
@@ -391,23 +436,25 @@ static VALUE rb_wmctrl_list_windows (int argc, VALUE *argv, VALUE self) {
391
436
  Window window_active;
392
437
  unsigned long client_list_size;
393
438
  unsigned int i;
394
- int get_state;
395
- VALUE get_state_obj, window_ary;
439
+ int get_state, stacking_order;
440
+ VALUE get_state_obj, stacking_order_obj, window_ary, display_name;
396
441
  Data_Get_Struct(self, Display*, ptr);
397
442
  disp = *ptr;
398
- rb_scan_args(argc, argv, "01", &get_state_obj);
443
+ rb_scan_args(argc, argv, "02", &get_state_obj, &stacking_order_obj);
399
444
  get_state = RTEST(get_state_obj);
445
+ stacking_order = RTEST(stacking_order_obj);
400
446
 
401
- if ((client_list = get_client_list(disp, &client_list_size)) == NULL) {
447
+ if ((client_list = get_client_list(disp, &client_list_size, stacking_order)) == NULL) {
402
448
  /* return EXIT_FAILURE; */
403
449
  return Qfalse;
404
450
  }
405
451
 
406
452
  window_active = get_active_window(disp);
407
453
  window_ary = rb_ary_new2(client_list_size);
454
+ display_name = rb_wmctrl_get_display_name(self);
408
455
 
409
456
  for (i = 0; i < client_list_size / sizeof(Window); i++) {
410
- rb_ary_push(window_ary, get_window_hash_data(client_list[i], disp, window_active, get_state));
457
+ rb_ary_push(window_ary, get_window_hash_data(client_list[i], disp, window_active, get_state, display_name));
411
458
  }
412
459
  g_free(client_list);
413
460
 
@@ -420,10 +467,12 @@ static VALUE rb_wmctrl_list_windows (int argc, VALUE *argv, VALUE self) {
420
467
  static VALUE rb_wmctrl_get_window_data (VALUE self, VALUE win_id_obj) {
421
468
  Display **ptr, *disp;
422
469
  Window win_id;
470
+ VALUE display_name;
423
471
  win_id = (Window) NUM2LONG(win_id_obj);
424
472
  Data_Get_Struct(self, Display*, ptr);
425
473
  disp = *ptr;
426
- return get_window_hash_data(win_id, disp, -1, TRUE);
474
+ display_name = rb_wmctrl_get_display_name(self);
475
+ return get_window_hash_data(win_id, disp, -1, TRUE, display_name);
427
476
  }
428
477
 
429
478
  /*
@@ -1307,6 +1356,8 @@ void Init_wmctrl()
1307
1356
  rb_define_alloc_func(rb_wmctrl_class, rb_wmctrl_alloc);
1308
1357
  rb_define_private_method(rb_wmctrl_class, "initialize", rb_wmctrl_initialize, -1);
1309
1358
 
1359
+ rb_define_method(rb_wmctrl_class, "get_display_name", rb_wmctrl_get_display_name, 0);
1360
+ rb_define_method(rb_wmctrl_class, "client_msg", rb_client_msg, 7);
1310
1361
  rb_define_method(rb_wmctrl_class, "list_windows", rb_wmctrl_list_windows, -1);
1311
1362
  rb_define_method(rb_wmctrl_class, "get_window_data", rb_wmctrl_get_window_data, 1);
1312
1363
  rb_define_method(rb_wmctrl_class, "list_desktops", rb_wmctrl_list_desktops, 0);
@@ -1323,6 +1374,7 @@ void Init_wmctrl()
1323
1374
  key_title = ID2SYM(rb_intern("title"));
1324
1375
  key_pid = ID2SYM(rb_intern("pid"));
1325
1376
  key_geometry = ID2SYM(rb_intern("geometry"));
1377
+ key_display = ID2SYM(rb_intern("display"));
1326
1378
  key_active = ID2SYM(rb_intern("active"));
1327
1379
  key_class = ID2SYM(rb_intern("class"));
1328
1380
  key_client_machine = ID2SYM(rb_intern("client_machine"));
@@ -1,3 +1,3 @@
1
1
  class WMCtrl
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
@@ -14,8 +14,20 @@ class WMCtrl
14
14
  GRAVITY_SOUTH_EAST = 9
15
15
  GRAVITY_STATIC = 10
16
16
 
17
+ @wmctrl = {}
18
+
17
19
  def self.instance
18
- @wmctrl ||= self.new
20
+ STDERR.puts "WMCtrl.instance is deprecated. Please use WMCtrl.display alternatively."
21
+ self.display
22
+ end
23
+
24
+ def self.display(dpy = nil)
25
+ dpy ||= ENV["DISPLAY"]
26
+ unless display = @wmctrl[dpy]
27
+ display = self.new(dpy)
28
+ @wmctrl[dpy] = display
29
+ end
30
+ display
19
31
  end
20
32
 
21
33
  class DataHash
@@ -68,7 +80,7 @@ class WMCtrl
68
80
 
69
81
  class Window < DataHash
70
82
  [:id, :title, :active, :desktop, :client_machine,
71
- :pid, :geometry, :state, :exterior_frame, :frame_extents, :strut].each do |key|
83
+ :pid, :geometry, :state, :exterior_frame, :frame_extents, :strut, :display].each do |key|
72
84
  define_method(key) do
73
85
  self[key]
74
86
  end
@@ -131,8 +143,9 @@ class WMCtrl
131
143
  end
132
144
 
133
145
  def action(*args)
134
- WMCtrl.instance.action_window(self[:id], *args)
135
- @data = WMCtrl.instance.get_window_data(self[:id])
146
+ wmctrl = WMCtrl.display(self[:display])
147
+ wmctrl.action_window(self[:id], *args)
148
+ @data = wmctrl.get_window_data(self[:id])
136
149
  self
137
150
  end
138
151
  private :action
@@ -191,16 +204,26 @@ class WMCtrl
191
204
  list_desktops.map { |hash| WMCtrl::Desktop.new(hash) }
192
205
  end
193
206
 
207
+ # @overload windows(*conditions, opts = {}, &block)
194
208
  # @param [Array] conditions An array of condition hash.
195
209
  # The keys of the hash are keys of WMCtrl::Window#[].
196
210
  # The values of the hash are tested by the method ===.
197
211
  # Keys of each condition are combined by logical product and
198
212
  # all conditions are combined by logical sum.
213
+ # @param [Hash] opts Options
214
+ # @option opts [Integer] :order Order of windows: :mapping or :stacking
199
215
  # @yield [WMCtrl::Window] Test window by block
200
216
  # @return [Array] An array of WMCtrl::Window including windows
201
217
  # matched by the conditions and the block.
202
218
  def windows(*conditions, &block)
203
- wins = list_windows(true).map { |hash| WMCtrl::Window.new(hash) }
219
+ cond_last = conditions.last || {}
220
+ if cond_last[:order] && (cond_last[:order] == :stacking)
221
+ conditions.pop
222
+ wins = list_windows(true, true)
223
+ else
224
+ wins = list_windows(true, nil)
225
+ end
226
+ wins.map! { |h| WMCtrl::Window.new(h) }
204
227
  unless conditions.empty?
205
228
  wins_selected = []
206
229
  conditions.each do |condition|
@@ -221,4 +244,25 @@ class WMCtrl
221
244
  end
222
245
  wins
223
246
  end
247
+
248
+ WAIT_CHANGE_STACKING_ORDER = 0.01
249
+
250
+ # @param [Hash] opts Options
251
+ # @option opts [Float] :waiting_time Time to wait restack request
252
+ # @option opts [String] :display Display name
253
+ def restack(wins_bottom_to_top, opts = {})
254
+ win_upper = nil
255
+ waiting_time = opts[:sleep] || WAIT_CHANGE_STACKING_ORDER
256
+ wins_bottom_to_top.reverse.each do |win|
257
+ next if win.sticky?
258
+ if win_upper
259
+ # 1 means below
260
+ WMCtrl.display(opts[:display]).client_msg(win.id, "_NET_RESTACK_WINDOW", 2, win_upper.id, 1, 0, 0)
261
+ # If there is no sleep, change the stacking order fails.
262
+ # Can we use _NET_WM_SYNC_REQUEST?
263
+ sleep(waiting_time)
264
+ end
265
+ win_upper = win
266
+ end
267
+ end
224
268
  end
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.extensions = Dir.glob("ext/**/extconf.rb")
20
20
 
21
21
  # specify any dependencies here; for example:
22
+ spec.add_development_dependency "rake"
22
23
  spec.add_development_dependency "rspec"
23
24
  spec.add_development_dependency "yard"
24
25
  spec.add_runtime_dependency "pkg-config"
@@ -15,6 +15,16 @@ describe WMCtrl do
15
15
  wins.each do |w|
16
16
  expect(w).to be_an_instance_of Hash
17
17
  end
18
+ wins = wm.list_windows(true)
19
+ expect(wins).to be_an_instance_of Array
20
+ wins.each do |w|
21
+ expect(w).to be_an_instance_of Hash
22
+ end
23
+ wins = wm.list_windows(true, true)
24
+ expect(wins).to be_an_instance_of Array
25
+ wins.each do |w|
26
+ expect(w).to be_an_instance_of Hash
27
+ end
18
28
  end
19
29
 
20
30
  it "should get an array of hashes." do
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-wmctrl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takayuki YAMAGUCHI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-17 00:00:00.000000000 Z
11
+ date: 2019-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -111,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
125
  - !ruby/object:Gem::Version
112
126
  version: '0'
113
127
  requirements: []
114
- rubyforge_project:
115
- rubygems_version: 2.7.3
128
+ rubygems_version: 3.0.3
116
129
  signing_key:
117
130
  specification_version: 4
118
131
  summary: Ruby bindings to control windows