--- /dev/null
+#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;
+}
#include <signal.h>
#include <math.h>
#include <X11/Xlib.h>
+#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/shape.h>
typedef struct CompositedMonitor
{
+ char *name;
int enabled;
int x;
int y;
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
+ Atom correction_atom;
+ Atom monitors_atom;
int dirty;
} Compositor;
{
CompositedMonitor *monitor;
XRROutputInfo *output;
+ int namelen;
XRRCrtcInfo *crtc;
unsigned buffers[2];
unsigned stride;
monitor = &screen->monitors[index];
output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
+ namelen = strlen(output->name);
+ monitor->name = (char *)malloc(namelen+1);
+ strcpy(monitor->name, output->name);
monitor->enabled = !!output->crtc;
if(!monitor->enabled)
{
return 1;
}
+CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
+{
+ unsigned i;
+
+ for(i=0; i<screen->nmonitors; ++i)
+ if(!strcmp(screen->monitors[i].name, name))
+ return &screen->monitors[i];
+
+ return NULL;
+}
+
+void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
+{
+ Atom prop_type;
+ int prop_format;
+ unsigned long overflow;
+ unsigned long names_length;
+ char *names;
+ unsigned long values_length;
+ short *values;
+ char *name_ptr;
+ unsigned i;
+
+ XGetWindowProperty(compositor->display, screen->root, compositor->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;
+
+ XGetWindowProperty(compositor->display, screen->root, compositor->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;
+ }
+
+ use_gl(compositor, screen);
+
+ name_ptr = names;
+ for(i=0; i*4<values_length; ++i)
+ {
+ CompositedMonitor *monitor;
+
+ if(name_ptr>=names+names_length)
+ break;
+
+ monitor = find_monitor_by_name(screen, name_ptr);
+ if(monitor)
+ {
+ monitor->keystone_vertical = values[i*4]/10000.0f;
+ monitor->cylinder_depth = values[i*4+1]/10000.0f;
+ monitor->vertical_center = values[i*4+2]/10000.0f;
+ monitor->perspective = values[i*4+3]/10000.0f;
+
+ update_monitor_vertices(screen, monitor);
+ }
+
+ name_ptr += strlen(name_ptr)+1;
+ }
+
+ XFree(names);
+ XFree(values);
+}
+
int initialize_screen(Compositor *compositor, unsigned number)
{
CompositedScreen *screen;
return with_error("GLX_EXT_texture_from_pixmap is required");
screen->root = RootWindow(compositor->display, screen->number);
- XSelectInput(compositor->display, screen->root, SubstructureNotifyMask);
+ XSelectInput(compositor->display, screen->root, SubstructureNotifyMask|PropertyChangeMask);
screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
return 0;
XRRFreeScreenResources(xrr_res);
+ update_geometry_correction(compositor, screen);
+
XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
+ compositor->correction_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION", False);
+ compositor->monitors_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION_MONITORS", False);
+
compositor->nscreens = ScreenCount(compositor->display);
compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
for(i=0; i<compositor->nscreens; ++i)
}
for(i=0; i<screen->nmonitors; ++i)
+ {
+ free(screen->monitors[i].name);
if(screen->monitors[i].enabled)
{
glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
glDeleteBuffers(1, &screen->monitors[i].index_buffer);
glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
}
+ }
glDeleteBuffers(1, &screen->window_vertex_buffer);
glDeleteVertexArrays(1, &screen->window_vertex_array);
mark_dirty(compositor, screen);
}
+void process_property_event(Compositor *compositor, XPropertyEvent *event)
+{
+ CompositedScreen *screen;
+
+ if(event->atom!=compositor->correction_atom)
+ return;
+
+ screen = find_screen_by_root(compositor, event->window);
+ if(!screen)
+ return;
+
+ update_geometry_correction(compositor, screen);
+}
+
void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
{
CompositedScreen *screen;
case ConfigureNotify:
process_configure_event(compositor, &event.xconfigure);
break;
+ case PropertyNotify:
+ process_property_event(compositor, &event.xproperty);
+ break;
default:
if(event.type==compositor->damage_event+XDamageNotify)
process_damage_event(compositor, (XDamageNotifyEvent *)&event);