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