]> git.tdb.fi Git - geometrycompositor.git/blobdiff - source/control.c
Implement a control interface using properties on the root window
[geometrycompositor.git] / source / control.c
diff --git a/source/control.c b/source/control.c
new file mode 100644 (file)
index 0000000..ae47c9e
--- /dev/null
@@ -0,0 +1,172 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+typedef struct GeometryCorrection
+{
+       char *monitor_name;
+       float keystone_vertical;
+       float cylinder_depth;
+       float vertical_center;
+       float perspective;
+} GeometryCorrection;
+
+GeometryCorrection *get_corrections(Display *display)
+{
+       Window root;
+       Atom monitors_atom;
+       Atom correction_atom;
+       Atom prop_type;
+       int prop_format;
+       unsigned long overflow;
+       unsigned long names_length;
+       char *names;
+       unsigned long values_length;
+       short *values;
+       unsigned ncorrections;
+       unsigned i;
+       GeometryCorrection *corrections;
+       char *name_ptr;
+
+       root = DefaultRootWindow(display);
+       monitors_atom = XInternAtom(display, "GEOMETRY_CORRECTION_MONITORS", False);
+       correction_atom = XInternAtom(display, "GEOMETRY_CORRECTION", False);
+
+       XGetWindowProperty(display, root, monitors_atom, 0, 64, False, XA_STRING,
+               &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
+       if(prop_type!=XA_STRING || prop_format!=8)
+               return NULL;
+
+       XGetWindowProperty(display, root, correction_atom, 0, 64, False, XA_INTEGER,
+               &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
+       if(prop_type!=XA_INTEGER || prop_format!=16)
+       {
+               XFree(names);
+               return NULL;
+       }
+
+       ncorrections = 0;
+       for(i=0; i<names_length; ++i)
+               if(!names[i])
+                       ++ncorrections;
+       if(ncorrections*4>values_length)
+               ncorrections = values_length/4;
+       corrections = (GeometryCorrection *)malloc((ncorrections+1)*sizeof(GeometryCorrection));
+
+       name_ptr = names;
+       for(i=0; i<ncorrections; ++i)
+       {
+               unsigned namelen;
+
+               namelen = strlen(name_ptr);
+               corrections[i].monitor_name = (char *)malloc(namelen+1);
+               strcpy(corrections[i].monitor_name, name_ptr);
+
+               corrections[i].keystone_vertical = values[i*4]/10000.0f;
+               corrections[i].cylinder_depth = values[i*4+1]/10000.0f;
+               corrections[i].vertical_center = values[i*4+2]/10000.0f;
+               corrections[i].perspective = values[i*4+3]/10000.0f;
+
+               name_ptr += namelen+1;
+       }
+
+       corrections[ncorrections].monitor_name = NULL;
+
+       XFree(names);
+       XFree(values);
+
+       return corrections;
+}
+
+void set_corrections(Display *display, GeometryCorrection *corrections)
+{
+       unsigned ncorrections;
+       unsigned total_len;
+       unsigned i;
+       char *names;
+       char *name_ptr;
+       short *values;
+       Window root;
+       Atom monitors_atom;
+       Atom correction_atom;
+
+       ncorrections = 0;
+       total_len = 0;
+       for(i=0; corrections[i].monitor_name; ++i)
+       {
+               ++ncorrections;
+               total_len += strlen(corrections[i].monitor_name);
+       }
+
+       names = (char *)malloc(total_len+ncorrections);
+       values = (short *)malloc(ncorrections*4*sizeof(short));
+       name_ptr = names;
+       for(i=0; i<ncorrections; ++i)
+       {
+               strcpy(name_ptr, corrections[i].monitor_name);
+               name_ptr += strlen(name_ptr)+1;
+
+               values[i*4] = corrections[i].keystone_vertical*10000;
+               values[i*4+1] = corrections[i].cylinder_depth*10000;
+               values[i*4+2] = corrections[i].vertical_center*10000;
+               values[i*4+3] = corrections[i].perspective*10000;
+       }
+
+       root = DefaultRootWindow(display);
+       monitors_atom = XInternAtom(display, "GEOMETRY_CORRECTION_MONITORS", False);
+       correction_atom = XInternAtom(display, "GEOMETRY_CORRECTION", False);
+       XChangeProperty(display, root, monitors_atom, XA_STRING, 8, PropModeReplace, (unsigned char *)names, total_len+ncorrections-1);
+       XChangeProperty(display, root, correction_atom, XA_INTEGER, 16, PropModeReplace, (unsigned char *)values, ncorrections*4);
+
+       free(names);
+       free(values);
+}
+
+int main(int argc, char **argv)
+{
+       Display *display;
+       GeometryCorrection *corrections;
+       unsigned i;
+
+       if(argc!=6)
+       {
+               fprintf(stderr, "Usage: %s <monitor> <keystone> <cylinder> <vcenter> <perspective>\n", argv[0]);
+               return 1;
+       }
+
+       display = XOpenDisplay(NULL);
+
+       corrections = get_corrections(display);
+       if(corrections)
+       {
+               for(i=0; corrections[i].monitor_name; ++i)
+                       if(!strcmp(corrections[i].monitor_name, argv[1]))
+                               break;
+       }
+       else
+               i = 0;
+
+       if(!corrections || !corrections[i].monitor_name)
+       {
+               unsigned namelen;
+
+               corrections = (GeometryCorrection *)realloc(corrections, (i+2)*sizeof(GeometryCorrection));
+               namelen = strlen(argv[1]);
+               corrections[i].monitor_name = (char *)malloc(namelen+1);
+               strcpy(corrections[i].monitor_name, argv[1]);
+               corrections[i+1].monitor_name = NULL;
+       }
+
+       corrections[i].keystone_vertical = strtod(argv[2], NULL);
+       corrections[i].cylinder_depth = strtod(argv[3], NULL);
+       corrections[i].vertical_center = strtod(argv[4], NULL);
+       corrections[i].perspective = strtod(argv[5], NULL);
+
+       set_corrections(display, corrections);
+
+       XCloseDisplay(display);
+
+       return 0;
+}