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