ruby-wmctrl 0.0.4 → 0.0.5

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.
data/README.md CHANGED
@@ -7,8 +7,10 @@ Ruby bindings to control windows in EWMH and NetWM compatible X Window manager.
7
7
 
8
8
  ## Installation
9
9
 
10
- ruby-wmctrl is a C extended library, which uses glib and x11.
11
- For ubuntu 11.04, we should install packages.
10
+ ruby-wmctrl is a C extended library, which uses glib and x11,
11
+ and is not a program to parse the output of command "wmctrl".
12
+
13
+ On ubuntu 11.04, we should install the following packages.
12
14
 
13
15
  apt-get install libx11-dev libglib2.0-dev libxmu-dev
14
16
 
@@ -16,28 +18,49 @@ Then we can install ruby-wmctrl from rubygems.
16
18
 
17
19
  gem install ruby-wmctrl
18
20
 
21
+ ## Remark
22
+
23
+ Note that values of positions of windows aredifferent from
24
+ those of original "wmctrl" and include frame sizes.
25
+
19
26
  ## Usage
20
27
 
21
- We load 'wmctrl' as below
28
+ We load 'wmctrl' as below;
22
29
 
23
30
  require 'wmctrl'
24
31
 
25
- and call methods of an instance of WMCtrl.
32
+ We get desktops and windows as follows;
33
+
34
+ pp WMCtrl.instance.desktops
35
+ pp WMCtrl.instance.windows
36
+
37
+ We can specify search conditions of windows; for example,
38
+
39
+ pp WMCtrl.instance.windows(:wm_class => /^emacs/)
40
+
41
+ ## Usage (Basic method similar to the command "wmctrl")
42
+
43
+ ruby-wmctrl has some basic methods derived from wmctrl,
44
+ but the author think that these methods may be changed in future release.
26
45
 
27
46
  ### List windows
28
47
 
29
48
  require 'wmctrl'
30
49
  require 'pp'
31
- wm = WMCtrl.new
50
+ wm = WMCtrl.instance
32
51
  pp wm.list_windows
33
52
 
53
+ If you want to get properties of windows, you pass true as an argument.
54
+
55
+ pp wm.list_windows(true)
56
+
34
57
  ### Activate a window
35
58
 
36
59
  wm.action_window(window_id, :activate)
37
60
 
38
- The method 'action_window' takes window ID as first argument.
39
- We can get window ID by the method 'list_windows'.
40
- The second argument of 'action_window' is an action that
61
+ The method 'action\_window' takes window ID as first argument.
62
+ We can get window ID by the method 'list\_windows'.
63
+ The second argument of 'action\_window' is an action that
41
64
  manages the window of window ID.
42
65
  The rest arguments are arguments of the action.
43
66
 
@@ -66,6 +89,11 @@ width, and height, respectively. That is,
66
89
 
67
90
  pp wm.list_desktops
68
91
 
92
+ ## rwmctrl
93
+
94
+ ruby-wmctrl includes the command "rwmctrl", which imitates the command "wmctrl"
95
+ but does not implement all functionalities of "wmctrl".
96
+
69
97
  ## License
70
98
 
71
99
  GPLv2
data/Rakefile CHANGED
@@ -2,3 +2,48 @@ require "bundler/gem_tasks"
2
2
 
3
3
  require 'yard'
4
4
  YARD::Rake::YardocTask.new
5
+
6
+ def each_extconf_directory(&block)
7
+ Dir.glob("ext/**/extconf.rb").each do |extconf|
8
+ cd File.dirname(extconf) do
9
+ yield
10
+ end
11
+ end
12
+ end
13
+
14
+ desc 'Compile extended library'
15
+ task 'ext:compile' do |t|
16
+ each_extconf_directory do
17
+ sh 'ruby extconf.rb' unless File.exist?('Makefile')
18
+ sh 'make'
19
+ end
20
+ end
21
+
22
+ desc 'Compile extended library'
23
+ task 'ext:recompile' do |t|
24
+ each_extconf_directory do
25
+ sh 'make distclean' if File.exist?('Makefile')
26
+ sh 'ruby extconf.rb'
27
+ sh 'make'
28
+ end
29
+ end
30
+
31
+ desc 'Clean'
32
+ task 'ext:clean' do |t|
33
+ each_extconf_directory do
34
+ sh 'make clean' if File.exist?('Makefile')
35
+ end
36
+ end
37
+
38
+ desc 'Clean completely'
39
+ task 'ext:distclean' do |t|
40
+ each_extconf_directory do
41
+ sh 'make distclean' if File.exist?('Makefile')
42
+ end
43
+ end
44
+
45
+ require 'rspec/core'
46
+ require 'rspec/core/rake_task'
47
+ RSpec::Core::RakeTask.new(:spec) do |spec|
48
+ spec.pattern = FileList['spec/**/*_spec.rb']
49
+ end
data/bin/rwmctrl CHANGED
@@ -20,7 +20,7 @@ begin
20
20
  opt.on('-p', 'Display PID of windows.') do |v|
