]> git.donarmstrong.com Git - deb_pkgs/autorandr.git/blob - contrib/autorandr_launcher/autorandr_launcher.c
Add --default default
[deb_pkgs/autorandr.git] / contrib / autorandr_launcher / autorandr_launcher.c
1 #include <signal.h>
2 #include <xcb/xcb.h>
3 #include <xcb/randr.h>
4 #include <getopt.h>
5 #include <unistd.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <ctype.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
12 #include <time.h>
13
14 // indent -kr -i8
15 static int VERBOSE = 0;
16 extern char **environ;
17
18 static void sigterm_handler(int signum)
19 {
20         signal(signum, SIG_DFL);
21         kill(getpid(), signum);
22 }
23
24 static void ar_log(const char *format, ...)
25 {
26         va_list args;
27
28         if (!VERBOSE)
29                 return;
30         va_start(args, format);
31         vprintf(format, args);
32         va_end(args);
33         fflush(stdout);
34 }
35
36 static int ar_launch()
37 {
38         pid_t pid = fork();
39         if (pid == 0) {
40                 static char *argv[] =
41                     { "/usr/bin/autorandr", "--change", "--default", "default", NULL };
42                 execve(argv[0], argv, environ);
43                 exit(127);
44         } else {
45                 waitpid(pid, 0, 0);
46         }
47         return 0;
48 }
49
50 int main(int argc, char **argv)
51 {
52         int help = 0;
53         int version = 0;
54         int daemonize = 0;
55
56         const struct option long_options[] = {
57                 { "help", no_argument, &help, 1 },
58                 { "daemonize", no_argument, &daemonize, 1 },
59                 { "version", no_argument, &version, 1 },
60                 { "verbose", no_argument, &VERBOSE, 1 },
61         };
62         static const char *short_options = "hd";
63
64         const char *help_str =
65             "Usage: autorandr_launcher [OPTION]\n"
66             "\n"
67             "Listens to X server screen change events and launches autorandr after an event occurs.\n"
68             "\n"
69             "\t-h,--help\t\t\tDisplay this help and exit\n"
70             "\t-d, --daemonize\t\t\tDaemonize program\n"
71             "\t--verbose\t\t\tOutput debugging information (prevents daemonizing)\n"
72             "\t--version\t\t\tDisplay version and exit\n";
73         const char *version_str = "v.5\n";
74
75         int option_index = 0;
76         int ch = 0;
77         while (ch != -1) {
78                 ch = getopt_long(argc, argv, short_options, long_options,
79                                  &option_index);
80                 switch (ch) {
81                 case 'h':
82                         help = 1;
83                         break;
84                 case 'd':
85                         daemonize = 1;
86                         break;
87                 }
88
89         }
90
91         if (help == 1) {
92                 printf("%s", help_str);
93                 exit(0);
94         }
95         if (version == 1) {
96                 printf("%s", version_str);
97                 exit(0);
98         }
99         // Check for already running daemon?
100
101         // Daemonize
102         if (daemonize == 1 && VERBOSE != 1) {
103                 struct sigaction sa;
104                 sa.sa_handler = sigterm_handler;
105                 sigemptyset(&sa.sa_mask);
106                 sa.sa_flags = 0;
107                 sigaction(SIGINT, &sa, NULL);
108                 sigaction(SIGTERM, &sa, NULL);
109                 sigaction(SIGQUIT, &sa, NULL);
110                 signal(SIGHUP, SIG_IGN);
111                 daemon(0, 0);
112         }
113
114         int screenNum;
115         xcb_connection_t *c = xcb_connect(NULL, &screenNum);
116         int conn_error = xcb_connection_has_error(c);
117         if (conn_error) {
118                 fprintf(stderr, "Connection error!\n");
119                 exit(conn_error);
120         }
121         // Get the screen whose number is screenNum
122         const xcb_setup_t *setup = xcb_get_setup(c);
123         xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
124
125         // we want the screen at index screenNum of the iterator
126         for (int i = 0; i < screenNum; ++i) {
127                 xcb_screen_next(&iter);
128         }
129         xcb_screen_t *default_screen = iter.data;
130         ar_log("Connected to server\n");
131
132         // Subscribe to screen change events
133         xcb_randr_select_input(c, default_screen->root,
134                                XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
135         xcb_flush(c);
136
137         xcb_timestamp_t last_timestamp = (xcb_timestamp_t) 0;
138         time_t last_time = time(NULL);
139         while (1) {
140
141                 ar_log("Waiting for event\n");
142                 xcb_generic_event_t *evt = xcb_wait_for_event(c);
143                 // ar_log("Event type: %" PRIu8 "\n", evt->response_type);
144                 // ar_log("screen change masked: %" PRIu8 "\n",
145                 //       evt->response_type &
146                 //       XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
147
148                 if (evt->response_type &
149                     XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE) {
150                         xcb_randr_screen_change_notify_event_t *randr_evt =
151                             (xcb_randr_screen_change_notify_event_t *) evt;
152                         time_t evt_time = time(NULL);
153                         if ((randr_evt->timestamp > last_timestamp)
154                             && (evt_time > last_time + 1)) {
155                                 ar_log("Launch autorandr!\n");
156                                 ar_launch();
157                                 last_time = evt_time;
158                                 last_timestamp = randr_evt->timestamp;
159                         }
160                 }
161
162                 free(evt);
163         }
164
165 }