ruby-wmctrl 0.0.3 → 0.0.4
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 +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
|