21
21
  options[:pid] = true
22
22
  end
23
- opt.on('-x', 'Display class name.') do |v|
23
+ opt.on('-x', 'Display class name or interpret <WIN> as the WM_CLASS name.') do |v|
24
24
  options[:class] = true
25
25
  end
26
26
  opt.on('-G', 'Display geometry of windows.') do |v|
@@ -43,6 +43,10 @@ begin
43
43
  options[:mode] = :close
44
44
  options[:target] = v
45
45
  end
46
+ opt.on('-a <WIN>', String, 'Switch desktop and make the specified window active.') do |v|
47
+ options[:mode] = :make_active
48
+ options[:target] = v
49
+ end
46
50
  opt.on('-d', 'List all desktops.') do |v|
47
51
  options[:mode] = :desktop
48
52
  end
@@ -54,19 +58,62 @@ begin
54
58
  options[:change_state] = v
55
59
  end
56
60
  opt.on('-n N', Integer, 'Change the number of desktops.') do |v|
57
- options[:mode] = :desktop_number
61
+ options[:mode] = :change_number_of_desktops
62
+ options[:arguments] = [v]
63
+ end
64
+ opt.on('-R <WIN>', String, 'Move <WIN> to the current desktop.') do |v|
65
+ options[:mode] = :move_to_current
66
+ options[:target] = v
67
+ end
68
+ opt.on('-t <DESK>', Integer, 'Move a window specified by -r to the desktop <DESK>.') do |v|
69
+ options[:mode] = :move_to_desktop
58
70
  options[:desktop_number] = v
59
71
  end
72
+ opt.on('-g SIZE', String, 'Change the geometry of all desktops. SIZE is the form w,h') do |v|
73
+ options[:mode] = :change_geometry
74
+ w, h = v.split(',').map(&:to_i)
75
+ if w && h
76
+ options[:arguments] = [w, h]
77
+ else
78
+ raise "Invalid argument"
79
+ end
80
+ end
81
+ opt.on('-o SIZE', String, 'Change the viewport. SIZE is the form w,h') do |v|
82
+ options[:mode] = :change_viewport
83
+ w, h = v.split(',').map(&:to_i)
84
+ if w && h
85
+ options[:arguments] = [w, h]
86
+ else
87
+ raise "Invalid argument"
88
+ end
89
+ end
90
+ opt.on('-N STR', String, 'Set long title of specified window.') do |v|
91
+ options[:mode] = :set_title_long
92
+ options[:arguments] = [v]
93
+ end
94
+ opt.on('-I STR', String, 'Set short title of specified window.') do |v|
95
+ options[:mode] = :set_title_short
96
+ options[:arguments] = [v]
97
+ end
98
+ opt.on('-T STR', String, 'Set long and short title of specified window.') do |v|
99
+ options[:mode] = :set_title_both
100
+ options[:arguments] = [v]
101
+ end
102
+ opt.on('-k ARG', String, 'Turn on or off "show the desktop". ARG is on or off.') do |v|
103
+ options[:mode] = :showing_desktop
104
+ if v == "on"
105
+ options[:arguments] = [true]
106
+ elsif v == "off"
107
+ options[:arguments] = [false]
108
+ else
109
+ raise "Invalid argument"
110
+ end
111
+ end
112
+ opt.on('-s <DESK>', Integer, 'Switch to the desktop <DESK>') do |v|
113
+ options[:mode] = :switch_desktop
114
+ options[:arguments] = [v]
115
+ end
60
116
  # Not implemented options
61
- # '-g'
62
- # '-I'
63
- # '-k'
64
- # '-N'
65
- # '-o'
66
- # '-R'
67
- # '-s'
68
- # '-t'
69
- # '-T'
70
117
  # '-w'
71
118
 
72
119
  # '-u'
@@ -75,7 +122,7 @@ begin
75
122
  options[:use_wid] = true
76
123
  end
77
124
  opt.on('-F', 'Use exact match of window title.') do |v|
78
- option[:use_exact] = true
125
+ options[:use_exact] = true
79
126
  end
80
127
  opt.on('--ignore-case', 'Ignore case to specfy target window.') do |v|
81
128
  options[:ignore_case] = true
@@ -96,32 +143,27 @@ MES
96
143
  exit(2)
97
144
  end
98
145
 
99
- wm = WMCtrl.new
146
+ wm = WMCtrl.instance
100
147
 
101
- def specify_window(wm, arg, options)
148
+ # Return first window specified by arg and options
149
+ def specify_window(arg, options)
150
+ wm = WMCtrl.instance
151
+ win = nil
102
152
  if arg == ':ACTIVE:'
103
- wm.list_windows.find do |w|
104
- w[:active] ? w : nil
105
- end
153
+ win = wm.windows(:active => true).first
106
154
  elsif arg == ':SELECT:'
107
155
  raise 'Not implemented.'
108
156
  elsif options[:use_wid]
109
- wid = Integer(arg)
110
- wm.list_windows.find do |w|
111
- wid == w[:id] ? w : nil
112
- end
157
+ win = wm.windows(:id => Integer(arg)).first
113
158
  else
114
- if options[:use_exact]
115
- wm.list_windows.find do |w|
116
- arg == w[:title] ? w : nil
117
- end
118
- else
119
- reg = Regexp.new(arg, options[:ignore_case] ? Regexp::IGNORECASE : 0)
120
- wm.list_windows.find do |w|
121
- reg =~ w[:title] ? w : nil
122
- end
123
- end
159
+ key_name = (options[:class] ? :class : :title)
160
+ cond_title = (options[:use_exact] ? arg : Regexp.new(arg, options[:ignore_case] ? Regexp::IGNORECASE : 0))
161
+ win = wm.windows(key_name => cond_title).first
124
162
  end
163
+ unless win
164
+ raise "Any window is not specified."
165
+ end
166
+ win
125
167
  end
126
168
 
127
169
  case options[:mode]
@@ -154,37 +196,39 @@ when :list_windows
154
196
  puts s
155
197
  end
156
198
  when :move_resize
157
- if target_win = specify_window(wm, options[:target], options)
158
- args = options[:move_resize].split(',').map(&:to_i)
159
- if args.size == 5
160
- wm.action_window(target_win[:id], :move_resize, *args)
161
- else
162
- puts "Invalid arguments."
163
- end
199
+ target_win = specify_window(options[:target], options)
200
+ args = options[:move_resize].split(',').map(&:to_i)
201
+ if args.size == 5
202
+ wm.action_window(target_win[:id], :move_resize, *args)
164
203
  else
165
- puts "Can not specify target window."
204
+ puts "Invalid arguments."
166
205
  end
167
206
  when :change_state
168
- if target_win = specify_window(wm, options[:target], options)
169
- args = options[:change_state].split(',')
170
- if args.size == 2 || args.size == 3
171
- wm.action_window(target_win[:id], :change_state, *args)
172
- else
173
- puts "Invalid property string."
174
- end
207
+ target_win = specify_window(options[:target], options)
208
+ args = options[:change_state].split(',')
209
+ if args.size == 2 || args.size == 3
210
+ target_win.change_state(*args)
211
+ else
212
+ puts "Invalid property string: #{args.inspect}"
175
213
  end
176
214
  when :close
177
- if target_win = specify_window(wm, options[:target], options)
178
- wm.action_window(target_win[:id], :close)
179
- end
215
+ specify_window(options[:target], options).close
216
+ when :make_active
217
+ specify_window(options[:target], options).activate
180
218
  when :desktop
181
219
  wm.list_desktops.each do |dt|
182
220
  printf("%d %s DG: %dx%d VP: %d,%d WA: %d,%d %dx%d %s\n",
183
221
  dt[:id], dt[:current] ? '*' : '-', dt[:geometry][0], dt[:geometry][1], dt[:viewport][0], dt[:viewport][1],
184
222
  dt[:workarea][0], dt[:workarea][1], dt[:workarea][2], dt[:workarea][3], dt[:title])
