ruby-wmctrl 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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: