1 #include "xdo_cmd.h"
2 #include <string.h>
3
cmd_search(context_t * context)4 int cmd_search(context_t *context) {
5 Window *list = NULL;
6 xdo_search_t search;
7 unsigned int nwindows;
8 unsigned int i;
9 int c;
10 int op_sync = False;
11
12 int search_title = 0;
13 int search_name = 0;
14 int out_shell = 0;
15 char out_prefix[17] = {'\0'};
16 int search_class = 0;
17 int search_classname = 0;
18 int search_role = 0;
19 enum {
20 opt_unused, opt_title, opt_onlyvisible, opt_name, opt_shell, opt_prefix, opt_class, opt_maxdepth,
21 opt_pid, opt_help, opt_any, opt_all, opt_screen, opt_classname, opt_desktop,
22 opt_limit, opt_sync, opt_role
23 };
24 struct option longopts[] = {
25 { "all", no_argument, NULL, opt_all },
26 { "any", no_argument, NULL, opt_any },
27 { "class", no_argument, NULL, opt_class },
28 { "classname", no_argument, NULL, opt_classname },
29 { "help", no_argument, NULL, opt_help },
30 { "maxdepth", required_argument, NULL, opt_maxdepth },
31 { "name", no_argument, NULL, opt_name },
32 { "shell", no_argument, NULL, opt_shell },
33 { "prefix", required_argument, NULL, opt_prefix },
34 { "onlyvisible", 0, NULL, opt_onlyvisible },
35 { "pid", required_argument, NULL, opt_pid },
36 { "screen", required_argument, NULL, opt_screen },
37 { "title", no_argument, NULL, opt_title },
38 { "desktop", required_argument, NULL, opt_desktop },
39 { "limit", required_argument, NULL, opt_limit },
40 { "sync", no_argument, NULL, opt_sync },
41 { "role", no_argument, NULL, opt_role },
42 { 0, 0, 0, 0 },
43 };
44 static const char *usage =
45 "Usage: xdotool %s "
46 "[options] regexp_pattern\n"
47 "--class check regexp_pattern against the window class\n"
48 "--classname check regexp_pattern against the window classname\n"
49 "--role check regexp_pattern against the window role\n"
50 "--maxdepth N set search depth to N. Default is infinite.\n"
51 " -1 also means infinite.\n"
52 "--onlyvisible matches only windows currently visible\n"
53 "--pid PID only show windows belonging to specific process\n"
54 " Not supported by all X11 applications\n"
55 "--screen N only search a specific screen. Default is all screens\n"
56 "--desktop N only search a specific desktop number\n"
57 "--limit N break search after N results\n"
58 "--name check regexp_pattern against the window name\n"
59 "--shell print results as shell array WINDOWS=( ... )\n"
60 "--prefix STR use prefix (max 16 chars) for array name STRWINDOWS\n"
61 "--title DEPRECATED. Same as --name.\n"
62 "--all Require all conditions match a window. Default is --any\n"
63 "--any Windows matching any condition will be reported\n"
64 "--sync Wait until a search result is found.\n"
65 "-h, --help show this help output\n"
66 "\n"
67 "If none of --name, --classname, --class, or --role are specified, the \n"
68 "defaults are: --name --classname --class --role\n";
69
70 memset(&search, 0, sizeof(xdo_search_t));
71 search.max_depth = -1;
72 search.require = SEARCH_ANY;
73
74 char *cmd = *context->argv;
75 int option_index;
76
77 while ((c = getopt_long_only(context->argc, context->argv, "+h",
78 longopts, &option_index)) != -1) {
79 switch (c) {
80 case 0:
81 break;
82 case 'h':
83 case opt_help:
84 printf(usage, cmd);
85 consume_args(context, context->argc);
86 return EXIT_SUCCESS;
87 case opt_maxdepth:
88 search.max_depth = strtol(optarg, NULL, 0);
89 break;
90 case opt_pid:
91 search.pid = atoi(optarg);
92 search.searchmask |= SEARCH_PID;
93 break;
94 case opt_any:
95 search.require = SEARCH_ANY;
96 break;
97 case opt_all:
98 search.require = SEARCH_ALL;
99 break;
100 case opt_screen:
101 search.screen = strtoul(optarg, NULL, 0);
102 search.searchmask |= SEARCH_SCREEN;
103 break;
104 case opt_onlyvisible:
105 search.only_visible = True;
106 search.searchmask |= SEARCH_ONLYVISIBLE;
107 break;
108 case opt_class:
109 search_class = True;
110 break;
111 case opt_classname:
112 search_classname = True;
113 break;
114 case opt_role:
115 search_role = True;
116 break;
117 case opt_title:
118 fprintf(stderr, "This flag is deprecated. Assuming you mean --name (the"
119 " window name).\n");
120 /* fall through */
121 case opt_name:
122 search_name = True;
123 break;
124 case opt_shell:
125 out_shell = True;
126 break;
127 case opt_prefix:
128 strncpy(out_prefix, optarg, sizeof(out_prefix)-1);
129 out_prefix[ sizeof(out_prefix)-1 ] = '\0'; //just in case
130 break;
131 case opt_desktop:
132 search.desktop = strtol(optarg, NULL, 0);
133 search.searchmask |= SEARCH_DESKTOP;
134 break;
135 case opt_limit:
136 search.limit = atoi(optarg);
137 break;
138 case opt_sync:
139 op_sync = True;
140 break;
141 default:
142 fprintf(stderr, "Invalid usage\n");
143 fprintf(stderr, usage, cmd);
144 return EXIT_FAILURE;
145 }
146 }
147
148 consume_args(context, optind);
149
150 /* We require a pattern or a pid to search for */
151 if (context->argc < 1 && search.pid == 0) {
152 fprintf(stderr, usage, cmd);
153 return EXIT_FAILURE;
154 }
155
156 if (context->argc > 0) {
157 if (!search_title && !search_name && !search_class && !search_classname
158 && !search_role) {
159 fprintf(stderr,
160 "Defaulting to search window name, class, classname, and role\n");
161 search.searchmask |= (SEARCH_NAME | SEARCH_CLASS | SEARCH_CLASSNAME
162 | SEARCH_ROLE);
163 search_name = 1;
164 search_class = 1;
165 search_classname = 1;
166 search_role = 1;
167 }
168
169 if (search_title) {
170 search.searchmask |= SEARCH_NAME;
171 search.winname = context->argv[0];
172 }
173 if (search_name) {
174 search.searchmask |= SEARCH_NAME;
175 search.winname = context->argv[0];
176 }
177 if (search_class) {
178 search.searchmask |= SEARCH_CLASS;
179 search.winclass = context->argv[0];
180 }
181 if (search_classname) {
182 search.searchmask |= SEARCH_CLASSNAME;
183 search.winclassname = context->argv[0];
184 }
185 if (search_role) {
186 search.searchmask |= SEARCH_ROLE;
187 search.winrole = context->argv[0];
188 }
189 consume_args(context, 1);
190 }
191
192 do {
193 if (list != NULL) {
194 free(list);
195 }
196
197 xdo_search_windows(context->xdo, &search, &list, &nwindows);
198
199 if ( (context->argc == 0) || out_shell ) {
200 /* only print if we're the last command or printing to shell*/
201 if (out_shell) printf("%s%s", out_prefix, "WINDOWS=(");
202 for (i = 0; i < nwindows; i++) {
203 window_print(list[i]);
204 }
205 if (out_shell) printf("%s",")\n");
206 }
207
208 if (op_sync && nwindows == 0) {
209 xdotool_debug(context, "No search results, still waiting...");
210
211 /* TODO(sissel): Make this tunable */
212 usleep(500000);
213 }
214 } while (op_sync && nwindows == 0);
215
216 /* Free old list as it's malloc'd by xdo_search_windows */
217 if (context->windows != NULL) {
218 free(context->windows);
219 }
220 context->windows = list;
221 context->nwindows = nwindows;
222
223 /* error if number of windows found is zero (behave like grep)
224 but return success when being used inside eval (--shell option)*/
225 return (nwindows || out_shell ? EXIT_SUCCESS : EXIT_FAILURE);
226 }
227