ruby-wmctrl 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +57 -3
- data/bin/rwmctrl +197 -0
- data/ext/wmctrl.c +11 -62
- data/lib/wmctrl/version.rb +1 -1
- metadata +11 -9
data/README.md
CHANGED
@@ -5,12 +5,66 @@ Ruby bindings to control windows in EWMH and NetWM compatible X Window manager.
|
|
5
5
|
- <http://rubygems.org/gems/ruby-wmctrl>
|
6
6
|
- <https://github.com/ytaka/ruby-wmctrl>
|
7
7
|
|
8
|
-
##
|
8
|
+
## Installation
|
9
9
|
|
10
10
|
ruby-wmctrl is a C extended library, which uses glib and x11.
|
11
11
|
For ubuntu 11.04, we should install packages.
|
12
12
|
|
13
|
-
apt-get install libx11-dev libglib2.0-dev
|
13
|
+
apt-get install libx11-dev libglib2.0-dev libxmu-dev
|
14
|
+
|
15
|
+
Then we can install ruby-wmctrl from rubygems.
|
16
|
+
|
17
|
+
gem install ruby-wmctrl
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
We load 'wmctrl' as below
|
22
|
+
|
23
|
+
require 'wmctrl'
|
24
|
+
|
25
|
+
and call methods of an instance of WMCtrl.
|
26
|
+
|
27
|
+
### List windows
|
28
|
+
|
29
|
+
require 'wmctrl'
|
30
|
+
require 'pp'
|
31
|
+
wm = WMCtrl.new
|
32
|
+
pp wm.list_windows
|
33
|
+
|
34
|
+
### Activate a window
|
35
|
+
|
36
|
+
wm.action_window(window_id, :activate)
|
37
|
+
|
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
|
41
|
+
manages the window of window ID.
|
42
|
+
The rest arguments are arguments of the action.
|
43
|
+
|
44
|
+
### Close a window
|
45
|
+
|
46
|
+
wm.action_window(window_id, :close)
|
47
|
+
|
48
|
+
### Move and resize a window
|
49
|
+
|
50
|
+
wm.action_window(window_id, :move_resize, 0, 100, 200, 500, 400)
|
51
|
+
|
52
|
+
The integers of the arguments means gravity, x coordinate, y coordinate,
|
53
|
+
width, and height, respectively. That is,
|
54
|
+
|
55
|
+
wm.action_window(window_id, :move_resize, gravity, x, y, width, height)
|
56
|
+
|
57
|
+
### Move window to a desktop
|
58
|
+
|
59
|
+
wm.action_window(window_id, :move_to_desktop, desktop_id)
|
60
|
+
|
61
|
+
### Move wndow to current desktop
|
62
|
+
|
63
|
+
wm.action_window(window_id, :move_to_current)
|
64
|
+
|
65
|
+
### List desktops
|
66
|
+
|
67
|
+
pp wm.list_desktops
|
14
68
|
|
15
69
|
## License
|
16
70
|
|
@@ -22,7 +76,7 @@ GPLv2
|
|
22
76
|
|
23
77
|
ruby-wmctrl is created from source code of wmctrl <http://sweb.cz/tripie/utils/wmctrl/>.
|
24
78
|
|
25
|
-
The copyright of
|
79
|
+
The copyright of original wmctrl:
|
26
80
|
|
27
81
|
Author, current maintainer: Tomas Styblo tripie@cpan.org
|
28
82
|
Copyright (C) 2003
|
data/bin/rwmctrl
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
4
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../ext'))
|
5
|
+
require 'wmctrl'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
help_message =<<HELP
|
9
|
+
Usage: rwmctrl [options ...]
|
10
|
+
HELP
|
11
|
+
|
12
|
+
Version = WMCtrl::VERSION
|
13
|
+
|
14
|
+
options = {}
|
15
|
+
begin
|
16
|
+
OptionParser.new(help_message) do |opt|
|
17
|
+
opt.on('-l', 'List windows.') do |v|
|
18
|
+
options[:mode] = :list_windows
|
19
|
+
end
|
20
|
+
opt.on('-p', 'Display PID of windows.') do |v|
|
21
|
+
options[:pid] = true
|
22
|
+
end
|
23
|
+
opt.on('-x', 'Display class name.') do |v|
|
24
|
+
options[:class] = true
|
25
|
+
end
|
26
|
+
opt.on('-G', 'Display geometry of windows.') do |v|
|
27
|
+
options[:geometry] = true
|
28
|
+
end
|
29
|
+
opt.on('-A', 'Mark active window.') do |v|
|
30
|
+
options[:active] = true
|
31
|
+
end
|
32
|
+
opt.on('-E', 'Display corners of exterior frame of windows.') do |v|
|
33
|
+
options[:exterior_frame] = true
|
34
|
+
end
|
35
|
+
opt.on('-e <MVARG>', String, 'Move and resize windows.') do |v|
|
36
|
+
options[:mode] = :move_resize
|
37
|
+
options[:move_resize] = v
|
38
|
+
end
|
39
|
+
opt.on('-r <WIN>', String, 'Specify target window.') do |v|
|
40
|
+
options[:target] = v
|
41
|
+
end
|
42
|
+
opt.on('-c <WIN>', String, 'Close window.') do |v|
|
43
|
+
options[:mode] = :close
|
44
|
+
options[:target] = v
|
45
|
+
end
|
46
|
+
opt.on('-d', 'List all desktops.') do |v|
|
47
|
+
options[:mode] = :desktop
|
48
|
+
end
|
49
|
+
opt.on('-m', 'Show information of window manager.') do |v|
|
50
|
+
options[:mode] = :wm_info
|
51
|
+
end
|
52
|
+
opt.on('-b STR', String, 'Change window properties. Format is (add|remove|toggle),prop1[,prop2]') do |v|
|
53
|
+
options[:mode] = :change_state
|
54
|
+
options[:change_state] = v
|
55
|
+
end
|
56
|
+
opt.on('-n N', Integer, 'Change the number of desktops.') do |v|
|
57
|
+
options[:mode] = :desktop_number
|
58
|
+
options[:desktop_number] = v
|
59
|
+
end
|
60
|
+
# Not implemented options
|
61
|
+
# '-g'
|
62
|
+
# '-I'
|
63
|
+
# '-k'
|
64
|
+
# '-N'
|
65
|
+
# '-o'
|
66
|
+
# '-R'
|
67
|
+
# '-s'
|
68
|
+
# '-t'
|
69
|
+
# '-T'
|
70
|
+
# '-w'
|
71
|
+
|
72
|
+
# '-u'
|
73
|
+
# '-v'
|
74
|
+
opt.on('-i', 'Use window ID number as window argument.') do |v|
|
75
|
+
options[:use_wid] = true
|
76
|
+
end
|
77
|
+
opt.on('-F', 'Use exact match of window title.') do |v|
|
78
|
+
option[:use_exact] = true
|
79
|
+
end
|
80
|
+
opt.on('--ignore-case', 'Ignore case to specfy target window.') do |v|
|
81
|
+
options[:ignore_case] = true
|
82
|
+
end
|
83
|
+
opt.parse!(ARGV)
|
84
|
+
end
|
85
|
+
rescue OptionParser::InvalidOption
|
86
|
+
$stderr.print <<MES
|
87
|
+
error: Invalid Option
|
88
|
+
#{help_message}
|
89
|
+
MES
|
90
|
+
exit(2)
|
91
|
+
rescue OptionParser::InvalidArgument
|
92
|
+
$stderr.print <<MES
|
93
|
+
error: Invalid Argument
|
94
|
+
#{help_message}
|
95
|
+
MES
|
96
|
+
exit(2)
|
97
|
+
end
|
98
|
+
|
99
|
+
wm = WMCtrl.new
|
100
|
+
|
101
|
+
def specify_window(wm, arg, options)
|
102
|
+
if arg == ':ACTIVE:'
|
103
|
+
wm.list_windows.find do |w|
|
104
|
+
w[:active] ? w : nil
|
105
|
+
end
|
106
|
+
elsif arg == ':SELECT:'
|
107
|
+
raise 'Not implemented.'
|
108
|
+
elsif options[:use_wid]
|
109
|
+
wid = Integer(arg)
|
110
|
+
wm.list_windows.find do |w|
|
111
|
+
wid == w[:id] ? w : nil
|
112
|
+
end
|
113
|
+
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
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
case options[:mode]
|
128
|
+
when :list_windows
|
129
|
+
windows = wm.list_windows(true)
|
130
|
+
str_class_size = windows.map { |w| w[:class].to_s.size }.max
|
131
|
+
windows.each do |win|
|
132
|
+
s = ''
|
133
|
+
if options[:active]
|
134
|
+
s << (win[:active] ? "* " : " ")
|
135
|
+
end
|
136
|
+
s << sprintf("0x%08x %2d ", win[:id], win[:desktop])
|
137
|
+
if options[:pid]
|
138
|
+
s << "%-7d" % (win[:pid] || 0)
|
139
|
+
end
|
140
|
+
if options[:geometry]
|
141
|
+
s << win[:geometry].map { |n| "%-5d" % n}.join
|
142
|
+
end
|
143
|
+
if options[:exterior_frame]
|
144
|
+
if win[:exterior_frame]
|
145
|
+
s << win[:exterior_frame].map { |n| "%-5d" % n}.join
|
146
|
+
else
|
147
|
+
s << "N/A"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
if options[:class]
|
151
|
+
s << sprintf("%*s ", -str_class_size, (win[:class] || "N/A"))
|
152
|
+
end
|
153
|
+
s << sprintf("%s %s", win[:client_machine] || "N/A", win[:title] || "N/A")
|
154
|
+
puts s
|
155
|
+
end
|
156
|
+
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
|
164
|
+
else
|
165
|
+
puts "Can not specify target window."
|
166
|
+
end
|
167
|
+
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
|
175
|
+
end
|
176
|
+
when :close
|
177
|
+
if target_win = specify_window(wm, options[:target], options)
|
178
|
+
wm.action_window(target_win[:id], :close)
|
179
|
+
end
|
180
|
+
when :desktop
|
181
|
+
wm.list_desktops.each do |dt|
|
182
|
+
printf("%d %s DG: %dx%d VP: %d,%d WA: %d,%d %dx%d %s\n",
|
183
|
+
dt[:id], dt[:current] ? '*' : '-', dt[:geometry][0], dt[:geometry][1], dt[:viewport][0], dt[:viewport][1],
|
184
|
+
dt[:workarea][0], dt[:workarea][1], dt[:workarea][2], dt[:workarea][3], dt[:title])
|
185
|
+
end
|
186
|
+
when :desktop_number
|
187
|
+
wm.change_number_of_desktops(options[:desktop_number])
|
188
|
+
when :wm_info
|
189
|
+
info = wm.info
|
190
|
+
puts "Name: #{info[:name]}"
|
191
|
+
puts "Class: #{info[:class]}"
|
192
|
+
puts "PID: #{info[:pid] ? info[:pid].to_s : "N/A"}"
|
193
|
+
puts "Window manager's \"showing the desktop\" mode: #{info[:showing_desktop]}"
|
194
|
+
else
|
195
|
+
puts "Not implemented."
|
196
|
+
exit(1)
|
197
|
+
end
|
data/ext/wmctrl.c
CHANGED
@@ -53,7 +53,7 @@ static Window get_target_window (Display *disp, VALUE obj);
|
|
53
53
|
static VALUE rb_wmctrl_class, key_id, key_title, key_pid, key_geometry,
|
54
54
|
key_active, key_class, key_client_machine, key_desktop,
|
55
55
|
key_viewport, key_workarea, key_current, key_showing_desktop, key_name,
|
56
|
-
key_state, key_frame_extents, key_strut;
|
56
|
+
key_state, key_frame_extents, key_strut, key_exterior_frame;
|
57
57
|
|
58
58
|
static ID id_select, id_active, id_activate, id_close, id_move_resize,
|
59
59
|
id_change_state, id_move_to_desktop, id_move_to_current,
|
@@ -318,7 +318,7 @@ static VALUE rb_wmctrl_list_windows (int argc, VALUE *argv, VALUE self) {
|
|
318
318
|
|
319
319
|
/* geometry */
|
320
320
|
XGetGeometry (disp, client_list[i], &junkroot, &junkx, &junky, &wwidth, &wheight, &bw, &depth);
|
321
|
-
XTranslateCoordinates (disp, client_list[i], junkroot,
|
321
|
+
XTranslateCoordinates (disp, client_list[i], junkroot, -bw, -bw, &x, &y, &junkroot);
|
322
322
|
|
323
323
|
rb_hash_aset(window_obj, key_geometry,
|
324
324
|
rb_ary_new3(4, INT2NUM(x), INT2NUM(y), INT2NUM(wwidth), INT2NUM(wheight)));
|
@@ -345,6 +345,13 @@ static VALUE rb_wmctrl_list_windows (int argc, VALUE *argv, VALUE self) {
|
|
345
345
|
for (j = 0; j < extents_size / sizeof(unsigned long); j++) {
|
346
346
|
rb_ary_push(extents_ary, ULONG2NUM(extents[j]));
|
347
347
|
}
|
348
|
+
/* exterior frame */
|
349
|
+
if (extents) {
|
350
|
+
rb_hash_aset(window_obj, key_exterior_frame,
|
351
|
+
rb_ary_new3(4, INT2NUM(x - (int)extents[0]), INT2NUM(y - (int)extents[2]),
|
352
|
+
INT2NUM(wwidth + (int)extents[0] + (int)extents[1]),
|
353
|
+
INT2NUM(wheight + (int)extents[2] + (int)extents[3])));
|
354
|
+
}
|
348
355
|
g_free(extents);
|
349
356
|
} else {
|
350
357
|
extents_ary = Qnil;
|
@@ -806,7 +813,7 @@ static int window_move_resize (Display *disp, Window win, signed long grav,
|
|
806
813
|
if (w != -1) grflags |= (1 << 10);
|
807
814
|
if (h != -1) grflags |= (1 << 11);
|
808
815
|
|
809
|
-
p_verbose("
|
816
|
+
p_verbose("move_resize: %lu %ld %ld %ld %ld\n", grflags, x, y, w, h);
|
810
817
|
|
811
818
|
if (wm_supports(disp, "_NET_MOVERESIZE_WINDOW")){
|
812
819
|
return client_msg(disp, win, "_NET_MOVERESIZE_WINDOW",
|
@@ -1101,65 +1108,6 @@ static Window get_target_window (Display *disp, VALUE obj)
|
|
1101
1108
|
return wid;
|
1102
1109
|
}
|
1103
1110
|
|
1104
|
-
/* static int action_window_str (Display *disp) { */
|
1105
|
-
/* Window activate = 0; */
|
1106
|
-
/* Window *client_list; */
|
1107
|
-
/* unsigned long client_list_size; */
|
1108
|
-
/* int i; */
|
1109
|
-
|
1110
|
-
/* if ((client_list = get_client_list(disp, &client_list_size)) != NULL) { */
|
1111
|
-
/* for (i = 0; i < client_list_size / sizeof(Window); i++) { */
|
1112
|
-
/* gchar *match_utf8; */
|
1113
|
-
/* if (options.show_class) { */
|
1114
|
-
/* match_utf8 = get_window_class(disp, client_list[i]); /\* UTF8 *\/ */
|
1115
|
-
/* } */
|
1116
|
-
/* else { */
|
1117
|
-
/* match_utf8 = get_window_title(disp, client_list[i]); /\* UTF8 *\/ */
|
1118
|
-
/* } */
|
1119
|
-
/* if (match_utf8) { */
|
1120
|
-
/* gchar *match; */
|
1121
|
-
/* gchar *match_cf; */
|
1122
|
-
/* gchar *match_utf8_cf = NULL; */
|
1123
|
-
/* if (envir_utf8) { */
|
1124
|
-
/* match = g_strdup(options.param_window); */
|
1125
|
-
/* match_cf = g_utf8_casefold(options.param_window, -1); */
|
1126
|
-
/* } */
|
1127
|
-
/* else { */
|
1128
|
-
/* if (! (match = g_locale_to_utf8(options.param_window, -1, NULL, NULL, NULL))) { */
|
1129
|
-
/* match = g_strdup(options.param_window); */
|
1130
|
-
/* } */
|
1131
|
-
/* match_cf = g_utf8_casefold(match, -1); */
|
1132
|
-
/* } */
|
1133
|
-
|
1134
|
-
/* if (!match || !match_cf) { */
|
1135
|
-
/* continue; */
|
1136
|
-
/* } */
|
1137
|
-
|
1138
|
-
/* match_utf8_cf = g_utf8_casefold(match_utf8, -1); */
|
1139
|
-
|
1140
|
-
/* if ((options.full_window_title_match && strcmp(match_utf8, match) == 0) || */
|
1141
|
-
/* (!options.full_window_title_match && strstr(match_utf8_cf, match_cf))) { */
|
1142
|
-
/* activate = client_list[i]; */
|
1143
|
-
/* g_free(match); */
|
1144
|
-
/* g_free(match_cf); */
|
1145
|
-
/* g_free(match_utf8); */
|
1146
|
-
/* g_free(match_utf8_cf); */
|
1147
|
-
/* break; */
|
1148
|
-
/* } */
|
1149
|
-
/* g_free(match); */
|
1150
|
-
/* g_free(match_cf); */
|
1151
|
-
/* g_free(match_utf8); */
|
1152
|
-
/* g_free(match_utf8_cf); */
|
1153
|
-
/* } */
|
1154
|
-
/* g_free(client_list); */
|
1155
|
-
/* if (activate) { */
|
1156
|
-
/* break; */
|
1157
|
-
/* } */
|
1158
|
-
/* } */
|
1159
|
-
/* } */
|
1160
|
-
/* return activate; */
|
1161
|
-
/* } */
|
1162
|
-
|
1163
1111
|
/*
|
1164
1112
|
call-seq:
|
1165
1113
|
wm.action_window(wid, cmd, *args)
|
@@ -1281,6 +1229,7 @@ void Init_wmctrl()
|
|
1281
1229
|
key_state = ID2SYM(rb_intern("state"));
|
1282
1230
|
key_frame_extents = ID2SYM(rb_intern("frame_extents"));
|
1283
1231
|
key_strut = ID2SYM(rb_intern("strut"));
|
1232
|
+
key_exterior_frame = ID2SYM(rb_intern("exterior_frame"));
|
1284
1233
|
|
1285
1234
|
id_active = rb_intern("active");
|
1286
1235
|
id_select = rb_intern("select");
|
data/lib/wmctrl/version.rb
CHANGED
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
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-09-
|
12
|
+
date: 2011-09-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &7241240 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *7241240
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: yard
|
27
|
-
requirement: &
|
27
|
+
requirement: &7240760 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *7240760
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: pkg-config
|
38
|
-
requirement: &
|
38
|
+
requirement: &7240220 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,12 +43,13 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *7240220
|
47
47
|
description: Ruby bindings to control windows in EWMH and NetWM compatible X Window
|
48
48
|
manager, which is created from source code of wmctrl command.
|
49
49
|
email:
|
50
50
|
- d@ytak.info
|
51
|
-
executables:
|
51
|
+
executables:
|
52
|
+
- rwmctrl
|
52
53
|
extensions:
|
53
54
|
- ext/extconf.rb
|
54
55
|
extra_rdoc_files: []
|
@@ -59,6 +60,7 @@ files:
|
|
59
60
|
- Gemfile
|
60
61
|
- README.md
|
61
62
|
- Rakefile
|
63
|
+
- bin/rwmctrl
|
62
64
|
- ext/extconf.rb
|
63
65
|
- ext/wmctrl.c
|
64
66
|
- lib/wmctrl.rb
|