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