+/*
+ * Copyright © 2008, 2017 Nick Bowler
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <inttypes.h>
#include <xcb/xcb.h>
-#define MKASPECT(w, h) { (double)w/h, #w ":" #h }
-
/* Table of common monitor aspect ratios. Add to this as necessary. */
-static struct aspect {
- double ratio;
- char *name;
+static const struct aspect {
+ unsigned num, denom;
} aspects[] = {
- MKASPECT(16, 10),
- MKASPECT(16, 9),
- MKASPECT(8, 5),
- MKASPECT(5, 4),
- MKASPECT(4, 3)
+ { 16, 10 },
+ { 16, 9 },
+ { 8, 3 },
+ { 5, 4 },
+ { 4, 3 }
};
/*
return NULL;
}
-char *testaspect(xcb_screen_t *screen)
+void find_nearest_aspect(xcb_screen_t *screen, struct aspect *out)
{
unsigned int w = screen->width_in_millimeters;
unsigned int h = screen->height_in_millimeters;
- double ratio = (double)w/h;
- double diff = 0;
- char *best = NULL;
+ double r = (double)w/h;
+ double d = HUGE_VAL;
int i;
for (i = 0; i < (sizeof aspects / sizeof aspects[0]); i++) {
- if (!best || fabs(aspects[i].ratio - ratio) < diff) {
- best = aspects[i].name;
- diff = fabs(aspects[i].ratio - ratio);
+ double t = (double) aspects[i].num / aspects[i].denom;
+ double cmp;
+
+ cmp = fabs(r - t);
+ if (cmp < d) {
+ *out = aspects[i];
+ d = cmp;
+ }
+
+ cmp = fabs(r - 1/t);
+ if (cmp < d) {
+ out->num = aspects[i].denom;
+ out->denom = aspects[i].num;
+ d = cmp;
+ }
+ }
+}
+
+struct options {
+ char *displayname;
+ int showdimensions;
+} *parseoptions(int argc, char **argv)
+{
+ static struct options opts = { 0 };
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ if (++i < argc) {
+ opts.displayname = argv[i];
+ continue;
+ }
+ fprintf(stderr, "-display requires an argument\n");
+ } else if (strcmp(argv[i], "-dimensions") == 0) {
+ opts.showdimensions = 1;
}
}
- return best;
+ return &opts;
}
int main(int argc, char **argv)
{
+ struct aspect screenaspect;
xcb_connection_t *display;
xcb_screen_t *screen;
- char *dpynam = NULL;
int screen_num;
- if (argc > 2 && strcmp(argv[1], "-display") == 0)
- dpynam = argv[2];
+ struct options *opts = parseoptions(argc, argv);
- display = xcb_connect(dpynam, &screen_num);
+ display = xcb_connect(opts->displayname, &screen_num);
if (xcb_connection_has_error(display)) {
fprintf(stderr, "Failed to open display.\n");
xcb_disconnect(display);
return EXIT_FAILURE;
}
- printf("%s\n", testaspect(screen));
+ if (opts->showdimensions) {
+ printf("%" PRIu16 "x%" PRIu16 "-",
+ screen->width_in_pixels, screen->height_in_pixels);
+ }
+
+ find_nearest_aspect(screen, &screenaspect);
+ printf("%u:%u\n", screenaspect.num, screenaspect.denom);
xcb_disconnect(display);
return EXIT_SUCCESS;