int BC_XImage::read_drawable(Drawable &pixmap, int source_x, int source_y) { XGetSubImage(top_level->display, pixmap, source_x, source_y, bitmap->w, bitmap->h, 0xffffffff, ZPixmap, ximage, 0, 0); return 0; }
static void swrastGetImage2(__DRIdrawable * read, int x, int y, int w, int h, int stride, char *data, void *loaderPrivate) { struct drisw_drawable *prp = loaderPrivate; __GLXDRIdrawable *pread = &(prp->base); Display *dpy = pread->psc->dpy; Drawable readable; XImage *ximage; if (!prp->ximage || prp->shminfo.shmid >= 0) { if (!XCreateDrawable(prp, -1, dpy)) return; } readable = pread->xDrawable; ximage = prp->ximage; ximage->data = data; ximage->width = w; ximage->height = h; ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32); XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0); ximage->data = NULL; }
// the bitmap must be wholly contained in the source during a GetImage int BC_Bitmap::read_drawable(Drawable &pixmap, int source_x, int source_y) { if(use_shm) XShmGetImage(top_level->display, pixmap, ximage[current_ringbuffer], source_x, source_y, 0xffffffff); else XGetSubImage(top_level->display, pixmap, source_x, source_y, w, h, 0xffffffff, ZPixmap, ximage[current_ringbuffer], 0, 0); return 0; }
Bool get_xshm_image (Display *dpy, Drawable d, XImage *image, int x, int y, unsigned long plane_mask, XShmSegmentInfo *shm_info) { #ifdef HAVE_XSHM_EXTENSION if (shm_info->shmid != -1) { return XShmGetImage (dpy, d, image, x, y, plane_mask); } #endif /* HAVE_XSHM_EXTENSION */ return XGetSubImage (dpy, d, x, y, image->width, image->height, plane_mask, image->format, image, 0, 0) != NULL; }
static struct fbuf_t *grab_x11_read(void *desc) { /* read frame from X11 */ struct grab_x11_desc *v = desc; struct fbuf_t *b = &v->b; XGetSubImage(v->dpy, RootWindow(v->dpy, DefaultScreen(v->dpy)), b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0); b->data = (uint8_t *)v->image->data; return b; }
int fbx_read(fbx_struct *fb, int x_, int y_) { int x, y; #ifdef _WIN32 fbx_gc gc; #endif if(!fb) _throw("Invalid argument"); x=x_>=0? x_:0; y=y_>=0? y_:0; #ifdef _WIN32 if(!fb->hmdc || fb->width<=0 || fb->height<=0 || !fb->bits || !fb->wh) _throw("Not initialized"); _w32(gc=GetDC(fb->wh)); _w32(BitBlt(fb->hmdc, 0, 0, fb->width, fb->height, gc, x, y, SRCCOPY)); _w32(ReleaseDC(fb->wh, gc)); return 0; #else if(!fb->wh.dpy || !fb->wh.d || !fb->xi || !fb->bits) _throw("Not initialized"); #ifdef USESHM if(!fb->xattach && fb->shm) { _x11(XShmAttach(fb->wh.dpy, &fb->shminfo)); fb->xattach=1; } #endif #ifdef USESHM if(fb->shm) { _x11(XShmGetImage(fb->wh.dpy, fb->wh.d, fb->xi, x, y, AllPlanes)); } else #endif { _x11(XGetSubImage(fb->wh.dpy, fb->wh.d, x, y, fb->width, fb->height, AllPlanes, ZPixmap, fb->xi, 0, 0)); } return 0; #endif finally: return -1; }
static void swrastGetImage(__DRIdrawable * draw, int x, int y, int w, int h, char *data, void *loaderPrivate) { __GLXDRIdrawablePrivate *pdp = loaderPrivate; __GLXDRIdrawable *pdraw = &(pdp->base); Display *dpy = pdraw->psc->dpy; Drawable drawable; XImage *ximage; drawable = pdraw->xDrawable; ximage = pdp->ximage; ximage->data = data; ximage->width = w; ximage->height = h; ximage->bytes_per_line = bytes_per_line(w, pdp->bpp, 32); XGetSubImage(dpy, drawable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0); ximage->data = NULL; }
int BC_Capture::capture_frame(VFrame *frame, int &x1, int &y1) { if(!display) return 1; if(x1 < 0) x1 = 0; if(y1 < 0) y1 = 0; if(x1 > get_top_w() - w) x1 = get_top_w() - w; if(y1 > get_top_h() - h) y1 = get_top_h() - h; // Read the raw data if(use_shm) XShmGetImage(display, rootwin, ximage, x1, y1, 0xffffffff); else XGetSubImage(display, rootwin, x1, y1, w, h, 0xffffffff, ZPixmap, ximage, 0, 0); BC_WindowBase::get_cmodels()->transfer(frame->get_rows(), row_data, frame->get_y(), frame->get_u(), frame->get_v(), 0, 0, 0, 0, 0, w, h, 0, 0, frame->get_w(), frame->get_h(), bitmap_color_model, frame->get_color_model(), 0, frame->get_w(), w); return 0; }
XImage* _xgetxdata(Memimage *m, Rectangle r) { int x, y; uchar *p; Point tp, xdelta, delta; Xmem *xm; xm = m->X; if(xm == nil) return nil; if(xm->dirty == 0) return xm->xi; abort(); /* should never call this now */ r = xm->dirtyr; if(Dx(r)==0 || Dy(r)==0) return xm->xi; delta = subpt(r.min, m->r.min); tp = xm->r.min; /* need temp for Digital UNIX */ xdelta = subpt(r.min, tp); XGetSubImage(_x.display, xm->pixmap, delta.x, delta.y, Dx(r), Dy(r), AllPlanes, ZPixmap, xm->xi, xdelta.x, delta.y); if(_x.usetable && m->chan==CMAP8){ for(y=r.min.y; y<r.max.y; y++) for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++) *p = _x.toplan9[*p]; } xm->dirty = 0; xm->dirtyr = Rect(0,0,0,0); return xm->xi; }
static void swrastGetImage(__DRIdrawable * read, int x, int y, int w, int h, char *data, void *loaderPrivate) { struct drisw_drawable *prp = loaderPrivate; __GLXDRIdrawable *pread = &(prp->base); Display *dpy = pread->psc->dpy; Drawable readable; XImage *ximage; readable = pread->xDrawable; ximage = prp->ximage; ximage->data = data; ximage->width = w; ximage->height = h; ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32); XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0); ximage->data = NULL; }
static DFBResult x11Read( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, void *destination, int pitch, const DFBRectangle *rect ) { XImage *image; XImage *sub; x11PoolLocalData *local = pool_local; x11AllocationData *alloc = alloc_data; DFBX11 *x11 = local->x11; D_DEBUG_AT( X11_Surfaces, "%s( %p )\n", __FUNCTION__, allocation ); D_DEBUG_AT( X11_Surfaces, " -> allocation: %s\n", ToString_CoreSurfaceAllocation( allocation ) ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_ASSERT( destination != NULL ); D_ASSERT( pitch >= 0 ); DFB_RECTANGLE_ASSERT( rect ); D_DEBUG_AT( X11_Surfaces, " => %p 0x%08lx [%4d,%4d-%4dx%4d]\n", alloc, alloc->xid, DFB_RECTANGLE_VALS(rect) ); XLockDisplay( x11->display ); #if 1 image = XCreateImage( x11->display, alloc->visual, alloc->depth, ZPixmap, 0, destination, rect->w, rect->h, 32, pitch ); if (!image) { D_ERROR( "X11/Surfaces: XCreateImage( %dx%d, depth %d ) failed!\n", rect->w, rect->h, alloc->depth ); XUnlockDisplay( x11->display ); return DFB_FAILURE; } sub = XGetSubImage( x11->display, alloc->xid, rect->x, rect->y, rect->w, rect->h, ~0, ZPixmap, image, 0, 0 ); #else image = XGetImage( x11->display, alloc->window ? alloc->window : alloc->xid, rect->x, rect->y, rect->w, rect->h, ~0, ZPixmap ); #endif if (image) { // dfb_surface_buffer_dump_type_locked2( allocation->buffer, ".", "x11Read", false, image->data, image->bytes_per_line ); /* FIXME: Why the X-hell is XDestroyImage() freeing *MY* data? */ image->data = NULL; XDestroyImage( image ); } XUnlockDisplay( x11->display ); #if 1 if (!sub) { D_ERROR( "X11/Surfaces: XGetSubImage( %d,%d-%dx%d ) failed!\n", DFB_RECTANGLE_VALS(rect) ); return DFB_FAILURE; } #endif return DFB_OK; }
static void _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap) { CoglTexture *tex = COGL_TEXTURE (tex_pixmap); Display *display; Visual *visual; CoglPixelFormat image_format; XImage *image; int src_x, src_y; int x, y, width, height; int bpp; int offset; CoglError *ignore = NULL; _COGL_GET_CONTEXT (ctx, NO_RETVAL); display = cogl_xlib_renderer_get_display (ctx->display->renderer); visual = tex_pixmap->visual; /* If the damage region is empty then there's nothing to do */ if (tex_pixmap->damage_rect.x2 == tex_pixmap->damage_rect.x1) return; x = tex_pixmap->damage_rect.x1; y = tex_pixmap->damage_rect.y1; width = tex_pixmap->damage_rect.x2 - x; height = tex_pixmap->damage_rect.y2 - y; /* We lazily create the texture the first time it is needed in case this texture can be entirely handled using the GLX texture instead */ if (tex_pixmap->tex == NULL) { CoglPixelFormat texture_format; texture_format = (tex_pixmap->depth >= 32 ? COGL_PIXEL_FORMAT_RGBA_8888_PRE : COGL_PIXEL_FORMAT_RGB_888); tex_pixmap->tex = create_fallback_texture (ctx, tex->width, tex->height, texture_format); } if (tex_pixmap->image == NULL) { /* If we also haven't got a shm segment then this must be the first time we've tried to update, so lets try allocating shm first */ if (tex_pixmap->shm_info.shmid == -1) try_alloc_shm (tex_pixmap); if (tex_pixmap->shm_info.shmid == -1) { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetImage", tex_pixmap); /* We'll fallback to using a regular XImage. We'll download the entire area instead of a sub region because presumably if this is the first update then the entire pixmap is needed anyway and it saves trying to manually allocate an XImage at the right size */ tex_pixmap->image = XGetImage (display, tex_pixmap->pixmap, 0, 0, tex->width, tex->height, AllPlanes, ZPixmap); image = tex_pixmap->image; src_x = x; src_y = y; } else { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XShmGetImage", tex_pixmap); /* Create a temporary image using the beginning of the shared memory segment and the right size for the region we want to update. We need to reallocate the XImage every time because there is no XShmGetSubImage. */ image = XShmCreateImage (display, tex_pixmap->visual, tex_pixmap->depth, ZPixmap, NULL, &tex_pixmap->shm_info, width, height); image->data = tex_pixmap->shm_info.shmaddr; src_x = 0; src_y = 0; XShmGetImage (display, tex_pixmap->pixmap, image, x, y, AllPlanes); } } else { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetSubImage", tex_pixmap); image = tex_pixmap->image; src_x = x; src_y = y; XGetSubImage (display, tex_pixmap->pixmap, x, y, width, height, AllPlanes, ZPixmap, image, x, y); } image_format = _cogl_util_pixel_format_from_masks (visual->red_mask, visual->green_mask, visual->blue_mask, image->depth, image->bits_per_pixel, image->byte_order == LSBFirst); bpp = _cogl_pixel_format_get_bytes_per_pixel (image_format); offset = image->bytes_per_line * src_y + bpp * src_x; _cogl_texture_set_region (tex_pixmap->tex, width, height, image_format, image->bytes_per_line, ((const uint8_t *) image->data) + offset, x, y, 0, /* level */ &ignore); /* If we have a shared memory segment then the XImage would be a temporary one with no data allocated so we can just XFree it */ if (tex_pixmap->shm_info.shmid != -1) XFree (image); memset (&tex_pixmap->damage_rect, 0, sizeof (CoglDamageRectangle)); }
static void _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap) { Display *display; CoglPixelFormat image_format; XImage *image; int src_x, src_y; int x, y, width, height; display = cogl_xlib_get_display (); /* If the damage region is empty then there's nothing to do */ if (tex_pixmap->damage_rect.x2 == tex_pixmap->damage_rect.x1) return; x = tex_pixmap->damage_rect.x1; y = tex_pixmap->damage_rect.y1; width = tex_pixmap->damage_rect.x2 - x; height = tex_pixmap->damage_rect.y2 - y; /* We lazily create the texture the first time it is needed in case this texture can be entirely handled using the GLX texture instead */ if (tex_pixmap->tex == COGL_INVALID_HANDLE) { CoglPixelFormat texture_format; texture_format = (tex_pixmap->depth >= 32 ? COGL_PIXEL_FORMAT_RGBA_8888_PRE : COGL_PIXEL_FORMAT_RGB_888); tex_pixmap->tex = cogl_texture_new_with_size (tex_pixmap->width, tex_pixmap->height, COGL_TEXTURE_NONE, texture_format); } if (tex_pixmap->image == NULL) { /* If we also haven't got a shm segment then this must be the first time we've tried to update, so lets try allocating shm first */ if (tex_pixmap->shm_info.shmid == -1) try_alloc_shm (tex_pixmap); if (tex_pixmap->shm_info.shmid == -1) { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetImage", tex_pixmap); /* We'll fallback to using a regular XImage. We'll download the entire area instead of a sub region because presumably if this is the first update then the entire pixmap is needed anyway and it saves trying to manually allocate an XImage at the right size */ tex_pixmap->image = XGetImage (display, tex_pixmap->pixmap, 0, 0, tex_pixmap->width, tex_pixmap->height, AllPlanes, ZPixmap); image = tex_pixmap->image; src_x = x; src_y = y; } else { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XShmGetImage", tex_pixmap); /* Create a temporary image using the beginning of the shared memory segment and the right size for the region we want to update. We need to reallocate the XImage every time because there is no XShmGetSubImage. */ image = XShmCreateImage (display, tex_pixmap->visual, tex_pixmap->depth, ZPixmap, NULL, &tex_pixmap->shm_info, width, height); image->data = tex_pixmap->shm_info.shmaddr; src_x = 0; src_y = 0; XShmGetImage (display, tex_pixmap->pixmap, image, x, y, AllPlanes); } } else { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetSubImage", tex_pixmap); image = tex_pixmap->image; src_x = x; src_y = y; XGetSubImage (display, tex_pixmap->pixmap, x, y, width, height, AllPlanes, ZPixmap, image, x, y); } /* xlib doesn't appear to fill in image->{red,green,blue}_mask so this just assumes that the image is stored as ARGB from most significant byte to to least significant. If the format is little endian that means the order will be BGRA in memory */ switch (image->bits_per_pixel) { default: case 32: { /* If the pixmap is actually non-packed-pixel RGB format then the texture would have been created in RGB_888 format so Cogl will ignore the alpha channel and effectively pack it for us */ image_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; /* If the format is actually big endian then the alpha component will come first */ if (image->byte_order == MSBFirst) image_format |= COGL_AFIRST_BIT; } break; case 24: image_format = COGL_PIXEL_FORMAT_RGB_888; break; case 16: /* FIXME: this should probably swap the orders around if the endianness does not match */ image_format = COGL_PIXEL_FORMAT_RGB_565; break; } if (image->bits_per_pixel != 16) { /* If the image is in little-endian then the order in memory is reversed */ if (image->byte_order == LSBFirst) image_format |= COGL_BGR_BIT; } cogl_texture_set_region (tex_pixmap->tex, src_x, src_y, x, y, width, height, image->width, image->height, image_format, image->bytes_per_line, (const guint8 *) image->data); /* If we have a shared memory segment then the XImage would be a temporary one with no data allocated so we can just XFree it */ if (tex_pixmap->shm_info.shmid != -1) XFree (image); memset (&tex_pixmap->damage_rect, 0, sizeof (CoglDamageRectangle)); }
static void clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, gint x, gint y, gint width, gint height) { ClutterX11TexturePixmapPrivate *priv; Display *dpy; XImage *image; char *first_pixel; GError *error = NULL; guint bytes_per_line; char *data; int err_code; char pixel_bpp; gboolean pixel_has_alpha; #if 0 clock_t start_t = clock(); #endif if (!CLUTTER_ACTOR_IS_REALIZED (texture)) return; priv = texture->priv; dpy = clutter_x11_get_default_display(); if (!priv->pixmap) return; if (priv->shminfo.shmid == -1) try_alloc_shm (texture); clutter_x11_trap_x_errors (); if (priv->have_shm) { image = XShmCreateImage(dpy, DefaultVisual(dpy, clutter_x11_get_default_screen()), priv->depth, ZPixmap, NULL, &priv->shminfo, width, height); image->data = priv->shminfo.shmaddr; XShmGetImage (dpy, priv->pixmap, image, x, y, AllPlanes); first_pixel = image->data; } else { if (!priv->image) { priv->image = XGetImage (dpy, priv->pixmap, 0, 0, priv->pixmap_width, priv->pixmap_height, AllPlanes, ZPixmap); if (priv->image) first_pixel = priv->image->data + priv->image->bytes_per_line * y + x * priv->image->bits_per_pixel/8; else { g_warning ("%s: XGetImage() failed", __FUNCTION__); return; } } else { XGetSubImage (dpy, priv->pixmap, x, y, width, height, AllPlanes, ZPixmap, priv->image, x, y); first_pixel = priv->image->data + priv->image->bytes_per_line * y + x * priv->image->bits_per_pixel/8; } image = priv->image; } XSync (dpy, FALSE); if ((err_code = clutter_x11_untrap_x_errors ())) { g_warning ("Failed to get XImage of pixmap: %lx, removing", priv->pixmap); /* safe to assume pixmap has gone away? - therefor reset */ clutter_x11_texture_pixmap_set_pixmap (texture, None); goto free_image_and_return; } if (priv->depth == 24) { bytes_per_line = image->bytes_per_line; data = first_pixel; pixel_bpp = 3; pixel_has_alpha = FALSE; } else if (priv->depth == 16) { bytes_per_line = image->bytes_per_line; data = first_pixel; pixel_bpp = 2; pixel_has_alpha = FALSE; } else if (priv->depth == 32) { bytes_per_line = image->bytes_per_line; data = first_pixel; pixel_bpp = 4; pixel_has_alpha = TRUE; } else goto free_image_and_return; if (!priv->allow_alpha) pixel_has_alpha = FALSE; /* For debugging purposes, un comment to simply generate dummy * pixmap data. (A Green background and Blue cross) */ #if 0 { guint xpos, ypos; if (data_allocated) g_free (data); data_allocated = TRUE; data = g_malloc (width*height*4); bytes_per_line = width *4; for (ypos=0; ypos<height; ypos++) for (xpos=0; xpos<width; xpos++) { char *p = data + width*4*ypos + xpos * 4; guint32 *pixel = (guint32 *)p; if ((xpos > width/2 && xpos <= (width/2) + width/4) || (ypos > height/2 && ypos <= (height/2) + height/4)) *pixel=0xff0000ff; else *pixel=0xff00ff00; } } #endif if (x != 0 || y != 0 || width != priv->pixmap_width || height != priv->pixmap_height) clutter_texture_set_area_from_rgb_data (CLUTTER_TEXTURE (texture), (guint8 *)data, pixel_has_alpha, x, y, width, height, bytes_per_line, pixel_bpp, CLUTTER_TEXTURE_RGB_FLAG_BGR, &error); else clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (texture), (guint8 *)data, pixel_has_alpha, width, height, bytes_per_line, pixel_bpp, CLUTTER_TEXTURE_RGB_FLAG_BGR, &error); if (error) { g_warning ("Error when uploading from pixbuf: %s", error->message); g_error_free (error); } free_image_and_return: if (priv->have_shm) XFree (image); #if 0 clock_t end_t = clock(); int time = (int)((double)(end_t - start_t) * (1000.0 / CLOCKS_PER_SEC)); g_print("clutter-x11-update-area-real(%d,%d,%d,%d) %d bits - %d ms\n",x,y,width,height,priv->depth,time); #endif }
void screenhack_record_anim (record_anim_state *st) { int bytes_per_line = st->xgwa.width * 3; double start_time = double_time(); # ifndef USE_GL Display *dpy = DisplayOfScreen (st->screen); char *data = (char *) st->img->data; /* Under XQuartz we can't just do XGetImage on the Window, we have to go through an intermediate Pixmap first. I don't understand why. Also, the f*****g resize handle shows up as black. God dammit. A workaround for that is to temporarily remove /opt/X11/bin/quartz-wm */ XCopyArea (dpy, st->window, st->p, st->gc, 0, 0, st->xgwa.width, st->xgwa.height, 0, 0); XGetSubImage (dpy, st->p, 0, 0, st->xgwa.width, st->xgwa.height, ~0L, ZPixmap, st->img, 0, 0); /* Convert BGRA to RGB */ { const char *in = st->img->data; char *out = st->img->data; int x, y; int w = st->img->width; int h = st->img->height; for (y = 0; y < h; y++) { const char *in2 = in; for (x = 0; x < w; x++) { *out++ = in2[2]; *out++ = in2[1]; *out++ = in2[0]; in2 += 4; } in += st->img->bytes_per_line; } } # else /* USE_GL */ char *data = st->data2; int y; # ifdef HAVE_JWZGLES # undef glReadPixels /* Kludge -- unimplemented in the GLES compat layer */ # endif /* First OpenGL frame tends to be random data like a shot of my desktop, since it is the front buffer when we were drawing in the back buffer. Leave it black. */ /* glDrawBuffer (GL_BACK); */ if (st->frame_count != 0) glReadPixels (0, 0, st->xgwa.width, st->xgwa.height, GL_RGB, GL_UNSIGNED_BYTE, st->data); /* Flip vertically */ for (y = 0; y < st->xgwa.height; y++) memcpy (data + bytes_per_line * y, st->data + bytes_per_line * (st->xgwa.height - y - 1), bytes_per_line); # endif /* USE_GL */ if (st->frame_count < st->fade_frames) fade_frame (st, (unsigned char *) data, (double) st->frame_count / st->fade_frames); else if (st->frame_count >= st->target_frames - st->fade_frames) fade_frame (st, (unsigned char *) data, (double) (st->target_frames - st->frame_count - 1) / st->fade_frames); # ifdef HAVE_GDK_PIXBUF { const char *type = "png"; char fn[1024]; GError *error = 0; GdkPixbuf *pixbuf; pixbuf = gdk_pixbuf_new_from_data ((guchar *) data, GDK_COLORSPACE_RGB, False, /* alpha */ 8, /* bits per sample */ st->xgwa.width, st->xgwa.height, bytes_per_line, 0, 0); sprintf (fn, "%s-%06d.%s", progname, st->frame_count, type); gdk_pixbuf_save (pixbuf, fn, type, &error, NULL); if (error) { fprintf (stderr, "%s: %s: %s\n", progname, fn, error->message); exit (1); } g_object_unref (pixbuf); } # else /* !HAVE_GDK_PIXBUF */ # error GDK_PIXBUF is required # endif /* !HAVE_GDK_PIXBUF */ # ifndef HAVE_JWXYZ { /* Put percent done in window title */ int pct = 100 * (st->frame_count + 1) / st->target_frames; if (pct != st->pct && st->title) { double end = st->target_frames / (double) st->fps; double secs0 = double_time() - st->start_time; double secs = double_timewarp() - st->start_time; double rate = secs / secs0; double secs2 = (end - secs) / rate; Display *dpy = DisplayOfScreen (st->screen); char *t2 = (char *) malloc (strlen(st->title) + 100); if (secs2 < 0) secs2 = 0; sprintf (t2, "%s: %3d%% done," " %d:%02d:%02d in" " %d:%02d:%02d;" " %d%% speed," " %d:%02d:%02d remaining", st->title, pct, ((int) secs) / (60*60), (((int) secs) / 60) % 60, ((int) secs) % 60, ((int) secs0) / (60*60), (((int) secs0) / 60) % 60, ((int) secs0) % 60, (int) (100 * rate), ((int) secs2) / (60*60), (((int) secs2) / 60) % 60, ((int) secs2) % 60 ); XStoreName (dpy, st->window, t2); XSync (dpy, 0); free (t2); st->pct = pct; } } # endif /* !HAVE_JWXYZ */ if (++st->frame_count >= st->target_frames) screenhack_record_anim_free (st); recanim_time_warp += double_time() - start_time; }