-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
164 lines (148 loc) · 4.91 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
Window find_window(Display *display, Window root, const char *window_class) {
Window parent;
Window *children;
unsigned int nchildren;
XClassHint class_hint;
if (XQueryTree(display, root, &root, &parent, &children, &nchildren)) {
for (unsigned int i = 0; i < nchildren; i++) {
if (XGetClassHint(display, children[i], &class_hint)) {
if (strcmp(class_hint.res_class, window_class) == 0) {
XFree(class_hint.res_name);
XFree(class_hint.res_class);
return children[i];
}
XFree(class_hint.res_name);
XFree(class_hint.res_class);
}
}
for (unsigned int i = 0; i < nchildren; i++) {
Window found = find_window(display, children[i], window_class);
if (found) {
XFree(children);
return found;
}
}
if (children) {
XFree(children);
}
}
return 0;
}
void list_windows(Display *display, Window root) {
Window parent;
Window *children;
unsigned int nchildren;
XClassHint class_hint;
if (XQueryTree(display, root, &root, &parent, &children, &nchildren)) {
for (unsigned int i = 0; i < nchildren; i++) {
if (XGetClassHint(display, children[i], &class_hint)) {
printf("Window ID: %ld, Class: %s\n", children[i], class_hint.res_class);
XFree(class_hint.res_name);
XFree(class_hint.res_class);
}
}
for (unsigned int i = 0; i < nchildren; i++) {
list_windows(display, children[i]);
}
if (children) {
XFree(children);
}
}
}
void toggle_window(Display *display, Window window) {
XWindowAttributes attrs;
XGetWindowAttributes(display, window, &attrs);
if (attrs.map_state == IsViewable) {
XUnmapWindow(display, window);
} else {
XMapWindow(display, window);
XRaiseWindow(display, window);
XGetWindowAttributes(display, window, &attrs);
if (attrs.map_state == IsViewable) {
XSetInputFocus(display, window, RevertToParent, CurrentTime);
}
}
}
void start_process(const char *path, char *const argv[]) {
pid_t pid = fork();
if (pid == 0) {
execvp(path, argv);
perror("execvp");
exit(EXIT_FAILURE);
}
}
int find_and_toggle_windows(Display *display, Window root, const char *window_class) {
Window parent;
Window *children;
unsigned int nchildren;
XClassHint class_hint;
int found = 0;
if (XQueryTree(display, root, &root, &parent, &children, &nchildren)) {
for (unsigned int i = 0; i < nchildren; i++) {
if (XGetClassHint(display, children[i], &class_hint)) {
if (strcmp(class_hint.res_class, window_class) == 0) {
XFree(class_hint.res_name);
XFree(class_hint.res_class);
toggle_window(display, children[i]);
found = 1;
} else {
XFree(class_hint.res_name);
XFree(class_hint.res_class);
}
}
}
for (unsigned int i = 0; i < nchildren; i++) {
found |= find_and_toggle_windows(display, children[i], window_class);
}
if (children) {
XFree(children);
}
}
return found;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <window_class> [<path_to_process> [process_args...]]\n", argv[0]);
fprintf(stderr, "%s list - to get a list of windows", argv[0]);
return EXIT_FAILURE;
}
const char *window_class = argv[1];
const char *path = argv[2];
char **process_args = &argv[2];
Display *display = XOpenDisplay(NULL);
if (!display) {
fprintf(stderr, "Unable to open X display\n");
return EXIT_FAILURE;
}
if (strcmp(window_class, "list") == 0) {
list_windows(display, DefaultRootWindow(display));
XCloseDisplay(display);
return EXIT_SUCCESS;
}
if (argc < 3) {
fprintf(stderr, "Path to process is required when window_class is not 'list'\n");
XCloseDisplay(display);
return EXIT_FAILURE;
}
int found = find_and_toggle_windows(display, DefaultRootWindow(display), window_class);
if (found) {
XCloseDisplay(display);
return EXIT_SUCCESS;
} else {
if (argc < 3) {
fprintf(stderr, "No windows found and no process specified to start\n");
XCloseDisplay(display);
return EXIT_FAILURE;
}
start_process(path, process_args);
}
XCloseDisplay(display);
return EXIT_SUCCESS;
}