aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/xlib.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/xlib.c b/src/xlib.c
new file mode 100644
index 0000000..e781835
--- /dev/null
+++ b/src/xlib.c
@@ -0,0 +1,179 @@
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+
+#include "meh.h"
+
+/* Globals */
+Display *display;
+int screen;
+Window window;
+GC gc;
+
+static unsigned int getshift(unsigned int mask){
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+ return __builtin_ctz(mask);
+#else
+ int i = 0;
+ while((mask & 1) == 0){
+ i++;
+ mask >>= 1;
+ }
+ return i;
+#endif
+}
+
+XImage *ximage(struct image *img, int width, int height) {
+ int depth;
+ XImage *ximg = NULL;
+ Visual *vis;
+ unsigned int rshift, gshift, bshift;
+ int i;
+ int x,y;
+
+ depth = DefaultDepth(display, screen);
+ vis = DefaultVisual(display, screen);
+
+ rshift = getshift(vis->red_mask);
+ gshift = getshift(vis->green_mask);
+ bshift = getshift(vis->blue_mask);
+
+ if (depth >= 24) {
+ unsigned int dx;
+ size_t numNewBufBytes = (4 * width * height);
+ u_int32_t *newBuf = malloc(numNewBufBytes);
+
+ dx = 1024 * img->width / width;
+ for(y = 0; y < height; y++){
+ i = (y * img->height / height * img->width) * 1024;
+ for(x = 0; x < width; x++){
+ unsigned int r, g, b;
+ r = (img->buf[(i >> 10)*3] << rshift) & vis->red_mask;
+ g = (img->buf[(i >> 10)*3+1] << gshift) & vis->green_mask;
+ b = (img->buf[(i >> 10)*3+2] << bshift) & vis->blue_mask;
+
+ newBuf[y * width + x] = r | g | b;
+ i += dx;
+ }
+ }
+
+ ximg = XCreateImage (display,
+ CopyFromParent, depth,
+ ZPixmap, 0,
+ (char *) newBuf,
+ width, height,
+ 32, 0
+ );
+ }else if(depth >= 15){
+ unsigned int dx;
+ size_t numNewBufBytes = (2 * width * height);
+ u_int16_t *newBuf = malloc (numNewBufBytes);
+
+ dx = 1024 * img->width / width;
+ for(y = 0; y < height; y++){
+ i = (y * img->height / height * img->width) * 1024;
+ for(x = 0; x < width; x++){
+ unsigned int r, g, b;
+ r = (img->buf[i++] << rshift) & vis->red_mask;
+ g = (img->buf[i++] << gshift) & vis->green_mask;
+ b = (img->buf[i++] << bshift) & vis->blue_mask;
+
+ newBuf[y * width + x] = r | g | b;
+ i += dx;
+ }
+ }
+
+ ximg = XCreateImage(display,
+ CopyFromParent, depth,
+ ZPixmap, 0,
+ (char *) newBuf,
+ width, height,
+ 16, 0
+ );
+ }else{
+ fprintf(stderr, "This program does not support displays with a depth less than 15.\n");
+ exit(1);
+ return NULL;
+ }
+
+ XInitImage(ximg);
+
+ return ximg;
+}
+
+
+void drawimage(struct image *img, int width, int height){
+ static struct image *lastimg = NULL;
+ static int lastwidth = 0, lastheight = 0;
+ static XImage *ximg = NULL;
+ if(img == lastimg && width == lastwidth && height == lastheight){
+ }else{
+ if(ximg)
+ XDestroyImage(ximg);
+ lastwidth = width;
+ lastheight = height;
+ lastimg = img;
+ if(width * img->height > height * img->width){
+ ximg = ximage(img, img->width * height / img->height, height);
+ }else{
+ ximg = ximage(img, width, img->height * width / img->width);
+ }
+ }
+ assert(ximg);
+ {
+ XRectangle rects[2];
+ int yoffset, xoffset;
+ xoffset = (width - ximg->width) / 2;
+ yoffset = (height - ximg->height) / 2;
+ if(xoffset || yoffset){
+ rects[0].x = rects[0].y = 0;
+ if(xoffset){
+ rects[0].width = rects[1].width = xoffset;
+ rects[0].height = rects[1].height = height;
+ rects[1].x = width-xoffset;
+ rects[1].y = 0;
+ }else if(yoffset){
+ rects[0].width = rects[1].width = width;
+ rects[0].height = rects[1].height = yoffset;
+ rects[1].x = 0;
+ rects[1].y = height - yoffset;
+ }
+ XFillRectangles(display, window, gc, rects, 2);
+ }
+ XPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->height);
+ XFlush(display);
+ }
+}
+
+
+void setaspect(int w, int h){
+ XSizeHints *hints = XAllocSizeHints();
+ hints->flags = PAspect;
+ hints->min_aspect.x = hints->max_aspect.x = w;
+ hints->min_aspect.y = hints->max_aspect.y = h;
+ XSetWMNormalHints(display, window, hints);
+ XFlush(display);
+ XFree(hints);
+}
+
+void xinit(){
+ display = XOpenDisplay (NULL);
+ assert(display);
+ screen = DefaultScreen(display);
+
+ window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 640, 480, 0, DefaultDepth(display, screen), InputOutput, CopyFromParent, 0, NULL);
+ setaspect(1, 1);
+ gc = XCreateGC(display, window, 0, NULL);
+
+ XMapRaised(display, window);
+ XSelectInput(display, window, StructureNotifyMask | ExposureMask | KeyPressMask);
+ XFlush(display);
+}
+
+
+