]> git.draconx.ca Git - fvwmconf.git/blob - scripts/C/xaspect.c
3e07caac52727d80b63c5cce18d7e6bd8a83aad8
[fvwmconf.git] / scripts / C / xaspect.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <inttypes.h>
6 #include <xcb/xcb.h>
7
8 #define MKASPECT(w, h) { (double)w/h, #w ":" #h }
9
10 /* Table of common monitor aspect ratios.  Add to this as necessary. */
11 static struct aspect {
12         double ratio;
13         char *name;
14 } aspects[] = {
15         MKASPECT(16, 10),
16         MKASPECT(16, 9),
17         MKASPECT(8, 3),
18         MKASPECT(5, 4),
19         MKASPECT(4, 3)
20 };
21
22 /*
23  * Get the xcb screen structure for the specified screen, or NULL if it doesn't
24  * exist.
25  */
26 static xcb_screen_t *getscreen(xcb_connection_t *c, int screen)
27 {
28         xcb_screen_iterator_t iter;
29
30         iter = xcb_setup_roots_iterator(xcb_get_setup(c));
31         while (iter.rem) {
32                 if (screen == 0)
33                         return iter.data;
34                 screen--;
35                 xcb_screen_next(&iter);
36         }
37
38         return NULL;
39 }
40
41 char *testaspect(xcb_screen_t *screen)
42 {
43         unsigned int w = screen->width_in_millimeters;
44         unsigned int h = screen->height_in_millimeters;
45
46         double ratio = (double)w/h;
47         double diff = 0;
48         char *best = NULL;
49         int i;
50
51         for (i = 0; i < (sizeof aspects / sizeof aspects[0]); i++) {
52                 if (!best || fabs(aspects[i].ratio - ratio) < diff) {
53                         best = aspects[i].name;
54                         diff = fabs(aspects[i].ratio - ratio);
55                 }
56         }
57
58         return best;
59 }
60
61 struct options {
62         char *displayname;
63         int showdimensions;
64 } *parseoptions(int argc, char **argv)
65 {
66         static struct options opts = { 0 };
67         int i;
68
69         for (i = 1; i < argc; i++) {
70                 if (strcmp(argv[i], "-display") == 0) {
71                         if (++i < argc) {
72                                 opts.displayname = argv[i];
73                                 continue;
74                         }
75                         fprintf(stderr, "-display requires an argument\n");
76                 } else if (strcmp(argv[i], "-dimensions") == 0) {
77                         opts.showdimensions = 1;
78                 }
79         }
80
81         return &opts;
82 }
83
84 int main(int argc, char **argv)
85 {
86         xcb_connection_t *display;
87         xcb_screen_t     *screen;
88         int screen_num;
89
90         struct options *opts = parseoptions(argc, argv);
91         
92         display = xcb_connect(opts->displayname, &screen_num);
93         if (xcb_connection_has_error(display)) {
94                 fprintf(stderr, "Failed to open display.\n");
95                 xcb_disconnect(display);
96                 return EXIT_FAILURE;
97         }
98
99         screen = getscreen(display, screen_num);
100         if (!screen) {
101                 fprintf(stderr, "Invalid screen number.\n");
102                 xcb_disconnect(display);
103                 return EXIT_FAILURE;
104         }
105
106         if (opts->showdimensions) {
107                 printf("%" PRIu16 "x%" PRIu16 "-",
108                        screen->width_in_pixels, screen->height_in_pixels);
109         }
110         printf("%s\n", testaspect(screen));
111
112         xcb_disconnect(display);
113         return EXIT_SUCCESS;
114 }