ruby-wmctrl 0.0.7 → 0.0.8

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: 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