185
223
  end
186
- when :desktop_number
187
- wm.change_number_of_desktops(options[:desktop_number])
224
+ when :move_to_desktop
225
+ wm.action_window(specify_window(options[:target], options)[:id], :move_to_desktop, options[:desktop_number])
226
+ when :move_to_current
227
+ wm.action_window(specify_window(options[:target], options)[:id], :move_to_current)
228
+ when :change_number_of_desktops, :change_geometry, :change_viewport, :showing_desktop, :switch_desktop
229
+ wm.__send__(options[:mode], *options[:arguments])
230
+ when :set_title_both, :set_title_short, :set_title_long
231
+ wm.action_window(specify_window(options[:target], options)[:id], options[:mode], *options[:arguments])
188
232
  when :wm_info
189
233
  info = wm.info
190
234
  puts "Name: #{info[:name]}"
data/ext/wmctrl.c CHANGED
@@ -61,7 +61,9 @@ static ID id_select, id_active, id_activate, id_close, id_move_resize,
61
61
 
62
62
  static void rb_wmctrl_free (void **ptr)
63
63
  {
64
- XCloseDisplay(*ptr);
64
+ Display **disp;
65
+ disp = (Display **) ptr;
66
+ XCloseDisplay(*disp);
65
67
  free(ptr);
66
68
  }
67
69
 
@@ -237,11 +239,12 @@ static gchar *get_window_title (Display *disp, Window win)
237
239
  }
238
240
 
239
241
  /*
240
- call-seq:
241
- wm.list_windows(get_state = nil)
242
+ @overload list_windows(get_state = nil)
242
243
 
243
244
  Get list of information of windows.
244
245
  @param get_state [Boolean] If the value is true then we get some properties at the same time
246
+
247
+ @return [Hash] An array of hashes of window information.
245
248
  */
