ruby-wmctrl 0.0.6 → 0.0.7
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.
- checksums.yaml +5 -5
- data/ext/extconf.rb +2 -1
- data/ext/wmctrl.c +188 -171
- data/lib/wmctrl/version.rb +1 -1
- data/lib/wmctrl/wmctrl.rb +59 -7
- data/spec/wmctrl_spec.rb +7 -7
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 64b85024233d08a600bd914867fcf4e3250aa4c21e8ec45eb7bf31644c3a317c
|
4
|
+
data.tar.gz: d42e156ef9c64fd3b43664b3cc4738295528541c12cae7dd7d4897c34e9496e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b83996d39afbf0b47c6b964673f0a147ac6dc10d49670f3dfac051092fb45684e9e114ec07378034e443b04c539fff7bb7cc564773484efc8931dc771b8e134b
|
7
|
+
data.tar.gz: 412805d6b06f93ba5fad169dc2192204cdfcbb410778c1459421a11c6d3d5891d9f6aab9507f265d96abd4342af2f8603ff6959936448794ad8d56e954e734f7
|
data/ext/extconf.rb
CHANGED
@@ -8,6 +8,7 @@ $CFLAGS << " " << glib.cflags
|
|
8
8
|
$libs << " " << glib.libs
|
9
9
|
|
10
10
|
dir_config("X11")
|
11
|
-
if have_header('X11/Xlib.h') && have_library('X11')
|
11
|
+
if have_header('X11/Xlib.h') && have_library('X11') &&
|
12
|
+
have_header('X11/Xmu/WinUtil.h') && have_library('Xmu')
|
12
13
|
create_makefile("wmctrl")
|
13
14
|
end
|
data/ext/wmctrl.c
CHANGED
@@ -35,16 +35,13 @@ static gchar *get_property (Display *disp, Window win,
|
|
35
35
|
static Window *get_client_list (Display *disp, unsigned long *size);
|
36
36
|
static gchar *get_window_class (Display *disp, Window win);
|
37
37
|
static gchar *get_window_title (Display *disp, Window win);
|
38
|
-
static
|
39
|
-
static
|
38
|
+
static VALUE activate_window (Display *disp, Window win, gboolean switch_desktop);
|
39
|
+
static VALUE close_window (Display *disp, Window win);
|
40
40
|
static gboolean wm_supports (Display *disp, const gchar *prop);
|
41
|
-
static
|
42
|
-
|
43
|
-
static int window_state (Display *disp, Window win,
|
44
|
-
const char *action_str, const char *prop1_str, const char *prop2_str);
|
41
|
+
static VALUE window_move_resize (Display *disp, Window win, signed long grav, signed long x, signed long y, signed long w, signed long h);
|
42
|
+
static VALUE change_window_state (Display *disp, Window win, const char *action_str, const char *prop1_str, const char *prop2_str);
|
45
43
|
static int window_to_desktop (Display *disp, Window win, int desktop);
|
46
|
-
static
|
47
|
-
static int action_window (Display *disp, Window win, char mode, int argc, VALUE *argv);
|
44
|
+
static VALUE window_set_title (Display *disp, Window win, char *title, ID sym_id);
|
48
45
|
static Window Select_Window(Display *dpy);
|
49
46
|
static Window get_active_window(Display *disp);
|
50
47
|
static Window get_target_window (Display *disp, VALUE obj);
|
@@ -53,7 +50,7 @@ static Window get_target_window (Display *disp, VALUE obj);
|
|
53
50
|
static VALUE rb_wmctrl_class, key_id, key_title, key_pid, key_geometry,
|
54
51
|
key_active, key_class, key_client_machine, key_desktop,
|
55
52
|
key_viewport, key_workarea, key_current, key_showing_desktop, key_name,
|
56
|
-
key_state, key_frame_extents, key_strut, key_exterior_frame;
|
53
|
+
key_state, key_window_type, key_frame_extents, key_strut, key_exterior_frame;
|
57
54
|
|
58
55
|
static ID id_select, id_active, id_activate, id_close, id_move_resize,
|
59
56
|
id_change_state, id_move_to_desktop, id_move_to_current,
|
@@ -283,6 +280,10 @@ static VALUE get_window_hash_data (Window win, Display *disp, Window window_acti
|
|
283
280
|
Atom *window_state;
|
284
281
|
gchar *state_name;
|
285
282
|
VALUE state_ary;
|
283
|
+
unsigned long window_type_size;
|
284
|
+
Atom *window_type;
|
285
|
+
gchar *window_type_name;
|
286
|
+
VALUE window_type_ary;
|
286
287
|
Atom *extents;
|
287
288
|
unsigned long extents_size;
|
288
289
|
VALUE extents_ary;
|
@@ -317,6 +318,21 @@ static VALUE get_window_hash_data (Window win, Display *disp, Window window_acti
|
|
317
318
|
}
|
318
319
|
rb_hash_aset(window_obj, key_state, state_ary);
|
319
320
|
|
321
|
+
/* window type */
|
322
|
+
if ((window_type = (Atom *)get_property(disp, win,
|
323
|
+
XA_ATOM, "_NET_WM_WINDOW_TYPE", &window_type_size)) != NULL) {
|
324
|
+
window_type_ary = rb_ary_new();
|
325
|
+
for (j = 0; j < window_type_size / sizeof(Atom); j++) {
|
326
|
+
window_type_name = XGetAtomName(disp, window_type[j]);
|
327
|
+
rb_ary_push(window_type_ary, rb_str_new2(window_type_name));
|
328
|
+
g_free(window_type_name);
|
329
|
+
}
|
330
|
+
g_free(window_type);
|
331
|
+
} else {
|
332
|
+
window_type_ary = Qnil;
|
333
|
+
}
|
334
|
+
rb_hash_aset(window_obj, key_window_type, window_type_ary);
|
335
|
+
|
320
336
|
/* frame extents */
|
321
337
|
if ((extents = (unsigned long *)get_property(disp, win,
|
322
338
|
XA_CARDINAL, "_NET_FRAME_EXTENTS", &extents_size)) != NULL) {
|
@@ -828,7 +844,7 @@ static VALUE rb_wmctrl_change_number_of_desktops (VALUE self, VALUE num) {
|
|
828
844
|
return Qtrue;
|
829
845
|
}
|
830
846
|
|
831
|
-
static
|
847
|
+
static VALUE activate_window (Display *disp, Window win, gboolean switch_desktop)
|
832
848
|
{
|
833
849
|
unsigned long *desktop;
|
834
850
|
|
@@ -853,12 +869,15 @@ static int activate_window (Display *disp, Window win, gboolean switch_desktop)
|
|
853
869
|
client_msg(disp, win, "_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0);
|
854
870
|
XMapRaised(disp, win);
|
855
871
|
|
856
|
-
return
|
872
|
+
return Qtrue;
|
857
873
|
}
|
858
874
|
|
859
|
-
static
|
875
|
+
static VALUE close_window (Display *disp, Window win)
|
860
876
|
{
|
861
|
-
|
877
|
+
if (client_msg(disp, win, "_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0)) {
|
878
|
+
return Qtrue;
|
879
|
+
}
|
880
|
+
return Qfalse;
|
862
881
|
}
|
863
882
|
|
864
883
|
static gboolean wm_supports (Display *disp, const gchar *prop)
|
@@ -885,39 +904,42 @@ static gboolean wm_supports (Display *disp, const gchar *prop)
|
|
885
904
|
return FALSE;
|
886
905
|
}
|
887
906
|
|
888
|
-
static
|
889
|
-
signed long x, signed long y, signed long w, signed long h)
|
907
|
+
static VALUE window_move_resize (Display *disp, Window win, signed long grav, signed long x, signed long y, signed long w, signed long h)
|
890
908
|
{
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
909
|
+
p_verbose("move_resize: %lu %ld %ld %ld %ld\n", grav, x, y, w, h);
|
910
|
+
if ((grav >= 0) && wm_supports(disp, "_NET_MOVERESIZE_WINDOW")) {
|
911
|
+
unsigned long grflags;
|
912
|
+
grflags = grav;
|
913
|
+
if (x != -1) {
|
914
|
+
grflags |= (1 << 8);
|
915
|
+
}
|
916
|
+
if (y != -1) {
|
917
|
+
grflags |= (1 << 9);
|
918
|
+
}
|
919
|
+
if (w != -1) {
|
920
|
+
grflags |= (1 << 10);
|
921
|
+
}
|
922
|
+
if (h != -1) {
|
923
|
+
grflags |= (1 << 11);
|
924
|
+
}
|
925
|
+
if (client_msg(disp, win, "_NET_MOVERESIZE_WINDOW", grflags, (unsigned long) x, (unsigned long) y, (unsigned long) w, (unsigned long) h)) {
|
926
|
+
return Qtrue;
|
927
|
+
}
|
928
|
+
return Qfalse;
|
929
|
+
} else {
|
905
930
|
p_verbose("WM doesn't support _NET_MOVERESIZE_WINDOW. Gravity will be ignored.\n");
|
906
931
|
if ((w < 1 || h < 1) && (x >= 0 && y >= 0)) {
|
907
932
|
XMoveWindow(disp, win, x, y);
|
908
|
-
}
|
909
|
-
else if ((x < 0 || y < 0) && (w >= 1 && h >= -1)) {
|
933
|
+
} else if ((x < 0 || y < 0) && (w >= 1 && h >= -1)) {
|
910
934
|
XResizeWindow(disp, win, w, h);
|
911
|
-
}
|
912
|
-
else if (x >= 0 && y >= 0 && w >= 1 && h >= 1) {
|
935
|
+
} else if (x >= 0 && y >= 0 && w >= 1 && h >= 1) {
|
913
936
|
XMoveResizeWindow(disp, win, x, y, w, h);
|
914
937
|
}
|
915
|
-
return
|
938
|
+
return Qtrue;
|
916
939
|
}
|
917
940
|
}
|
918
941
|
|
919
|
-
static
|
920
|
-
const char *action_str, const char *prop1_str, const char *prop2_str)
|
942
|
+
static VALUE change_window_state (Display *disp, Window win, const char *action_str, const char *prop1_str, const char *prop2_str)
|
921
943
|
{
|
922
944
|
unsigned long action;
|
923
945
|
Atom prop1 = 0;
|
@@ -927,14 +949,11 @@ static int window_state (Display *disp, Window win,
|
|
927
949
|
/* action */
|
928
950
|
if (strcmp(action_str, "remove") == 0) {
|
929
951
|
action = _NET_WM_STATE_REMOVE;
|
930
|
-
}
|
931
|
-
else if (strcmp(action_str, "add") == 0) {
|
952
|
+
} else if (strcmp(action_str, "add") == 0) {
|
932
953
|
action = _NET_WM_STATE_ADD;
|
933
|
-
}
|
934
|
-
else if (strcmp(action_str, "toggle") == 0) {
|
954
|
+
} else if (strcmp(action_str, "toggle") == 0) {
|
935
955
|
action = _NET_WM_STATE_TOGGLE;
|
936
|
-
}
|
937
|
-
else {
|
956
|
+
} else {
|
938
957
|
rb_raise(rb_eArgError, "Invalid action. Use either remove, add or toggle.");
|
939
958
|
}
|
940
959
|
|
@@ -953,7 +972,10 @@ static int window_state (Display *disp, Window win,
|
|
953
972
|
g_free(tmp2);
|
954
973
|
g_free(tmp_prop2);
|
955
974
|
}
|
956
|
-
|
975
|
+
if (client_msg(disp, win, "_NET_WM_STATE", action, (unsigned long) prop1, (unsigned long) prop2, 0, 0)) {
|
976
|
+
return Qtrue;
|
977
|
+
}
|
978
|
+
return Qnil;
|
957
979
|
}
|
958
980
|
|
959
981
|
static int window_to_desktop (Display *disp, Window win, int desktop)
|
@@ -979,7 +1001,7 @@ static int window_to_desktop (Display *disp, Window win, int desktop)
|
|
979
1001
|
return client_msg(disp, win, "_NET_WM_DESKTOP", (unsigned long)desktop, 0, 0, 0, 0);
|
980
1002
|
}
|
981
1003
|
|
982
|
-
static
|
1004
|
+
static VALUE window_set_title (Display *disp, Window win, char *title, ID sym_id)
|
983
1005
|
{
|
984
1006
|
gchar *title_utf8;
|
985
1007
|
gchar *title_local;
|
@@ -987,109 +1009,38 @@ static void window_set_title (Display *disp, Window win, char *title, char mode)
|
|
987
1009
|
if (envir_utf8) {
|
988
1010
|
title_utf8 = g_strdup(title);
|
989
1011
|
title_local = NULL;
|
990
|
-
}
|
991
|
-
|
992
|
-
if (! (title_utf8 = g_locale_to_utf8(title, -1, NULL, NULL, NULL))) {
|
1012
|
+
} else {
|
1013
|
+
if (!(title_utf8 = g_locale_to_utf8(title, -1, NULL, NULL, NULL))) {
|
993
1014
|
title_utf8 = g_strdup(title);
|
994
1015
|
}
|
995
1016
|
title_local = g_strdup(title);
|
996
1017
|
}
|
997
1018
|
|
998
|
-
if (
|
1019
|
+
if ((sym_id == id_set_title_both) || (sym_id == id_set_title_long)) {
|
999
1020
|
/* set name */
|
1000
1021
|
if (title_local) {
|
1001
|
-
XChangeProperty(disp, win, XA_WM_NAME, XA_STRING, 8, PropModeReplace,
|
1002
|
-
|
1003
|
-
}
|
1004
|
-
else {
|
1022
|
+
XChangeProperty(disp, win, XA_WM_NAME, XA_STRING, 8, PropModeReplace, (const unsigned char *) title_local, strlen(title_local));
|
1023
|
+
} else {
|
1005
1024
|
XDeleteProperty(disp, win, XA_WM_NAME);
|
1006
1025
|
}
|
1007
|
-
XChangeProperty(disp, win, XInternAtom(disp, "_NET_WM_NAME", False),
|
1008
|
-
XInternAtom(disp, "UTF8_STRING", False), 8, PropModeReplace,
|
1009
|
-
(const unsigned char *)title_utf8, strlen(title_utf8));
|
1026
|
+
XChangeProperty(disp, win, XInternAtom(disp, "_NET_WM_NAME", False), XInternAtom(disp, "UTF8_STRING", False), 8, PropModeReplace, (const unsigned char *) title_utf8, strlen(title_utf8));
|
1010
1027
|
}
|
1011
1028
|
|
1012
|
-
if (
|
1029
|
+
if ((sym_id == id_set_title_both) || (sym_id == id_set_title_short)) {
|
1013
1030
|
/* set icon name */
|
1014
1031
|
if (title_local) {
|
1015
|
-
XChangeProperty(disp, win, XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace,
|
1016
|
-
|
1017
|
-
}
|
1018
|
-
else {
|
1032
|
+
XChangeProperty(disp, win, XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace, (const unsigned char *) title_local, strlen(title_local));
|
1033
|
+
} else {
|
1019
1034
|
XDeleteProperty(disp, win, XA_WM_ICON_NAME);
|
1020
1035
|
}
|
1021
|
-
XChangeProperty(disp, win, XInternAtom(disp, "_NET_WM_ICON_NAME", False),
|
1022
|
-
XInternAtom(disp, "UTF8_STRING", False), 8, PropModeReplace,
|
1023
|
-
(const unsigned char *)title_utf8, strlen(title_utf8));
|
1036
|
+
XChangeProperty(disp, win, XInternAtom(disp, "_NET_WM_ICON_NAME", False), XInternAtom(disp, "UTF8_STRING", False), 8, PropModeReplace, (const unsigned char *) title_utf8, strlen(title_utf8));
|
1024
1037
|
}
|
1025
1038
|
|
1026
1039
|
g_free(title_utf8);
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
static int action_window (Display *disp, Window win, char mode, int argc, VALUE *argv)
|
1031
|
-
{
|
1032
|
-
p_verbose("Using window: 0x%.8lx\n", win);
|
1033
|
-
switch (mode) {
|
1034
|
-
case 'a':
|
1035
|
-
if (argc == 0) {
|
1036
|
-
return activate_window(disp, win, TRUE);
|
1037
|
-
}
|
1038
|
-
case 'c':
|
1039
|
-
if (argc == 0) {
|
1040
|
-
return close_window(disp, win);
|
1041
|
-
}
|
1042
|
-
case 'e':
|
1043
|
-
/* resize/move the window around the desktop => -r -e */
|
1044
|
-
if (argc == 5) {
|
1045
|
-
int grav, x, y, w, h;
|
1046
|
-
grav = FIX2INT(argv[0]);
|
1047
|
-
x = FIX2INT(argv[1]);
|
1048
|
-
y = FIX2INT(argv[2]);
|
1049
|
-
w = FIX2INT(argv[3]);
|
1050
|
-
h = FIX2INT(argv[4]);
|
1051
|
-
if (grav >= 0) {
|
1052
|
-
return window_move_resize(disp, win, grav, x, y, w, h);
|
1053
|
-
}
|
1054
|
-
}
|
1055
|
-
break;
|
1056
|
-
case 'b':
|
1057
|
-
/* change state of a window => -r -b */
|
1058
|
-
if (argc == 2 || argc == 3) {
|
1059
|
-
const char *action, *prop1, *prop2;
|
1060
|
-
action = StringValuePtr(argv[0]);
|
1061
|
-
prop1 = StringValuePtr(argv[1]);
|
1062
|
-
if (argc == 3) {
|
1063
|
-
prop2 = StringValuePtr(argv[2]);
|
1064
|
-
} else {
|
1065
|
-
prop2 = NULL;
|
1066
|
-
}
|
1067
|
-
return window_state(disp, win, action, prop1, prop2);
|
1068
|
-
}
|
1069
|
-
case 't':
|
1070
|
-
/* move the window to the specified desktop => -r -t */
|
1071
|
-
if (argc == 1) {
|
1072
|
-
return window_to_desktop(disp, win, FIX2INT(argv[0]));
|
1073
|
-
}
|
1074
|
-
case 'R':
|
1075
|
-
/* move the window to the current desktop and activate it => -r */
|
1076
|
-
if (argc == 0) {
|
1077
|
-
if (window_to_desktop(disp, win, -1)) {
|
1078
|
-
usleep(100000); /* 100 ms - make sure the WM has enough
|
1079
|
-
time to move the window, before we activate it */
|
1080
|
-
return activate_window(disp, win, FALSE);
|
1081
|
-
}
|
1082
|
-
else {
|
1083
|
-
return False;
|
1084
|
-
}
|
1085
|
-
}
|
1086
|
-
case 'N': case 'I': case 'T':
|
1087
|
-
if (argc == 1) {
|
1088
|
-
window_set_title(disp, win, StringValuePtr(argv[0]), mode);
|
1089
|
-
return True;
|
1090
|
-
}
|
1040
|
+
if (title_local) {
|
1041
|
+
g_free(title_local);
|
1091
1042
|
}
|
1092
|
-
|
1043
|
+
return Qtrue;
|
1093
1044
|
}
|
1094
1045
|
|
1095
1046
|
static Window Select_Window(Display *dpy)
|
@@ -1191,31 +1142,63 @@ static Window get_target_window (Display *disp, VALUE obj)
|
|
1191
1142
|
}
|
1192
1143
|
|
1193
1144
|
/*
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
@
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
@
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1145
|
+
Manage a window.
|
1146
|
+
@overload action_window(wid, :activate)
|
1147
|
+
Activate a window.
|
1148
|
+
@param [Integer] wid Window ID
|
1149
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1150
|
+
@overload action_window(wid, :close)
|
1151
|
+
Close a window
|
1152
|
+
@param [Integer] wid Window ID
|
1153
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1154
|
+
@overload action_window(wid, :move_resize, grav, x, y, w, h)
|
1155
|
+
@param [Integer] wid Window ID
|
1156
|
+
@param [Integer] grav Gravity
|
1157
|
+
@param [Integer] x X coordinate
|
1158
|
+
@param [Integer] y Y coordinate
|
1159
|
+
@param [Integer] w Width
|
1160
|
+
@param [Integer] h Height
|
1161
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1162
|
+
@overload action_window(wid, :change_state, "add", prop1, prop2 = nil)
|
1163
|
+
@param [Integer] wid Window ID
|
1164
|
+
@param [String] prop1 String of _NET_WM_STATE type.
|
1165
|
+
@param [String] prop2 String of _NET_WM_STATE type.
|
1166
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1167
|
+
@overload action_window(wid, :change_state, "remove", prop1, prop2 = nil)
|
1168
|
+
@param [Integer] wid Window ID
|
1169
|
+
@param [String] prop1 String of _NET_WM_STATE type.
|
1170
|
+
@param [String] prop2 String of _NET_WM_STATE type.
|
1171
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1172
|
+
@overload action_window(wid, :change_state, "toggle", prop1, prop2 = nil)
|
1173
|
+
@param [Integer] wid Window ID
|
1174
|
+
@param [String] prop1 String of _NET_WM_STATE type.
|
1175
|
+
@param [String] prop2 String of _NET_WM_STATE type.
|
1176
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1177
|
+
@overload action_window(wid, :move_to_desktop, desktop_id)
|
1178
|
+
@param [Integer] wid Window ID
|
1179
|
+
@param [Integer] desktop_id Desktop ID
|
1180
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1181
|
+
@overload action_window(wid, :move_to_current)
|
1182
|
+
@param [Integer] wid Window ID
|
1183
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1184
|
+
@overload action_window(wid, :set_title_long, str)
|
1185
|
+
@param [Integer] wid Window ID
|
1186
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1187
|
+
@overload action_window(wid, :set_title_short, str)
|
1188
|
+
@param [Integer] wid Window ID
|
1189
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1190
|
+
@overload action_window(wid, :set_title_both, str)
|
1191
|
+
@param [Integer] wid Window ID
|
1192
|
+
@return [boolean] true if succeeded. Otherwise, false.
|
1193
|
+
|
1194
|
+
@note
|
1195
|
+
The arguments of prop1 and prop2 for :change_state command are strings
|
1196
|
+
that mean type of _NET_WM_STATE.
|
1197
|
+
For example, For example, we use "modal" or "MODAL" for _NET_WM_STATE_MODAL.
|
1198
|
+
See also http://standards.freedesktop.org/wm-spec/wm-spec-latest.html
|
1215
1199
|
*/
|
1216
1200
|
static VALUE rb_wmctrl_action_window(int argc, VALUE *argv, VALUE self) {
|
1217
|
-
Window
|
1218
|
-
int mode;
|
1201
|
+
Window win;
|
1219
1202
|
ID sym_id;
|
1220
1203
|
Display **ptr, *disp;
|
1221
1204
|
Data_Get_Struct(self, Display*, ptr);
|
@@ -1223,34 +1206,67 @@ static VALUE rb_wmctrl_action_window(int argc, VALUE *argv, VALUE self) {
|
|
1223
1206
|
if (argc < 2) {
|
1224
1207
|
rb_raise(rb_eArgError, "Need more than one argument.");
|
1225
1208
|
}
|
1226
|
-
|
1209
|
+
win = get_target_window(disp, argv[0]);
|
1227
1210
|
sym_id = SYM2ID(argv[1]);
|
1211
|
+
argc = argc - 2;
|
1212
|
+
argv = argv + 2;
|
1213
|
+
p_verbose("Using window: 0x%.8lx\n", win);
|
1228
1214
|
if (sym_id == id_activate) {
|
1229
|
-
|
1215
|
+
if (argc == 0) {
|
1216
|
+
return activate_window(disp, win, TRUE);
|
1217
|
+
}
|
1230
1218
|
} else if (sym_id == id_close) {
|
1231
|
-
|
1219
|
+
if (argc == 0) {
|
1220
|
+
return close_window(disp, win);
|
1221
|
+
}
|
1232
1222
|
} else if (sym_id == id_move_resize) {
|
1233
|
-
|
1223
|
+
/* resize/move the window around the desktop => -r -e */
|
1224
|
+
if (argc == 5) {
|
1225
|
+
int grav, x, y, w, h;
|
1226
|
+
grav = FIX2INT(argv[0]);
|
1227
|
+
x = FIX2INT(argv[1]);
|
1228
|
+
y = FIX2INT(argv[2]);
|
1229
|
+
w = FIX2INT(argv[3]);
|
1230
|
+
h = FIX2INT(argv[4]);
|
1231
|
+
return window_move_resize(disp, win, grav, x, y, w, h);
|
1232
|
+
}
|
1234
1233
|
} else if (sym_id == id_change_state) {
|
1235
|
-
|
1234
|
+
/* change state of a window => -r -b */
|
1235
|
+
if (argc == 2 || argc == 3) {
|
1236
|
+
const char *action, *prop1, *prop2;
|
1237
|
+
action = StringValuePtr(argv[0]);
|
1238
|
+
prop1 = StringValuePtr(argv[1]);
|
1239
|
+
if (argc == 3) {
|
1240
|
+
prop2 = StringValuePtr(argv[2]);
|
1241
|
+
} else {
|
1242
|
+
prop2 = NULL;
|
1243
|
+
}
|
1244
|
+
return change_window_state(disp, win, action, prop1, prop2);
|
1245
|
+
}
|
1236
1246
|
} else if (sym_id == id_move_to_desktop) {
|
1237
|
-
|
1247
|
+
/* move the window to the specified desktop => -r -t */
|
1248
|
+
if (argc == 1) {
|
1249
|
+
if (window_to_desktop(disp, win, FIX2INT(argv[0]))) {
|
1250
|
+
return Qtrue;
|
1251
|
+
}
|
1252
|
+
return Qfalse;
|
1253
|
+
}
|
1238
1254
|
} else if (sym_id == id_move_to_current) {
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
}
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
return Qfalse;
|
1255
|
+
/* move the window to the current desktop and activate it => -r */
|
1256
|
+
if (argc == 0) {
|
1257
|
+
if (window_to_desktop(disp, win, -1)) {
|
1258
|
+
usleep(100000);
|
1259
|
+
/* 100 ms - make sure the WM has enough time to move the window, before we activate it */
|
1260
|
+
return activate_window(disp, win, FALSE);
|
1261
|
+
}
|
1262
|
+
return Qfalse;
|
1263
|
+
}
|
1264
|
+
} else if (sym_id == id_set_title_long || sym_id == id_set_title_short || sym_id == id_set_title_both) {
|
1265
|
+
if (argc == 1) {
|
1266
|
+
return window_set_title(disp, win, StringValuePtr(argv[0]), sym_id);
|
1267
|
+
}
|
1253
1268
|
}
|
1269
|
+
rb_raise(rb_eStandardError, "Invalid argument of action_window.");
|
1254
1270
|
}
|
1255
1271
|
|
1256
1272
|
/*
|
@@ -1317,6 +1333,7 @@ void Init_wmctrl()
|
|
1317
1333
|
key_showing_desktop = ID2SYM(rb_intern("showing_desktop"));
|
1318
1334
|
key_name = ID2SYM(rb_intern("name"));
|
1319
1335
|
key_state = ID2SYM(rb_intern("state"));
|
1336
|
+
key_window_type = ID2SYM(rb_intern("window_type"));
|
1320
1337
|
key_frame_extents = ID2SYM(rb_intern("frame_extents"));
|
1321
1338
|
key_strut = ID2SYM(rb_intern("strut"));
|
1322
1339
|
key_exterior_frame = ID2SYM(rb_intern("exterior_frame"));
|
data/lib/wmctrl/version.rb
CHANGED
data/lib/wmctrl/wmctrl.rb
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
require 'wmctrl.so'
|
2
2
|
|
3
3
|
class WMCtrl
|
4
|
+
NOT_USE_NET_MOVERESIZE_WINDOW = -1
|
5
|
+
GRAVITY_DEFAULT = 0
|
6
|
+
GRAVITY_NORTH_WEST = 1
|
7
|
+
GRAVITY_NORTH = 2
|
8
|
+
GRAVITY_NORTH_EAST = 3
|
9
|
+
GRAVITY_WEST = 4
|
10
|
+
GRAVITY_CENTER = 5
|
11
|
+
GRAVITY_EAST = 6
|
12
|
+
GRAVITY_SOUTH_WEST = 7
|
13
|
+
GRAVITY_SOUTH = 8
|
14
|
+
GRAVITY_SOUTH_EAST = 9
|
15
|
+
GRAVITY_STATIC = 10
|
16
|
+
|
4
17
|
def self.instance
|
5
18
|
@wmctrl ||= self.new
|
6
19
|
end
|
@@ -85,10 +98,36 @@ class WMCtrl
|
|
85
98
|
self[:active]
|
86
99
|
end
|
87
100
|
|
88
|
-
STATE_FULLSCREEN = "_NET_WM_STATE_FULLSCREEN"
|
89
|
-
|
90
101
|
def fullscreen?
|
91
|
-
self[:state].include?(
|
102
|
+
self[:state].include?("_NET_WM_STATE_FULLSCREEN")
|
103
|
+
end
|
104
|
+
|
105
|
+
def modal?
|
106
|
+
self[:state].include?("_NET_WM_STATE_MODAL")
|
107
|
+
end
|
108
|
+
|
109
|
+
def maximized_vertically?
|
110
|
+
self[:state].include?("_NET_WM_STATE_MAXIMIZED_VERT")
|
111
|
+
end
|
112
|
+
|
113
|
+
def maximized_horizontally?
|
114
|
+
self[:state].include?("_NET_WM_STATE_MAXIMIZED_HORZ")
|
115
|
+
end
|
116
|
+
|
117
|
+
def shaded?
|
118
|
+
self[:state].include?("_NET_WM_STATE_SHADED")
|
119
|
+
end
|
120
|
+
|
121
|
+
def hidden?
|
122
|
+
self[:state].include?("_NET_WM_STATE_HIDDEN")
|
123
|
+
end
|
124
|
+
|
125
|
+
def skipped_by_taskbar?
|
126
|
+
self[:state].include?("_NET_WM_STATE_SKIP_TASKBAR")
|
127
|
+
end
|
128
|
+
|
129
|
+
def skipped_by_pager?
|
130
|
+
self[:state].include?("_NET_WM_STATE_SKIP_PAGER")
|
92
131
|
end
|
93
132
|
|
94
133
|
def action(*args)
|
@@ -116,6 +155,9 @@ class WMCtrl
|
|
116
155
|
# @option opts [Integer] :width Width of window
|
117
156
|
# @option opts [Integer] :height Height of window
|
118
157
|
# @option opts [Integer,:current] :desktop Desktop number
|
158
|
+
# @option opts [Integer] :gravity Number meaning gravity: NOT_USE_NET_MOVERESIZE_WINDOW,
|
159
|
+
# GRAVITY_DEFAULT, GRAVITY_NORTH_WEST, GRAVITY_NORTH, GRAVITY_NORTH_EAST, GRAVITY_WEST, GRAVITY_CENTER,
|
160
|
+
# GRAVITY_EAST, GRAVITY_SOUTH_WEST, GRAVITY_SOUTH, GRAVITY_SOUTH_EAST, GRAVITY_STATIC
|
119
161
|
def place(opts = {})
|
120
162
|
if opts[:desktop]
|
121
163
|
if opts[:desktop] == :current
|
@@ -124,6 +166,7 @@ class WMCtrl
|
|
124
166
|
action(:move_to_desktop, opts[:desktop])
|
125
167
|
end
|
126
168
|
end
|
169
|
+
gravity = opts[:gravity] || GRAVITY_DEFAULT
|
127
170
|
x = self[:exterior_frame][0]
|
128
171
|
y = self[:exterior_frame][1]
|
129
172
|
width = self[:exterior_frame][2]
|
@@ -134,7 +177,7 @@ class WMCtrl
|
|
134
177
|
height = opts[:height] if opts[:height] && (opts[:height] != height)
|
135
178
|
x = opts[:x] if opts[:x] && (opts[:x] != x)
|
136
179
|
y = opts[:y] if opts[:y] && (opts[:y] != y)
|
137
|
-
action(:move_resize,
|
180
|
+
action(:move_resize, gravity, x + self[:frame_extents][0], y + self[:frame_extents][1], width - extent_horizontal, height - extent_vertical)
|
138
181
|
end
|
139
182
|
|
140
183
|
def position
|
@@ -148,9 +191,15 @@ class WMCtrl
|
|
148
191
|
list_desktops.map { |hash| WMCtrl::Desktop.new(hash) }
|
149
192
|
end
|
150
193
|
|
151
|
-
# @param [Array] conditions An array of condition hash.
|
152
|
-
#
|
153
|
-
|
194
|
+
# @param [Array] conditions An array of condition hash.
|
195
|
+
# The keys of the hash are keys of WMCtrl::Window#[].
|
196
|
+
# The values of the hash are tested by the method ===.
|
197
|
+
# Keys of each condition are combined by logical product and
|
198
|
+
# all conditions are combined by logical sum.
|
199
|
+
# @yield [WMCtrl::Window] Test window by block
|
200
|
+
# @return [Array] An array of WMCtrl::Window including windows
|
201
|
+
# matched by the conditions and the block.
|
202
|
+
def windows(*conditions, &block)
|
154
203
|
wins = list_windows(true).map { |hash| WMCtrl::Window.new(hash) }
|
155
204
|
unless conditions.empty?
|
156
205
|
wins_selected = []
|
@@ -167,6 +216,9 @@ class WMCtrl
|
|
167
216
|
end
|
168
217
|
wins = wins_selected
|
169
218
|
end
|
219
|
+
if block_given?
|
220
|
+
wins.delete_if { |win| !yield(win) }
|
221
|
+
end
|
170
222
|
wins
|
171
223
|
end
|
172
224
|
end
|
data/spec/wmctrl_spec.rb
CHANGED
@@ -11,29 +11,29 @@ describe WMCtrl do
|
|
11
11
|
|
12
12
|
it "should get an array of hashes." do
|
13
13
|
wins = wm.list_windows
|
14
|
-
wins.
|
14
|
+
expect(wins).to be_an_instance_of Array
|
15
15
|
wins.each do |w|
|
16
|
-
w.
|
16
|
+
expect(w).to be_an_instance_of Hash
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should get an array of hashes." do
|
21
21
|
desktops = wm.list_desktops
|
22
|
-
desktops.
|
22
|
+
expect(desktops).to be_an_instance_of Array
|
23
23
|
desktops.each do |w|
|
24
|
-
w.
|
24
|
+
expect(w).to be_an_instance_of Hash
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
it "should get information of window manager." do
|
29
|
-
wm.info.
|
29
|
+
expect(wm.info).to be_an_instance_of Hash
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should get an array." do
|
33
33
|
sp = wm.supported
|
34
|
-
sp.
|
34
|
+
expect(sp).to be_an_instance_of Array
|
35
35
|
sp.each do |prop|
|
36
|
-
prop.
|
36
|
+
expect(prop).to be_an_instance_of String
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takayuki YAMAGUCHI
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -112,9 +112,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
112
|
version: '0'
|
113
113
|
requirements: []
|
114
114
|
rubyforge_project:
|
115
|
-
rubygems_version: 2.
|
115
|
+
rubygems_version: 2.7.3
|
116
116
|
signing_key:
|
117
117
|
specification_version: 4
|
118
118
|
summary: Ruby bindings to control windows
|
119
119
|
test_files: []
|
120
|
-
has_rdoc:
|