summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2013-01-18 16:44:56 -0800
committerKeith Packard <keithp@keithp.com>2013-01-18 16:44:56 -0800
commit7543c6e258195833daa5f17efdc095ad25489db9 (patch)
treec3912137693b81f6f9b0d7863f0482ad48532ba1
Import MIT-SHM fd passing test program
Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--Makefile10
-rw-r--r--shmfd.c202
2 files changed, 212 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..73bd712
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,10 @@
+CFLAGS=-O0 -g $(shell pkg-config --cflags xcb-shm xcb-aux)
+LIBS=$(shell pkg-config --libs xcb-shm xcb-aux)
+
+OBJS=shmfd.o
+
+shmfd: $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+ rm -f shmfd $(OBJS) \ No newline at end of file
diff --git a/shmfd.c b/shmfd.c
new file mode 100644
index 0000000..f4b25de
--- /dev/null
+++ b/shmfd.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <xcb/xcb.h>
+#include <xcb/shm.h>
+#include <xcb/xcb_aux.h>
+
+int
+make_shm(int size, void **addrp)
+{
+ void *addr;
+ char template[] = "/tmp/shmfd-XXXXXX";
+ int fd = mkstemp(template);
+
+ if (fd < 0)
+ return fd;
+ unlink(template);
+ ftruncate(fd, size);
+ addr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ close (fd);
+ return -1;
+ }
+ *addrp = addr;
+ return fd;
+}
+
+void
+paint(uint32_t *base, int width, int height, int forward)
+{
+ int x, y;
+ uint8_t r, g, b;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ r = x * 256 / width;
+ g = 255 - r;
+ if (forward)
+ b = y * 256 / height;
+ else
+ b = (255 - y) * 256 / height;
+ base[y * width + x] = (r << 16) | (g << 8) | b;
+ }
+ }
+}
+
+#define WIDTH 128
+#define HEIGHT 128
+
+int
+main (int argc, char **argv)
+{
+ xcb_connection_t *c;
+ int screen_num;
+ xcb_screen_t *screen;
+ int fd;
+ void *addr;
+ void *server_addr;
+ xcb_shm_seg_t shm_seg;
+ xcb_shm_seg_t shm_server_seg;
+ xcb_gc_t gc;
+ xcb_pixmap_t pixmap;
+ xcb_window_t window;
+ xcb_generic_event_t *event;
+ xcb_generic_error_t *error;
+ xcb_shm_create_segment_cookie_t shm_create_segment_cookie;
+ xcb_shm_create_segment_reply_t *shm_create_segment_reply;
+ xcb_generic_error_t *shm_create_segment_error;
+ int *shm_create_segment_fds;
+ uint32_t window_mask;
+ uint32_t window_values[5];
+ uint32_t size = WIDTH * HEIGHT * 4;
+
+ fd = make_shm(size, &addr); /* some memory */
+ paint(addr, WIDTH, HEIGHT, 0);
+ printf ("painted\n");
+ c = xcb_connect(NULL, &screen_num);
+ if (xcb_connection_has_error(c)) {
+ printf ("connection error\n");
+ exit(1);
+ }
+ screen = xcb_aux_get_screen(c, screen_num);
+
+ xcb_shm_attach_fd (c,
+ (shm_seg = xcb_generate_id(c)),
+ fd,
+ 1);
+
+ shm_create_segment_cookie = xcb_shm_create_segment(c,
+ (shm_server_seg = xcb_generate_id(c)),
+ size,
+ 1);
+ shm_create_segment_reply = xcb_shm_create_segment_reply (c,
+ shm_create_segment_cookie,
+ &shm_create_segment_error);
+ if (shm_create_segment_reply) {
+ shm_create_segment_fds = xcb_shm_create_segment_reply_fds(c,
+ shm_create_segment_reply);
+
+ server_addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm_create_segment_fds[0], 0);
+ close(shm_create_segment_fds[0]);
+ free(shm_create_segment_reply);
+ paint(server_addr, WIDTH, HEIGHT, 1);
+ }
+ else
+ server_addr = NULL;
+
+ window_mask = XCB_CW_EVENT_MASK;
+ window_values[0] = XCB_EVENT_MASK_EXPOSURE;
+
+ xcb_create_window(c,
+ 0, /* depth */
+ (window = xcb_generate_id(c)), /* window */
+ screen->root, /* root */
+ 0, /* x */
+ 0, /* y */
+ WIDTH * 2, /* width */
+ HEIGHT, /* height */
+ 0, /* border_width */
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
+ screen->root_visual, /* visual */
+ window_mask, /* mask */
+ window_values); /* values */
+ xcb_create_gc(c,
+ (gc = xcb_generate_id(c)), /* gc */
+ window, /* drawable */
+ 0, /* mask */
+ NULL); /* values */
+
+ xcb_map_window(c, window);
+
+ printf ("mapped\n");
+
+ for (;;) {
+ xcb_flush(c);
+ event = xcb_wait_for_event(c);
+ switch (event->response_type) {
+ case XCB_EXPOSE:
+ xcb_shm_put_image(c,
+ window,
+ gc,
+ WIDTH,
+ HEIGHT,
+ 0,
+ 0,
+ WIDTH,
+ HEIGHT,
+ 0,
+ 0,
+ 24,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ 0,
+ shm_seg,
+ 0);
+ xcb_shm_put_image(c,
+ window,
+ gc,
+ WIDTH,
+ HEIGHT,
+ 0,
+ 0,
+ WIDTH,
+ HEIGHT,
+ WIDTH,
+ 0,
+ 24,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ 0,
+ shm_server_seg,
+ 0);
+ break;
+ case 0:
+ error = (xcb_generic_error_t *) event;
+ printf ("error %d major %d minor %d\n",
+ error->error_code,
+ error->major_code,
+ error->minor_code);
+ break;
+ default:
+ printf ("response %d\n", event->response_type);
+ break;
+ }
+ }
+}