246
249
  static VALUE rb_wmctrl_list_windows (int argc, VALUE *argv, VALUE self) {
247
250
  Display **ptr, *disp;
@@ -387,7 +390,11 @@ static VALUE rb_wmctrl_list_windows (int argc, VALUE *argv, VALUE self) {
387
390
  return window_ary;
388
391
  }
389
392
 
390
- /* Get list of information of desktops. */
393
+ /*
394
+ Get list of information of desktops.
395
+
396
+ @return [Hash] An array of hashes of desktop information.
397
+ */
391
398
  static VALUE rb_wmctrl_list_desktops (VALUE self) {
392
399
  Display **ptr, *disp;
393
400
  unsigned long *num_desktops = NULL;
@@ -609,7 +616,15 @@ static VALUE rb_wmctrl_list_desktops (VALUE self) {
609
616
  return ret;
610
617
  }
611
618
 
612
- /* Switch desktop. */
619
+ /*
620
+ @overload switch_desktop(desktop_id)
621
+
622
+ Switch desktop.
623
+
624
+ @param desktop_id [Integer] ID number of desktop.
625
+
626
+ @return [Qtrue]
627
+ */
613
628
  static VALUE rb_wmctrl_switch_desktop (VALUE self, VALUE desktop_id) {
614
629
  int target;
615
630
  Display **ptr, *disp;
@@ -624,7 +639,11 @@ static VALUE rb_wmctrl_switch_desktop (VALUE self, VALUE desktop_id) {
624
639
  return Qtrue;
625
640
  }
626
641
 
627
- /* Get hash of information of window manager. */
642
+ /*
643
+ Get hash of information of window manager.
644
+
645
+ @return [Hash]
646
+ */
628
647
  static VALUE rb_wmctrl_info (VALUE self) {
629
648
  Display **ptr, *disp;
630
649
  Window *sup_window = NULL;
@@ -632,7 +651,7 @@ static VALUE rb_wmctrl_info (VALUE self) {
632
651
  gchar *wm_class = NULL;
633
652
  unsigned long *wm_pid = NULL;
634
653
  unsigned long *showing_desktop = NULL;
635
- gboolean name_is_utf8 = TRUE;
654
+ gboolean name_is_utf8;
636
655
  VALUE ret = rb_hash_new();
637
656
 
638
657
  Data_Get_Struct(self, Display*, ptr);
@@ -644,11 +663,13 @@ static VALUE rb_wmctrl_info (VALUE self) {
644
663
  XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK", NULL))) {
645
664
  fputs("Cannot get window manager info properties.\n"
646
665
  "(_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)\n", stderr);
647
- return EXIT_FAILURE;
666
+ /* return EXIT_FAILURE; */
667
+ return Qfalse;
648
668
  }
649
669
  }
650
670
 
651
671
  /* WM_NAME */
672
+ name_is_utf8 = TRUE;
652
673
  if (! (wm_name = get_property(disp, *sup_window,
653
674
  XInternAtom(disp, "UTF8_STRING", False), "_NET_WM_NAME", NULL))) {
654
675
  name_is_utf8 = FALSE;
@@ -657,8 +678,12 @@ static VALUE rb_wmctrl_info (VALUE self) {
657
678
  p_verbose("Cannot get name of the window manager (_NET_WM_NAME).\n");
658
679
  }
659
680
  }
681
+ if (wm_name) {
682
+ rb_hash_aset(ret, key_name, (name_is_utf8 ? RB_UTF8_STRING_NEW2(wm_name) : rb_str_new(wm_name, strlen(wm_name))));
683
+ }
660
684
 
661
685
  /* WM_CLASS */
686
+ name_is_utf8 = TRUE;
662
687
  if (! (wm_class = get_property(disp, *sup_window,
663
688
  XInternAtom(disp, "UTF8_STRING", False), "WM_CLASS", NULL))) {
664
689
  name_is_utf8 = FALSE;
@@ -667,6 +692,9 @@ static VALUE rb_wmctrl_info (VALUE self) {
667
692
  p_verbose("Cannot get class of the window manager (WM_CLASS).\n");
668
693
  }
669
694
  }
695
+ if (wm_class) {
696
+ rb_hash_aset(ret, key_class, (name_is_utf8 ? RB_UTF8_STRING_NEW2(wm_class) : rb_str_new(wm_class, strlen(wm_class))));
697
+ }
670
698
 
671
699
  /* WM_PID */
672
700
  if (! (wm_pid = (unsigned long *)get_property(disp, *sup_window,
@@ -680,8 +708,6 @@ static VALUE rb_wmctrl_info (VALUE self) {
680
708
  p_verbose("Cannot get the _NET_SHOWING_DESKTOP property.\n");
681
709
  }
682
710
 
683
- rb_hash_aset(ret, key_name, (wm_name ? RB_UTF8_STRING_NEW2(wm_name) : Qnil));
684
- rb_hash_aset(ret, key_class, (wm_class ? RB_UTF8_STRING_NEW2(wm_class) : Qnil));
685
711
  rb_hash_aset(ret, key_pid, (wm_pid ? UINT2NUM(*wm_pid) : Qnil));
686
712
  rb_hash_aset(ret, key_showing_desktop,
687
713
  (showing_desktop ? RB_UTF8_STRING_NEW2(*showing_desktop == 1 ? "ON" : "OFF") : Qnil));
@@ -695,7 +721,15 @@ static VALUE rb_wmctrl_info (VALUE self) {
695
721
  return ret;
696
722
  }
697
723
 
698
- /* Minimize windows to show desktop. */
724
+ /*
725
+ @overload showing_desktop(state)
726
+
727
+ Minimize windows to show desktop if the window manager implements "show the desktop" mode.
728
+
729
+ @param state [boolean] We set true if we want to turn on showing desktop mode.
730
+
731
+ @return [true]
732
+ */
699
733
  static VALUE rb_wmctrl_showing_desktop (VALUE self, VALUE state) {
700
734
  Display **ptr, *disp;
701
735
  Data_Get_Struct(self, Display*, ptr);
@@ -704,6 +738,16 @@ static VALUE rb_wmctrl_showing_desktop (VALUE self, VALUE state) {
704
738
  return Qtrue;
705
739
  }
706
740
 
741
+ /*
742
+ @overload change_viewport(x, y)
743
+
744
+ Change the viewport. A window manager may ignore this request.
745
+
746
+ @param x [Integer] Offset of top position
747
+ @param y [Integer] Offset of left position
748
+
749
+ @return [true]
750
+ */
707
751
  static VALUE rb_wmctrl_change_viewport (VALUE self, VALUE xnum, VALUE ynum) {
708
752
  long x, y;
709
753
  Display **ptr, *disp;
@@ -718,6 +762,16 @@ static VALUE rb_wmctrl_change_viewport (VALUE self, VALUE xnum, VALUE ynum) {
718
762
  return Qtrue;
719
763
  }
720
764
 
765
+ /*
766
+ @overload change_geometry(w, h)
767
+
768
+ Change geometry of all desktops. A window manager may ignore this request.
769
+
770
+ @param w [Ineteger] Width
771
+ @param h [Ineteger] Height
772
+
773
+ @return [true]
774
+ */
721
775
  static VALUE rb_wmctrl_change_geometry (VALUE self, VALUE xnum, VALUE ynum) {
722
776
  long x, y;
723
777
  Display **ptr, *disp;
@@ -732,7 +786,15 @@ static VALUE rb_wmctrl_change_geometry (VALUE self, VALUE xnum, VALUE ynum) {
732
786
  return Qtrue;
733
787
  }
734
788
 
735
- /* Change number of desktops. */
789
+ /*
790
+ @overload change_number_of_desktops(num)
791
+
792
+ Change number of desktops.
793
+
794
+ @param num [Integer] Number of desktops.
795
+
796
+ @return [true]
797
+ */
736
798
  static VALUE rb_wmctrl_change_number_of_desktops (VALUE self, VALUE num) {
737
799
  long n;
738
800
  Display **ptr, *disp;
@@ -1109,15 +1171,17 @@ static Window get_target_window (Display *disp, VALUE obj)
1109
1171
  }
1110
1172
 
1111
1173
  /*
1112
- call-seq:
1113
- wm.action_window(wid, cmd, *args)
1174
+ @overload action_window(wid, cmd, *args)
1114
1175
 
1115
1176
  Manage windows.
1116
1177
  @param wid Window ID
1117
1178
  @param cmd [Symbol] Symbol of command
1118
1179
  @param args [Array] Arguments for the command
1180
+
1181
+ @return [boolean] true if succeeded. Otherwise, false.
1119
1182
 
1120
1183
  @example
1184
+ wm.action_window(wid, :activate)
1121
1185
  wm.action_window(wid, :close)
1122
1186
  wm.action_window(wid, :move_resize, grav, x, y, w, h)
1123
1187
  wm.action_window(wid, :change_state, add, prop1, prop2 = nil)
@@ -1169,6 +1233,11 @@ static VALUE rb_wmctrl_action_window(int argc, VALUE *argv, VALUE self) {
1169
1233
  }
1170
1234
  }
1171
1235
 
1236
+ /*
1237
+ Get an array of _NET_SUPPORTED property.
1238
+
1239
+ @return [Array] An array of strings.
1240
+ */
1172
1241
  static VALUE rb_wmctrl_supported (VALUE self)
1173
1242
  {
1174
1243
  Atom *list;
@@ -1207,8 +1276,8 @@ void Init_wmctrl()
1207
1276
  rb_define_method(rb_wmctrl_class, "switch_desktop", rb_wmctrl_switch_desktop, 1);
1208
1277
  rb_define_method(rb_wmctrl_class, "info", rb_wmctrl_info, 0);
1209
1278
  rb_define_method(rb_wmctrl_class, "showing_desktop", rb_wmctrl_showing_desktop, 1);
1210
- rb_define_method(rb_wmctrl_class, "change_viewport", rb_wmctrl_change_viewport, 0);
1211
- rb_define_method(rb_wmctrl_class, "change_geometry", rb_wmctrl_change_geometry, 0);
1279
+ rb_define_method(rb_wmctrl_class, "change_viewport", rb_wmctrl_change_viewport, 2);
1280
+ rb_define_method(rb_wmctrl_class, "change_geometry", rb_wmctrl_change_geometry, 2);
1212
1281
  rb_define_method(rb_wmctrl_class, "change_number_of_desktops", rb_wmctrl_change_number_of_desktops, 1);
1213
1282
  rb_define_method(rb_wmctrl_class, "action_window", rb_wmctrl_action_window, -1);
1214
1283
  rb_define_method(rb_wmctrl_class, "supported", rb_wmctrl_supported, 0);
data/lib/wmctrl.rb CHANGED
@@ -1,2 +1,2 @@
1
- require 'wmctrl.so'
1
+ require 'wmctrl/wmctrl'
2
2
  require 'wmctrl/version'
@@ -1,3 +1,3 @@
1
1
  class WMCtrl
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -0,0 +1,131 @@
1
+ require 'wmctrl.so'
2
+
3
+ class WMCtrl
4
+ def self.instance
5
+ @wmctrl ||= self.new
6
+ end
7
+
8
+ class DataHash
9
+ def initialize(data_hash)
10
+ @data = data_hash
11
+ end
12
+
13
+ def method_missing(*args, &block)
14
+ @data.__send__(*args, &block)
15
+ end
16
+ end
17
+
18
+ class Desktop < DataHash
19
+ [:id, :current, :title, :geometry, :viewport, :workarea].each do |key|
20
+ define_method(key) do
21
+ self[key]
22
+ end
23
+ end
24
+
25
+ # Valid keys of the method[] are :id, :current, :title, :geometry, :viewport, and :workarea.
26
+ end
27
+
28
+ class Window < DataHash
29
+ [:id, :title, :active, :desktop, :client_machine,
30
+ :pid, :geometry, :state, :exterior_frame, :frame_extents, :strut].each do |key|
31
+ define_method(key) do
32
+ self[key]
33
+ end
34
+ end
35
+
36
+ # Because method name "class" is a basic ruby method, we use "wm_class" to get window class.
37
+ def wm_class
38
+ self[:class]
39
+ end
40
+
41
+ # @param [Symbol] key Valid keys are :class, :id, :title, :active, :desktop, :client_machine,
42
+ # :pid, :geometry, :state, :exterior_frame, :frame_extents, and :strut.
43
+ # :wm_class is an alias of :class.
44
+ def [](key)
45
+ if key == :wm_class
46
+ self.wm_class
47
+ else
48
+ super(key)
49
+ end
50
+ end
51
+
52
+ def sticky?
53
+ self[:desktop] == -1
54
+ end
55
+
56
+ def active?
57
+ self[:active]
58
+ end
59
+
60
+ def action(*args)
61
+ WMCtrl.instance.action_window(self[:id], *args)
62
+ end
63
+ private :action
64
+
65
+ def close
66
+ action(:close)
67
+ end
68
+
69
+ def change_state(*args)
70
+ action(:change_state, *args)
71
+ end
72
+
73
+ def activate
74
+ action(:activate)
75
+ end
76
+
77
+ # @param [Hash] opts Options
78
+ # @option opts [Integer] :x X coordinate
79
+ # @option opts [Integer] :y Y coordinate
80
+ # @option opts [Integer] :width Width of window
81
+ # @option opts [Integer] :height Height of window
82
+ # @option opts [Integer,:current] :desktop Desktop number
83
+ def place(opts = {})
84
+ if opts[:desktop]
85
+ if opts[:desktop] == :current
86
+ action(:move_to_current)
87
+ elsif (opts[:desktop] != self[:desktop])
88
+ action(:move_to_desktop, opts[:desktop])
89
+ end
90
+ end
91
+ x = self[:exterior_frame][0]
92
+ y = self[:exterior_frame][1]
93
+ width = self[:exterior_frame][2]
94
+ height = self[:exterior_frame][3]
95
+ extent_horizontal = self[:frame_extents][0] + self[:frame_extents][1]
96
+ extent_vertical = self[:frame_extents][2] + self[:frame_extents][3]
97
+ width = opts[:width] if opts[:width] && (opts[:width] != width)
98
+ height = opts[:height] if opts[:height] && (opts[:height] != height)
99
+ x = opts[:x] if opts[:x] && (opts[:x] != x)
100
+ y = opts[:y] if opts[:y] && (opts[:y] != y)
101
+ action(:move_resize, 0, x + self[:frame_extents][0], y + self[:frame_extents][1], width - extent_horizontal, height - extent_vertical)
102
+ end
103
+ end
104
+
105
+ # @return [Array] An array of WMCtrl::Desktop
106
+ def desktops
107
+ list_desktops.map { |hash| WMCtrl::Desktop.new(hash) }
108
+ end
109
+
110
+ # @param [Array] conditions An array of condition hash. The values of hash are tested by the method ===.
111
+ # @return [Array] An array of WMCtrl::Window
112
+ def windows(*conditions)
113
+ wins = list_windows(true).map { |hash| WMCtrl::Window.new(hash) }
114
+ unless conditions.empty?
115
+ wins_selected = []
116
+ conditions.each do |condition|
117
+ wins_rest = []
118
+ wins.each do |win|
119
+ if condition.all? { |k, v| v === win[k] }
120
+ wins_selected << win
121
+ else
122
+ wins_rest << win
123
+ end
124
+ end
125
+ wins = wins_rest
126
+ end
127
+ wins = wins_selected
128
+ end
129
+ wins
130
+ end
131
+ end
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'ext'))
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+
5
+ require 'rspec'
6
+ require 'wmctrl'
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ describe WMCtrl do
4
+ before(:all) do
5
+ @wm = WMCtrl.new
6
+ end
7
+
8
+ let :wm do
9
+ @wm
10
+ end
11
+
12
+ it "should get an array of hashes." do
13
+ wins = wm.list_windows
14
+ wins.should be_an_instance_of Array
15
+ wins.each do |w|
16
+ w.should be_an_instance_of Hash
17
+ end
18
+ end
19
+
20
+ it "should get an array of hashes." do
21
+ desktops = wm.list_desktops
22
+ desktops.should be_an_instance_of Array
23
+ desktops.each do |w|
24
+ w.should be_an_instance_of Hash
25
+ end
26
+ end
27
+
28
+ it "should get information of window manager." do
29
+ wm.info.should be_an_instance_of Hash
30
+ end
31
+
32
+ it "should get an array." do
33
+ sp = wm.supported
34
+ sp.should be_an_instance_of Array
35
+ sp.each do |prop|
36
+ prop.should be_an_instance_of String
37
+ end
38
+ end
39
+
40
+ # action_window(wid, cmd, *args)
41
+ # change_geometry(w, h)
42
+ # change_number_of_desktops(num)
43
+ # change_viewport(x, y)
44
+ # showing_desktop(state)
45
+ # switch_desktop(desktop_id)
46
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-wmctrl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,41 +9,56 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-25 00:00:00.000000000 Z
12
+ date: 2013-03-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &7241240 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ! '>='
19
+ - - '>='
20
20
  - !ruby/object:Gem::Version
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *7241240
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: yard
27
- requirement: &7240760 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
- - - ! '>='
35
+ - - '>='
31
36
  - !ruby/object:Gem::Version
32
37
  version: '0'
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *7240760
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: pkg-config
38
- requirement: &7240220 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
- - - ! '>='
51
+ - - '>='
42
52
  - !ruby/object:Gem::Version
43
53
  version: '0'
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *7240220
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
47
62
  description: Ruby bindings to control windows in EWMH and NetWM compatible X Window
48
63
  manager, which is created from source code of wmctrl command.
49
64
  email:
@@ -65,6 +80,7 @@ files:
65
80
  - ext/wmctrl.c
66
81
  - lib/wmctrl.rb
67
82
  - lib/wmctrl/version.rb
83
+ - lib/wmctrl/wmctrl.rb
68
84
  - ruby-wmctrl.gemspec
69
85
  - sample/activate.rb
70
86
  - sample/change_number_of_desktops.rb
@@ -80,6 +96,8 @@ files:
80
96
  - sample/showing_desktop.rb
81
97
  - sample/supported.rb
82
98
  - sample/switch_desktop.rb
99
+ - spec/spec_helper.rb
100
+ - spec/wmctrl_spec.rb
83
101
  homepage: ''
84
102
  licenses: []
85
103
  post_install_message:
@@ -90,19 +108,20 @@ require_paths:
90
108
  required_ruby_version: !ruby/object:Gem::Requirement
91
109
  none: false
92
110
  requirements:
93
- - - ! '>='
111
+ - - '>='
94
112
  - !ruby/object:Gem::Version
95
113
  version: '0'
96
114
  required_rubygems_version: !ruby/object:Gem::Requirement
97
115
  none: false
98
116
  requirements:
99
- - - ! '>='
117
+ - - '>='
100
118
  - !ruby/object:Gem::Version
101
119
  version: '0'
102
120
  requirements: []
103
121
  rubyforge_project: ruby-wmctrl
104
- rubygems_version: 1.8.5
122
+ rubygems_version: 1.8.25
105
123
  signing_key:
106
124
  specification_version: 3
107
125
  summary: Ruby bindings to control windows
108
126
  test_files: []
127
+ has_rdoc: