* Last modified: Wed May 15 00:04:43 2013,
* Dave Odell <dmo2118@gmail.com>
* Tuned performance; double-buffering is now off by default.
- * Made animation speed independant of FPS.
+ * Made animation speed independent of FPS.
* Added cleanup code, fixed a few glitches.
* Added gratuitous #ifdefs.
+ * Last modified: Fri Feb 21 02:14:29 2014, <dmo2118@gmail.com>
+ * Added support for SMP rendering.
+ * Tweaked math a bit re: performance.
+ * Last modified: Tue Dec 30 16:43:33 2014, <dmo2118@gmail.com>
+ * Killed the black margin on the right and bottom.
+ * Reduced the default grid size to 2.
+ * Last modified: Sun Oct 9 11:20:48 2016, <dmo2118@gmail.com>
+ * Updated for new xshm.c.
+ * Ditched USE_BIG_XIMAGE.
*/
#include <math.h>
#include "screenhack.h"
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
+#include "thread_util.h"
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
#else
typedef unsigned int uint32_t;
USE_XIMAGE is off: Yes (-db: 4.1 FPS, -no-db: 2.9 FPS)
XPutImage in strips: No (-db: 35.9 FPS, -no-db: 38.7 FPS)
XPutImage, whole image: No (-db: 32.3 FPS, -no-db: 33.7 FPS)
-MIT-SHM, whole image: Doesn't work anyway: (37.3 FPS)
+MIT-SHM, whole image: Doesn't work anyway: (-no-db: 37.3 FPS)
If gridsize = 1, XPutImage is slow when the XImage is one line at a time.
XPutImage in strips: -db: 21.2 FPS, -no-db: 19.7 FPS
/* It's a lot faster for me, though - D.O. */
#define USE_XIMAGE
-/* i.e. make the XImage the size of the screen. This is much faster when
- * gridsize = 1. (And SHM is turned off.) */
-#define USE_BIG_XIMAGE
-
-/* Numbers are wave_table size, measured in unsigned integers.
+/* Numbers are wave_table size, measured in # of unsigned integers.
* FPS/radius = 50/radius = 800/radius = 1500/Big-O memory usage
*
* Use at most one of the following:
/* #define USE_FAST_SQRT_HACKISH */ /* 17.8 FPS/2873/4921/5395/O(lg(radius)) */
#define USE_FAST_SQRT_BIGTABLE2 /* 26.1 FPS/156/2242/5386/O(radius^2) */
-#ifndef USE_XIMAGE
-# undef HAVE_XSHM_EXTENSION /* only applicable when using XImages */
-#endif /* USE_XIMAGE */
-
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
# include "xdbe.h"
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-#ifdef HAVE_XSHM_EXTENSION
+#ifdef USE_XIMAGE
# include "xshm.h"
-#endif /* HAVE_XSHM_EXTENSION */
+#endif /* USE_XIMAGE */
static const char *interference_defaults [] = {
".background: black",
".foreground: white",
"*count: 3", /* number of waves */
- "*gridsize: 4", /* pixel size, smaller values for better resolution */
- "*ncolors: 128", /* number of colours used */
+ "*gridsize: 2", /* pixel size, smaller values for better resolution */
+ "*ncolors: 192", /* number of colours used */
"*hue: 0", /* hue to use for base color (0-360) */
"*speed: 30", /* speed of wave origins moving around */
"*delay: 30000", /* or something */
#ifdef HAVE_XSHM_EXTENSION
"*useSHM: True", /* use shared memory extension */
#endif /* HAVE_XSHM_EXTENSION */
-#ifdef USE_IPHONE
+#ifdef HAVE_MOBILE
"*ignoreRotation: True",
#endif
+ THREAD_DEFAULTS
0
};
{ "-shm", ".useSHM", XrmoptionNoArg, "True" },
{ "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
#endif /* HAVE_XSHM_EXTENSION */
+ THREAD_OPTIONS
{ 0, 0, 0, 0 }
};
GC copy_gc;
#ifdef USE_XIMAGE
XImage *ximage;
-#endif /* USE_XIMAGE */
-#ifdef HAVE_XSHM_EXTENSION
- Bool use_shm, shm_can_draw;
+ Bool shm_can_draw;
XShmSegmentInfo shm_info;
-#endif /* HAVE_XSHM_EXTENSION */
+#endif /* USE_XIMAGE */
/*
* Resources
*/
int w;
int h;
+ unsigned w_div_g, h_div_g;
Colormap cmap;
Screen *screen;
+ unsigned bits_per_pixel;
XColor* pal;
#ifndef USE_XIMAGE
GC* gcs;
#endif
int radius; /* Not always the same as the X resource. */
double last_frame;
-#ifdef USE_XIMAGE
- uint32_t* row;
-#endif
+
+ struct threadpool threadpool;
/*
* lookup tables
struct inter_source* source;
};
+struct inter_thread
+{
+ const struct inter_context *context;
+ unsigned thread_id;
+
+#ifdef USE_XIMAGE
+ uint32_t* row;
+#endif
+
+ unsigned* result_row;
+};
+
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
# define TARGET(c) ((c)->back_buf ? (c)->back_buf : \
(c)->pix_buf ? (c)->pix_buf : (c)->win)
#endif
-/* Also destroys c->row. */
static void destroy_image(Display* dpy, struct inter_context* c)
{
#ifdef USE_XIMAGE
if(c->ximage) {
-# ifdef HAVE_XSHM_EXTENSION
- if(c->use_shm) {
- destroy_xshm_image(dpy, c->ximage, &c->shm_info);
- } else
-# endif
- {
- /* Also frees c->ximage->data, which isn't allocated by XCreateImage. */
- XDestroyImage(c->ximage);
- }
+ destroy_xshm_image(dpy, c->ximage, &c->shm_info);
}
-
- free(c->row);
#endif
+
+ if(c->threadpool.count)
+ {
+ threadpool_destroy(&c->threadpool);
+ c->threadpool.count = 0;
+ }
}
static void inter_free(Display* dpy, struct inter_context* c)
if(c->colors <= 2)
free(c->pal);
- else
+ else if(c->pal)
free_colors(c->screen, c->cmap, c->pal, c->colors);
#ifndef USE_XIMAGE
free(c->source);
}
-static void abort_no_mem(void)
+static void abort_on_error(int error)
{
- fprintf(stderr, "interference: %s\n", strerror(ENOMEM));
+ fprintf(stderr, "interference: %s\n", strerror(error));
exit(1);
}
+static void abort_no_mem(void)
+{
+ abort_on_error(ENOMEM);
+}
+
static void check_no_mem(Display* dpy, struct inter_context* c, void* ptr)
{
if(!ptr) {
}
}
-/* On allocation error, c->row == NULL. */
-static void create_image(
- Display* dpy,
- struct inter_context* c,
- const XWindowAttributes* xgwa)
+static int inter_thread_create(
+ void* self_raw,
+ struct threadpool* pool,
+ unsigned id)
{
+ struct inter_thread* self = (struct inter_thread*)self_raw;
+ const struct inter_context* c = GET_PARENT_OBJ(struct inter_context, threadpool, pool);
+
+ self->context = c;
+ self->thread_id = id;
+
+ self->result_row = malloc(c->w_div_g * sizeof(unsigned));
+ if(!self->result_row)
+ return ENOMEM;
+
#ifdef USE_XIMAGE
- c->row = malloc((c->w / c->grid_size) * sizeof(uint32_t));
- check_no_mem(dpy, c, c->row);
+ self->row = malloc(c->w_div_g * sizeof(uint32_t));
+ if(!self->row) {
+ free(self->result_row);
+ return ENOMEM;
+ }
+#endif
-# ifdef HAVE_XSHM_EXTENSION
- /*
- * interference used to put one row at a time to the X server. This changes
- * today.
- *
- * XShmPutImage is asynchronous; the contents of the XImage must not be
- * modified until the server has placed the data on the screen. Waiting for
- * an XShmCompletionEvent after every line of pixels is a little nutty, so
- * shared-memory XImages will cover the entire screen, and it only has to be
- * sent once per frame.
- *
- * The non-SHM code, on the other hand is noticeably slower when
- * gridsize = 1 with one row at a time. If, on the other hand, gridsize >= 2,
- * there's a slight speed increase with one row at a time.
- *
- * This uses a lot more RAM than the single line approach. Users with only
- * 4 MB of RAM may wish to disable USE_BIG_XIMAGE and specify -no-shm on the
- * command line. Since this is 2013 and desktop computers are shipping with
- * 8 GB of RAM, I doubt that this will be a major issue. - D.O.
- */
+ return 0;
+}
- if (c->use_shm)
- {
- c->ximage = create_xshm_image(dpy, xgwa->visual, xgwa->depth,
- ZPixmap, 0, &c->shm_info,
- xgwa->width, xgwa->height);
- if (!c->ximage)
- c->use_shm = False;
- /* If create_xshm_image fails, it will not be attempted again. */
-
- c->shm_can_draw = True;
+static void inter_thread_destroy(void* self_raw)
+{
+ struct inter_thread* self = (struct inter_thread*)self_raw;
+#ifdef USE_XIMAGE
+ free(self->row);
+#endif
+ free(self->result_row);
+}
+
+/*
+A higher performance design would have input and output queues, so that when
+worker threads finish with one frame, they can pull the next work order from
+the queue and get started on it immediately, rather than going straight to
+sleep. The current "single-buffered" design still provides reasonable
+performance at low frame rates; high frame rates are noticeably less efficient.
+*/
+
+static void inter_thread_run(void* self_raw)
+{
+ struct inter_thread* self = (struct inter_thread*)self_raw;
+ const struct inter_context* c = self->context;
+
+ int i, j, k;
+ unsigned result;
+ int dist1;
+ int g = c->grid_size;
+
+ int dx, dy, g2 = 2 * g * g;
+ int px, py, px2g;
+
+ int dist0, ddist;
+
+#ifdef USE_XIMAGE
+ unsigned img_y = g * self->thread_id;
+ void *scanline = c->ximage->data + c->ximage->bytes_per_line * g * self->thread_id;
+#endif
+
+ for(j = self->thread_id; j < c->h_div_g; j += c->threadpool.count) {
+ px = g/2;
+ py = j*g + px;
+
+ memset(self->result_row, 0, c->w_div_g * sizeof(unsigned));
+
+ for(k = 0; k < c->count; k++) {
+
+ dx = px - c->source[k].x;
+ dy = py - c->source[k].y;
+
+ dist0 = dx*dx + dy*dy;
+ ddist = -2 * g * c->source[k].x;
+
+ /* px2g = g*(px*2 + g); */
+ px2g = g2;
+
+ for(i = 0; i < c->w_div_g; i++) {
+ /*
+ * Discarded possibilities for improving performance here:
+ * 1. Using octagon-based distance estimation
+ * (Which causes giant octagons to appear.)
+ * 2. Square root approximation by reinterpret-casting IEEE floats to
+ * integers.
+ * (Which causes angles to appear when two waves interfere.)
+ */
+
+/* int_float u;
+ u.f = dx*dx + dy*dy;
+ u.i = (1 << 29) + (u.i >> 1) - (1 << 22);
+ dist = u.f; */
+
+#if defined USE_FAST_SQRT_BIGTABLE2
+ dist1 = FAST_TABLE(dist0);
+#elif defined USE_FAST_SQRT_HACKISH
+ dist1 = fast_log2(dist0);
+#else
+ dist1 = sqrt(dist0);
+#endif
+
+ if(dist1 < c->radius)
+ self->result_row[i] += c->wave_height[dist1];
+
+ dist0 += px2g + ddist;
+ px2g += g2;
+ }
}
-# endif /* HAVE_XSHM_EXTENSION */
- if (!c->ximage)
+ for(i = 0; i < c->w_div_g; i++) {
+
+ result = self->result_row[i];
+
+ /* It's slightly faster to do a subtraction or two before calculating the
+ * modulus. - D.O. */
+ if(result >= c->colors)
+ {
+ result -= c->colors;
+ if(result >= c->colors)
+ result %= (unsigned)c->colors;
+ }
+
+#ifdef USE_XIMAGE
+ self->row[i] = c->pal[result].pixel;
+#else
+ XFillRectangle(c->dpy, TARGET(c), c->gcs[result], g*i, g*j, g, g);
+#endif /* USE_XIMAGE */
+ }
+
+#ifdef USE_XIMAGE
+ /* Fill in these `gridsize' horizontal bits in the scanline */
+ if(c->ximage->bits_per_pixel == 32)
{
- c->ximage =
- XCreateImage(dpy, xgwa->visual,
- xgwa->depth, ZPixmap, 0, 0, /* depth, fmt, offset, data */
- xgwa->width, /* width */
-# ifdef USE_BIG_XIMAGE
- xgwa->height, /* height */
-# else
- c->grid_size, /* height */
-# endif
- 8, 0); /* pad, bpl */
-
- if(c->ximage)
- {
- c->ximage->data = (char *)
- calloc(c->ximage->height, c->ximage->bytes_per_line);
-
- if(!c->ximage->data)
- {
- free(c->ximage);
- c->ximage = NULL;
- }
+ uint32_t *ptr = (uint32_t *)scanline;
+ for(i = 0; i < c->w_div_g; i++) {
+ for(k = 0; k < g; k++)
+ ptr[g*i+k] = self->row[i];
+ }
+ }
+ else if(c->ximage->bits_per_pixel == 24)
+ {
+ uint8_t *ptr = (uint8_t *)scanline;
+ for(i = 0; i < c->w_div_g; i++) {
+ for(k = 0; k < g; k++) {
+ uint32_t pixel = self->row[i];
+ /* Might not work on big-endian. */
+ ptr[0] = pixel;
+ ptr[1] = (pixel & 0x0000ff00) >> 8;
+ ptr[2] = (pixel & 0x00ff0000) >> 16;
+ ptr += 3;
}
+ }
}
-
- if(!c->ximage)
+ else if(c->ximage->bits_per_pixel == 16)
{
- free(c->row);
- c->row = 0;
+ uint16_t *ptr = (uint16_t *)scanline;
+ for(i = 0; i < c->w_div_g; i++) {
+ for(k = 0; k < g; k++)
+ ptr[g*i+k] = self->row[i];
+ }
+ }
+ else if(c->ximage->bits_per_pixel == 8)
+ {
+ uint8_t *ptr = (uint8_t *)scanline;
+ for(i = 0; i < c->w_div_g; i++) {
+ for(k = 0; k < g; k++)
+ ptr[g*i+k] = self->row[i];
+ }
+ }
+ else
+ {
+ for(i = 0; i < c->w_div_g; i++) {
+ for(k = 0; k < g; k++)
+ /* XPutPixel is thread safe as long as the XImage didn't have its
+ * bits_per_pixel changed. */
+ XPutPixel(c->ximage, (g*i)+k, img_y, self->row[i]);
+ }
}
- check_no_mem(dpy, c, c->row);
+ /* Only the first scanline of the image has been filled in; clone that
+ scanline to the rest of the `gridsize' lines in the ximage */
+ for(k = 0; k < (g-1); k++)
+ memcpy(c->ximage->data + (c->ximage->bytes_per_line * (img_y + k + 1)),
+ c->ximage->data + (c->ximage->bytes_per_line * img_y),
+ c->ximage->bytes_per_line);
+
+ scanline = (char *)scanline +
+ c->ximage->bytes_per_line * g * c->threadpool.count;
+ img_y += g * c->threadpool.count;
+
+#endif /* USE_XIMAGE */
+ }
+}
+
+/* On allocation error, c->ximage == NULL. */
+static void create_image(
+ Display* dpy,
+ struct inter_context* c,
+ const XWindowAttributes* xgwa)
+{
+#ifdef USE_XIMAGE
+
+ /* Set the width so that each thread can work on a different line. */
+ unsigned align = thread_memory_alignment(dpy) * 8 - 1;
+ unsigned wbits, w, h;
+#endif /* USE_XIMAGE */
+
+ c->w = xgwa->width;
+ c->h = xgwa->height;
+ c->w_div_g = (c->w + c->grid_size - 1) / c->grid_size;
+ c->h_div_g = (c->h + c->grid_size - 1) / c->grid_size;
+
+#ifdef USE_XIMAGE
+ w = c->w_div_g * c->grid_size;
+ h = c->h_div_g * c->grid_size;
+
+ /* The width of a scan line, in *bits*. */
+ wbits = (w * c->bits_per_pixel + align) & ~align;
+
+ /* This uses a lot more RAM than the single line approach. Users without
+ * enough RAM to fit even a single framebuffer should consider an upgrade for
+ * their 386. - D.O.
+ */
+
+ c->ximage = create_xshm_image(dpy, xgwa->visual, xgwa->depth,
+ ZPixmap, &c->shm_info,
+ wbits / c->bits_per_pixel, h);
+
+ c->shm_can_draw = True;
+
+ check_no_mem(dpy, c, c->ximage);
#endif /* USE_XIMAGE */
+
+ {
+ static const struct threadpool_class cls =
+ {
+ sizeof(struct inter_thread),
+ inter_thread_create,
+ inter_thread_destroy
+ };
+
+ int error = threadpool_create(
+ &c->threadpool,
+ &cls,
+ dpy,
+#ifdef USE_XIMAGE
+ hardware_concurrency(dpy)
+#else
+ 1
+ /* At least two issues with threads without USE_XIMAGE:
+ * 1. Most of Xlib isn't thread safe without XInitThreads.
+ * 2. X(Un)LockDisplay would need to be called for each line, which is
+ * terrible.
+ */
+#endif
+ );
+
+ if(error) {
+ c->threadpool.count = 0; /* See the note in thread_util.h. */
+ inter_free(dpy, c);
+ abort_on_error(error);
+ }
+ }
}
static void create_pix_buf(Display* dpy, Window win, struct inter_context *c,
unsigned long valmask = 0;
#endif
-# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
+# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
dbuf = False;
# endif
c->dpy = dpy;
c->win = win;
+
c->delay = get_integer_resource(dpy, "delay", "Integer");
XGetWindowAttributes(c->dpy, c->win, &xgwa);
- c->w = xgwa.width;
- c->h = xgwa.height;
c->cmap = xgwa.colormap;
c->screen = xgwa.screen;
-
-#ifdef HAVE_XSHM_EXTENSION
- c->use_shm = get_boolean_resource(dpy, "useSHM", "Boolean");
-#endif /* HAVE_XSHM_EXTENSION */
+ c->bits_per_pixel = visual_pixmap_depth(xgwa.screen, xgwa.visual);
+ check_no_mem(dpy, c, (void *)(ptrdiff_t)c->bits_per_pixel);
val.function = GXcopy;
c->copy_gc = XCreateGC(c->dpy, TARGET(c), GCFunction, &val);
c->pal[1].pixel = WhitePixel(c->dpy, DefaultScreen(c->dpy));
}
-#ifdef HAVE_XSHM_EXTENSION
- if(c->use_shm)
- dbuf = False;
+#ifdef USE_XIMAGE
+ dbuf = False;
/* Double-buffering doesn't work with MIT-SHM: XShmPutImage must draw to the
* window. Otherwise, XShmCompletion events will have the XAnyEvent::window
- * field set to the back buffer, and XScreenSaver will ignore the event. */
+ * field set to the back buffer, and XScreenSaver will ignore the event.
+ */
#endif
if (dbuf)
c->radius = radius;
#endif
+ if (c->radius < 1) c->radius = 1;
c->wave_height = calloc(c->radius, sizeof(unsigned));
check_no_mem(dpy, c, c->wave_height);
(c->h/2 + ((int)(cos(c->source[i].y_theta)*((float)c->h/2.0))))
/*
- * This is rather suboptimal. Calculating the distance per-pixel is going to
+ * This is somewhat suboptimal. Calculating the distance per-pixel is going to
* be a lot slower than using now-ubiquitous SIMD CPU instructions to do four
- * or eight pixels at a time. Plus, this could be almost trivially
- * parallelized, what with all the multi-core hardware nowadays.
+ * or eight pixels at a time.
*/
static unsigned long do_inter(struct inter_context* c)
{
- int i, j, k;
- unsigned result;
- int dist;
- int g = c->grid_size;
- unsigned w_div_g = c->w/g;
-
- int dx, dy;
- int px, py;
-
-#ifdef USE_XIMAGE
- unsigned img_y = 0;
- void *scanline = c->ximage->data;
-#endif
+ int i;
double now;
float elapsed;
-#if defined USE_XIMAGE && defined HAVE_XSHM_EXTENSION
+#ifdef USE_XIMAGE
/* Wait a little while for the XServer to become ready if necessary. */
- if(c->use_shm && !c->shm_can_draw)
+ if(!c->shm_can_draw)
return 2000;
#endif
c->source[i].y = source_y(c, i);
}
- for(j = 0; j < c->h/g; j++) {
- for(i = 0; i < w_div_g; i++) {
- result = 0;
- px = i*g + g/2;
- py = j*g + g/2;
- for(k = 0; k < c->count; k++) {
-
- dx = px - c->source[k].x;
- dy = py - c->source[k].y;
-
- /*
- * Other possibilities for improving performance here:
- * 1. Using octagon-based distance estimation
- * (Which causes giant octagons to appear.)
- * 2. Square root approximation by reinterpret-casting IEEE floats to
- * integers.
- * (Which causes angles to appear when two waves interfere.)
- */
-
-/* int_float u;
- u.f = dx*dx + dy*dy;
- u.i = (1 << 29) + (u.i >> 1) - (1 << 22);
- dist = u.f; */
-
-#if defined USE_FAST_SQRT_BIGTABLE2
- dist = dx*dx + dy*dy;
- dist = FAST_TABLE(dist);
-#elif defined USE_FAST_SQRT_HACKISH
- dist = fast_log2(dx*dx + dy*dy);
-#else
- dist = sqrt(dx*dx + dy*dy);
-#endif
-
- result += (dist >= c->radius ? 0 : c->wave_height[dist]);
- }
-
- /* It's slightly faster to do a subtraction or two before calculating the
- * modulus. - D.O. */
- if(result >= c->colors)
- {
- result -= c->colors;
- if(result >= c->colors)
- result %= (unsigned)c->colors;
- }
+ threadpool_run(&c->threadpool, inter_thread_run);
+ threadpool_wait(&c->threadpool);
#ifdef USE_XIMAGE
- c->row[i] = c->pal[result].pixel;
-#else
- XFillRectangle(c->dpy, TARGET(c), c->gcs[result], g*i, g*j, g, g);
-#endif /* USE_XIMAGE */
- }
-
-#ifdef USE_XIMAGE
- /* Fill in these `gridsize' horizontal bits in the scanline */
- if(c->ximage->bits_per_pixel == 32)
- {
- uint32_t *ptr = (uint32_t *)scanline;
- for(i = 0; i < w_div_g; i++) {
- for(k = 0; k < g; k++)
- ptr[g*i+k] = c->row[i];
- }
- }
- else if(c->ximage->bits_per_pixel == 24)
- {
- uint8_t *ptr = (uint8_t *)scanline;
- for(i = 0; i < w_div_g; i++) {
- for(k = 0; k < g; k++) {
- uint32_t pixel = c->row[i];
- /* Might not work on big-endian. */
- ptr[0] = pixel;
- ptr[1] = (pixel & 0x0000ff00) >> 8;
- ptr[2] = (pixel & 0x00ff0000) >> 16;
- ptr += 3;
- }
- }
- }
- else if(c->ximage->bits_per_pixel == 16)
- {
- uint16_t *ptr = (uint16_t *)scanline;
- for(i = 0; i < w_div_g; i++) {
- for(k = 0; k < g; k++)
- ptr[g*i+k] = c->row[i];
- }
- }
- else if(c->ximage->bits_per_pixel == 8)
- {
- uint8_t *ptr = (uint8_t *)scanline;
- for(i = 0; i < w_div_g; i++) {
- for(k = 0; k < g; k++)
- ptr[g*i+k] = c->row[i];
- }
- }
- else
- {
- for(i = 0; i < w_div_g; i++) {
- for(k = 0; k < g; k++)
- XPutPixel(c->ximage, (g*i)+k, img_y, c->row[i]);
- }
- }
-
- /* Only the first scanline of the image has been filled in; clone that
- scanline to the rest of the `gridsize' lines in the ximage */
- for(k = 0; k < (g-1); k++)
- memcpy(c->ximage->data + (c->ximage->bytes_per_line * (img_y + k + 1)),
- c->ximage->data + (c->ximage->bytes_per_line * img_y),
- c->ximage->bytes_per_line);
-
-# ifndef USE_BIG_XIMAGE
- /* Move the bits for this horizontal stripe to the server. */
-# ifdef HAVE_XSHM_EXTENSION
- if (!c->use_shm)
-# endif /* HAVE_XSHM_EXTENSION */
- XPutImage(c->dpy, TARGET(c), c->copy_gc, c->ximage,
- 0, 0, 0, g*j, c->ximage->width, c->ximage->height);
-# endif
-
-# if defined HAVE_XSHM_EXTENSION && !defined USE_BIG_XIMAGE
- if (c->use_shm)
-# endif
- {
-# if defined HAVE_XSHM_EXTENSION || defined USE_BIG_XIMAGE
- scanline = (char *)scanline + c->ximage->bytes_per_line * g;
- img_y += g;
-# endif
- }
-
-#endif /* USE_XIMAGE */
- }
-
-#ifdef HAVE_XSHM_EXTENSION
- if (c->use_shm)
- {
- XShmPutImage(c->dpy, c->win, c->copy_gc, c->ximage,
- 0, 0, 0, 0, c->ximage->width, c->ximage->height,
- True);
- c->shm_can_draw = False;
- }
-#endif
-#if defined HAVE_XSHM_EXTENSION && defined USE_BIG_XIMAGE
- else
-#endif
-#ifdef USE_BIG_XIMAGE
- {
- XPutImage(c->dpy, TARGET(c), c->copy_gc, c->ximage,
- 0, 0, 0, 0, c->ximage->width, c->ximage->height);
- }
+ put_xshm_image(c->dpy, c->win, c->copy_gc, c->ximage, 0, 0, 0, 0,
+ c->ximage->width, c->ximage->height, &c->shm_info);
+ /* c->shm_can_draw = False; */
#endif
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
{
struct inter_context *c = (struct inter_context *) closure;
XWindowAttributes xgwa;
- Bool dbuf = (c->pix_buf
+ Bool dbuf = (!!c->pix_buf
# ifdef HAVE_DOUBLE_BUFFER_EXTENSION
|| c->back_buf
# endif
);
- c->w = w;
- c->h = h;
-
#ifdef USE_XIMAGE
destroy_image(dpy, c);
c->ximage = 0;
#if HAVE_XSHM_EXTENSION
struct inter_context *c = (struct inter_context *) closure;
- if(c->use_shm && event->type == XShmGetEventBase(dpy) + ShmCompletion)
+ if(event->type == XShmGetEventBase(dpy) + ShmCompletion)
{
c->shm_can_draw = True;
return True;