/* * browse.c -- Enfle main browsing loop * (C)Copyright 1999, 2000 by Hiroshi Takekawa * This file is part of Enfle. * * Last Modified: Mon Jan 29 09:17:39 2001. * $Id: browse.c,v 1.33 2001/01/29 00:31:30 sian Exp $ * * Enfle 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; either version 2 of the License, or * (at your option) any later version. * * Enfle 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 "enfle.h" #include "action.h" #include "archive.h" #include "plugin.h" #include "utils.h" #include "render.h" #include "dlist.h" #if HAVE_UNISTD_H # include # include #endif #include #include /* delete and return next */ static Dlist_data * delete_from_list(Dlist *p, Dlist_data *t) { Dlist_data *u; u = t->next; if (!dlist_delete(p, t, 1)) { fprintf(stderr, "Dlist error: attempt to delete null data\n"); exit(1); } return u; } int browse_load_image(Info *info, Binfo *binfo, Image *p) { int c; info->swidth = info->sheight = 0; if ((c = load_image(info, p)) == PROC_NOT) { if (binfo->if_warning) fprintf(stderr, "Not supported format %s, skipping...\n", info->filename); return 0; } else if (c == PROC_ERROR) { fprintf(stderr, "Error occurred during loading %s(Format %s), skipping...\n", info->filename, info->format); return 0; } else if (info->format == NULL) { fprintf(stderr, "enfle: %s: info->format is unset.\n", info->filename); return 0; } else if (p->type == _UNKNOWN) { fprintf(stderr, "enfle: %s: p->type is unset.\n", info->filename); return 0; } else if (p->bytes_per_line == 0) { fprintf(stderr, "enfle: %s: p->bytes_per_line is unset.\n", info->filename); return 0; } if ((info->swidth && !info->sheight) || (!info->swidth && info->sheight)) { fprintf(stderr, "enfle: %s: Invalid screen size %d %d\n", info->filename, info->swidth, info->sheight); return 0; } info->mswidth = info->swidth; info->msheight = info->sheight; return 1; } int browse_save_image(Info *info, Binfo *binfo, Image *p, char *format, char *ext) { char *new, *s, *base = get_basename(info->filename), buf[7]; int f, l, fe = 0; if (!strcmp(info->format, format)) return 1; if (ext == NULL) { string_tolower(ext = strdup(format)); fe = 1; } s = strrchr(base, '.'); l = (s == NULL) ? strlen(base) : s - base; new = malloc((info->ar->nfiles > 1) ? (l + 6 + 1 + strlen(ext) + 1) : (l + 1 + strlen(ext) + 1)); strncpy(new, base, l); new[l] = '\0'; if (info->ar->nfiles > 1) { sprintf(buf, "-%05d", info->index + 1); strcat(new, buf); } strcat(new, "."); strcat(new, ext); f = save_image(format, info, p, new); free(new); if (fe) free(ext); return f; } static void enfle_archive_close(Info *info) { archive_close(info->ar); info->ar = NULL; } static void set_info_string(Info *info, Binfo *binfo, Image *p) { char *s = binfo->info_string; char buf[INFO_STRING_LENGTH]; char d = binfo->direction == _FORWARD ? (binfo->interpolate_method == _NONE ? '>' : ')') : (binfo->interpolate_method == _NONE ? '<' : '('); if (info->ar->nfiles > 1) sprintf(s, "%c%d/%d(%s) ", d, info->index + 1, info->ar->nfiles, info->ar->format); else sprintf(s, "%c%d/%d ", d, binfo->current_file, binfo->nfiles); if (info->npics > 1) { sprintf(buf, "%d cells ", info->npics); strcat(s, buf); } if (strlen(s) + strlen(info->filename) + 1 + strlen(info->format) + 1 + 1 < INFO_STRING_LENGTH) { sprintf(buf, "%s(%s) ", info->filename, info->format); strcat(s, buf); sprintf(buf, "(%d, %d)", p->width, p->height); if (strlen(s) + strlen(buf) + 1 < INFO_STRING_LENGTH) strcat(s, buf); } } static void put_info_string(Info *info, Binfo *binfo, char *str) { int h = (info->xheight >= binfo->vheight) ? binfo->vheight : info->xheight; XFontStruct *fs = XQueryFont(info->disp, binfo->info_string_font); int x = (binfo->swidth - XTextWidth(fs, str, strlen(str))) >> 1; int y = binfo->y_offset + h + 12; if (x < 0) x = 0; if (y < binfo->sheight) XDrawString(info->disp, info->win, info->gc, x, y, str, strlen(str)); } static void show_info_string(Info *info, Binfo *binfo) { if (binfo->if_fullscreen) put_info_string(info, binfo, binfo->info_string); } static void erase_info_string(Info *info, Binfo *binfo) { if (binfo->if_fullscreen) { int h = (info->xheight >= binfo->vheight) ? binfo->vheight : info->xheight; XFontStruct *fs = XQueryFont(info->disp, binfo->info_string_font); int w = XTextWidth(fs, binfo->info_string, strlen(binfo->info_string)); int x = (binfo->swidth - w) >> 1; int y = binfo->y_offset + h + 12; if (x < 0) x = 0; if (y < binfo->sheight) XClearArea(info->disp, info->win, x, y - fs->ascent, w, fs->ascent + fs->descent, False); } } static int get_coord(Info *info, Window xw, int *x_return, int *y_return) { Window root, parent, *children; unsigned int nc, w, h, bw, depth; parent = xw; do { xw = parent; if (!XQueryTree(info->disp, xw, &root, &parent, &children, &nc)) return 0; if (children != NULL) XFree(children); } while (parent != root); if (!XGetGeometry(info->disp, xw, &root, x_return, y_return, &w, &h, &bw, &depth)) return 0; return 1; } void browse_resize_window(Info *info, Binfo *binfo, Image *p) { int x, y, mx, my; set_info_string(info, binfo, p); if (!binfo->if_fullscreen) { if (!get_coord(info, info->win, &x, &y)) return; mx = x; my = y; if (binfo->vwidth + x >= binfo->swidth) mx = binfo->vwidth >= binfo->swidth ? 0 : binfo->swidth - binfo->vwidth; if (binfo->vheight + y >= binfo->sheight) my = binfo->vheight >= binfo->sheight ? 0 : binfo->sheight - binfo->vheight; if (x < 0) mx = 0; if (y < 24) my = 24; if (mx != x || my != y) XMoveResizeWindow(info->disp, info->win, mx, my, binfo->vwidth, binfo->vheight); else XResizeWindow(info->disp, info->win, binfo->vwidth, binfo->vheight); XStoreName(info->disp, info->win, binfo->info_string); } XSync(info->disp, True); } void browse_calculate_view_window(Binfo *binfo, Image *p) { int width = p->left + p->width; int height = p->top + p->height; if (binfo->if_fullscreen) { binfo->vwidth = binfo->swidth; binfo->vheight = binfo->sheight; binfo->x_offset = (width < binfo->swidth) ? (binfo->swidth - width) >> 1 : 0; binfo->y_offset = (height < binfo->sheight) ? (binfo->sheight - height) >> 1 : 0; } else { binfo->vwidth = (width > binfo->swidth - WIDTH_CUT) ? binfo->swidth - WIDTH_CUT : width; binfo->vheight = (height > binfo->sheight - HEIGHT_CUT) ? binfo->sheight - HEIGHT_CUT : height; binfo->x_offset = binfo->y_offset = 0; } binfo->w_scroll = (width > binfo->vwidth) ? width - binfo->vwidth : 0; binfo->h_scroll = (height > binfo->vheight) ? height - binfo->vheight : 0; } static Pixmap prepare_pixmap(Info *info, Binfo *binfo, Image *p, int f) { XImage *ximage = render_image(info, binfo, p, f); Pixmap pix; if (ximage == NULL) return -1; pix = XCreatePixmap(info->disp, info->win, info->xwidth, info->xheight, info->depth); XPutImage(info->disp, pix, info->gc, ximage, 0, 0, 0, 0, info->xwidth, info->xheight); ximage->data = NULL; render_destroy_ximage(ximage); return pix; } static void clean_pixmap_list(Info *info, Dlist *pixmap_list) { Dlist_data *p; for (p = dlist_gettop(pixmap_list); p; p = p->next) { Pixmap pix = (Pixmap)p->data; XFreePixmap(info->disp, pix); } dlist_destroy(pixmap_list, 0); } static int prepare_pixmap_list(Info *info, Binfo *binfo, Image *p, int f) { Pixmap pix; if (binfo->pixmap_list) clean_pixmap_list(info, binfo->pixmap_list); binfo->pixmap_list = dlist_create(); while (p) { if (p->image_disposal == _RESTOREBACKGROUND && info->xdata != NULL) memset(info->xdata, p->background.index, info->xdata_size); if ((pix = prepare_pixmap(info, binfo, p, f)) == -1) return 0; f = 1; dlist_add(binfo->pixmap_list, (void *)pix); p = p->next; } binfo->pixmap_list_current = dlist_gettop(binfo->pixmap_list); binfo->pix = (Pixmap)binfo->pixmap_list_current->data; return 1; } void browse_show_image(Info *info, Binfo *binfo) { int w, h; w = (info->xwidth >= binfo->vwidth) ? binfo->vwidth : info->xwidth; h = (info->xheight >= binfo->vheight) ? binfo->vheight : info->xheight; XCopyArea(info->disp, binfo->pix, info->win, info->gc, 0, 0, w, h, binfo->x_offset, binfo->y_offset); show_info_string(info, binfo); } void browse_refresh(Info *info, Binfo *binfo, Image *p, int f) { if (!prepare_pixmap_list(info, binfo, p, f)) { fprintf(stderr, "prepare_pixmap_list() failed.\n"); return; } browse_calculate_view_window(binfo, p); browse_resize_window(info, binfo, p); browse_show_image(info, binfo); } int browse_magnify(Info *info, Binfo *binfo, Image *p) { double s = 1.0, ws, hs; int f; switch (binfo->if_magnify) { case 1: s = MAGNIFICATION; break; case 3: /* Place before 2 */ if (p->width < binfo->swidth - WIDTH_CUT && p->height < binfo->sheight - HEIGHT_CUT) return 1; case 2: ws = (double)(binfo->swidth - WIDTH_CUT) / p->width; hs = (double)(binfo->sheight - HEIGHT_CUT) / p->height; s = (ws * p->height > (binfo->sheight - HEIGHT_CUT)) ? hs : ws; break; case 4: ws = (double)(binfo->swidth - WIDTH_CUT) / p->width; hs = (double)(binfo->sheight - HEIGHT_CUT) / p->height; s = (ws * p->height > (binfo->sheight - HEIGHT_CUT)) ? ws : hs; break; } f = image_magnify(p, s, binfo->interpolate_method); info->mswidth = info->swidth * s; info->msheight = info->sheight * s; return f; } void browse_set_wallpaper(Info *info, Binfo *binfo, Image *p) { XSetWindowBackgroundPixmap(info->disp, info->root, binfo->pix); XClearWindow(info->disp, info->root); } void browse_create_thumbnail(Info *info, Binfo *binfo, Image *p, Dlist_data *t) { int n, c, f = 0, tx, ty; Image *thumbnails, *ip; Dlist_data *tp = t; Archive *ar_save = info->ar; XDefineCursor(info->disp, info->win, info->wait_cursor); XFlush(info->disp); if ((thumbnails = image_create(THUMB_WIDTH, THUMB_HEIGHT, _RGB24)) == NULL) return; n = 0; for (ty = 0; ty <= THUMB_HEIGHT - THUMB_SIZE && tp != NULL && n < THUMB_MAXFILES; ty += THUMB_SIZE + THUMB_INTERVAL) { for (tx = 0; tx <= THUMB_WIDTH - THUMB_SIZE && tp != NULL && n < THUMB_MAXFILES;) { if ((ip = image_allocate()) == NULL) { image_destroy(thumbnails); break; } info->filename = tp->data; info->ar = archive_open(info->pluginlist, info->filename); if ((c = load_image(info, ip)) == PROC_NOT || c == PROC_ERROR) { tp = tp->next; continue; } archive_close(info->ar); switch (ip->type) { case _INDEX: case _RGB16: (void)image_expand(ip, _RGB24); break; case _RGB24: break; default: image_destroy(ip); continue; } if (!(f = ip->width > ip->height ? image_magnify_generic(ip, THUMB_SIZE, ip->height * THUMB_SIZE / ip->width, binfo->interpolate_method) : image_magnify_generic(ip, ip->width * THUMB_SIZE / ip->height, THUMB_SIZE, binfo->interpolate_method))) { image_destroy(ip); image_destroy(thumbnails); break; } image_copy(ip, thumbnails, tx, ty); image_destroy(ip); tp = tp->next; tx += THUMB_SIZE + THUMB_INTERVAL; n++; } if (!f) break; } if (n > 0) { image_destroy(p); p = info->shown_image = info->top_image = thumbnails; p->ncolors = 257; info->filename = "Thumbnail"; browse_refresh(info, binfo, p, 0); } else image_destroy(thumbnails); info->ar = ar_save; XDefineCursor(info->disp, info->win, info->normal_cursor); } /* main browsing loop */ void main_loop(Dlist *dp, Info *info, Binfo *binfo) { XEvent ev; Image *p = NULL; Event event; Dlist_data *t = dlist_gettop(dp); int c = 0, mx, my; int old_w_offset = 0, old_h_offset = 0, ox = 0, oy = 0; int if_mapped = 0; info->ar = NULL; binfo->pixmap_list = NULL; binfo->x_prev = binfo->y_prev = -1; binfo->nfiles = dlist_getndata(dp); binfo->current_file = 1; binfo->direction = _FORWARD; event = _LOAD; while (t != NULL) { switch (event) { case _LOAD: if (!binfo->if_convert) { XDefineCursor(info->disp, info->win, info->wait_cursor); XFlush(info->disp); } if ((info->image = image_allocate()) == NULL) { fprintf(stderr, "No enough memory for info->image\n"); exit(1); } info->filename = t->data; info->if_animated = 0; info->rerender = RERENDER_NONE; info->handler.alarmoff = NULL; info->handler.destroy = NULL; p = NULL; if (info->ar == NULL && (info->ar = archive_open(info->pluginlist, info->filename)) == NULL) { fprintf(stderr, "Error occurred in archive_open()\n"); c = 1; event = _NEXT; break; } if (!archive_select(info->ar, info->index)) { fprintf(stderr, "Error occurred in archive_select()\n"); c = 1; info->index = info->ar->nfiles - 1; event = _NEXT; break; } if ((c = browse_load_image(info, binfo, info->image))) { /* XXX */ if (info->npics == 1) image_expand_auto(info->image, info->depth); info->shown_image = info->top_image = p = image_duplicate(info->image); if (p->width <= binfo->x_threshold || p->height <= binfo->y_threshold) { if (info->ar->nfiles > 1) { if (binfo->if_warning) fprintf(stderr, "%s-%d: Image size is (%d, %d) skipped\n", info->filename, info->index + 1, p->width, p->height); } else { if (binfo->if_warning) fprintf(stderr, "%s: Image size is (%d, %d) skipped\n", info->filename, p->width, p->height); } c = 0; } } if (!c) { event = (binfo->direction == _FORWARD) ? _NEXT : _PREV; break; } if (binfo->if_comment && info->comment) printf("%s:\n%s\n", info->filename, info->comment); #ifdef DEBUG fprintf(stderr, "%s: (%d, %d) - (%d, %d)\n", info->filename, p->left, p->top, p->left + p->width, p->top + p->height); #endif if (binfo->if_magnify) browse_magnify(info, binfo, info->top_image); if (binfo->if_wallpaper) { if (!prepare_pixmap_list(info, binfo, p, 0)) { fprintf(stderr, "prepare_pixmap_list() failed.\n"); return; } browse_set_wallpaper(info, binfo, p); event = _END; break; } if (!binfo->if_convert) { if (binfo->if_fullscreen && (binfo->x_prev > p->width || binfo->y_prev > p->height)) XClearWindow(info->disp, info->win); browse_refresh(info, binfo, p, 0); if (!if_mapped) { XMapWindow(info->disp, info->win); if_mapped++; } if (info->handler.alarmset != NULL) (*info->handler.alarmset)(info); ox = oy = -1; old_w_offset = old_h_offset = 0; binfo->w_offset = binfo->h_offset = 0; XDefineCursor(info->disp, info->win, info->normal_cursor); event = _NOTHING; } else { if (browse_save_image(info, binfo, p, binfo->conv_format, NULL)) { if (binfo->if_warning) printf("%s saved\n", info->filename); } else fprintf(stderr, "%s save failed\n", info->filename); event = _NEXT; } break; case _NOTHING: { int ret; int x_fd = ConnectionNumber(info->disp); fd_set read_fds, write_fds, except_fds; struct timeval timeout; while (event == _NOTHING) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&except_fds); FD_SET(x_fd, &read_fds); timeout.tv_sec = 0; timeout.tv_usec = 50; if ((ret = select(getdtablesize(), &read_fds, &write_fds, &except_fds, &timeout)) < 0) { if (errno == 4) continue; fprintf(stderr, "main_loop: select returns %d: errno = %d\n", ret, errno); perror("enfle: main_loop: "); event = _END; break; } while (XCheckMaskEvent(info->disp, MAIN_WIN_MASK, &ev) == True) { switch (ev.type) { case Expose: { XExposeEvent *xev = (XExposeEvent *)&ev; Region region = XCreateRegion(); XRectangle rect; do { rect.x = xev->x; rect.y = xev->y; rect.width = xev->width; rect.height = xev->height; XUnionRectWithRegion(&rect, region, region); } while (XCheckWindowEvent(info->disp, info->win, ExposureMask, (XEvent *)xev)); XClipBox(region, &rect); XSetRegion(info->disp, info->gc, region); XCopyArea(info->disp, binfo->pix, info->win, info->gc, rect.x + binfo->w_offset, rect.y + binfo->h_offset, rect.width, rect.height, rect.x + binfo->x_offset, rect.y + binfo->y_offset); show_info_string(info, binfo); XSync(info->disp, False); XSetClipMask(info->disp, info->gc, None); XDestroyRegion(region); } break; case ButtonPress: switch (ev.xbutton.button) { case Button1: binfo->pressed = 1; break; case Button2: binfo->pressed = 2; break; case Button3: binfo->pressed = 3; break; case Button4: binfo->pressed = 4; break; case Button5: binfo->pressed = 5; break; } if (ev.xbutton.button == 1) ox = oy = -1; break; case ButtonRelease: switch (ev.xbutton.button) { case Button1: if (binfo->pressed == 1) event = _NEXT; break; case Button2: if (binfo->pressed == 2) event = _END; break; case Button3: if (binfo->pressed == 3) event = _PREV; break; case Button4: if (binfo->pressed == 4) event = _NEXT; break; case Button5: if (binfo->pressed == 5) event = _PREV; break; } break; case KeyPress: { char c; KeySym keysym; XLookupString((XKeyEvent *)&ev, &c, 1, &keysym, NULL); event = action_by_key(binfo->act_hash, keysym, ev.xkey.state & (ShiftMask | ControlMask | Mod1Mask), info, binfo, p, t); break; } case MotionNotify: if (ev.xmotion.state & Button1Mask) { XMotionEvent *xev = (XMotionEvent *)&ev; if (ox != -1 && oy != -1) { mx = xev->x - ox; my = xev->y - oy; } else mx = my = 0; ox = xev->x; oy = xev->y; if (my != 0) { binfo->pressed = -1; binfo->h_offset += my; if (binfo->h_offset < 0) binfo->h_offset = 0; else if (binfo->h_offset > binfo->h_scroll) binfo->h_offset = binfo->h_scroll; } if (mx != 0) { binfo->pressed = 0; binfo->w_offset += mx; if (binfo->w_offset < 0) binfo->w_offset = 0; else if (binfo->w_offset > binfo->w_scroll) binfo->w_offset = binfo->w_scroll; } if (binfo->h_offset != old_h_offset || binfo->w_offset != old_w_offset) { XCopyArea(info->disp, binfo->pix, info->win, info->gc, binfo->w_offset, binfo->h_offset, binfo->vwidth, binfo->vheight, binfo->x_offset, binfo->y_offset); show_info_string(info, binfo); } old_h_offset = binfo->h_offset; old_w_offset = binfo->w_offset; } break; case ConfigureNotify: { XConfigureEvent *xev = (XConfigureEvent *)&ev; if (!info->if_animated && (binfo->vwidth != xev->width || binfo->vheight != xev->height) && (image_magnify_generic(p, xev->width, xev->height, binfo->interpolate_method))) { binfo->vwidth = xev->width; binfo->vheight = xev->height; info->mswidth = xev->width; info->msheight = xev->height; binfo->h_scroll = binfo->w_scroll = 0; browse_refresh(info, binfo, p, 0); } } break; case VisibilityNotify: if (binfo->if_fullscreen) { XVisibilityEvent *xev = (XVisibilityEvent *)&ev; if (xev->state == VisibilityPartiallyObscured) XRaiseWindow(info->disp, info->win); else if (xev->state == VisibilityUnobscured) browse_show_image(info, binfo); } break; default: break; } } if (info->if_animated && info->rerender != RERENDER_NONE) { while (info->rerender != RERENDER_NONE) { switch (info->rerender) { case RERENDER_FIRST: binfo->pixmap_list_current = dlist_gettop(binfo->pixmap_list); binfo->pix = (Pixmap)binfo->pixmap_list_current->data; info->shown_image = info->top_image; info->rerender = RERENDER_REDRAW; break; case RERENDER_NEXT: if ((binfo->pixmap_list_current = binfo->pixmap_list_current->next) == NULL) info->rerender = RERENDER_FIRST; else { binfo->pix = (Pixmap)binfo->pixmap_list_current->data; info->shown_image = info->shown_image->next; info->rerender = RERENDER_REDRAW; } break; case RERENDER_REDRAW: browse_show_image(info, binfo); info->rerender = RERENDER_NONE; break; default: fprintf(stderr, "Rerender method %d unknown\n", info->rerender); info->rerender = RERENDER_ERROR; break; } if (info->rerender == RERENDER_ERROR) break; } if (info->handler.alarmset != NULL) (*info->handler.alarmset)(info); } } break; } case _NEXT: if (info->index + 1 == info->ar->nfiles) { info->index = 0; t = (c || info->ar->nfiles > 1) ? t->next : delete_from_list(dp, t); enfle_archive_close(info); binfo->current_file++; } else info->index++; binfo->direction = _FORWARD; event = _CHANGE; break; case _NEXTDIR: { char *pathdir = get_pathdir(t->data); char *tpd = NULL; int f = 1; while (f) { t = t->next; if (t == NULL) f = 0; else { binfo->current_file++; tpd = get_pathdir(t->data); if (strcmp(pathdir, tpd)) { enfle_archive_close(info); f = 0; } free(tpd); } } free(pathdir); } event = (t != NULL) ? _CHANGE : _END; break; case _PREV: if (info->index > 0) info->index--; else if (t != dlist_gettop(dp)) { enfle_archive_close(info); t = t->prev; binfo->current_file--; } binfo->direction = _BACKWARD; event = _CHANGE; break; case _TOP: enfle_archive_close(info); t = dlist_gettop(dp); binfo->current_file = 1; info->index = 0; event = _CHANGE; break; case _DELETE: enfle_archive_close(info); t = delete_from_list(dp, t); info->index = 0; binfo->nfiles--; event = _CHANGE; break; case _CHANGE: if (info->handler.alarmoff != NULL) (*info->handler.alarmoff)(); if (info->handler.destroy != NULL) (*info->handler.destroy)(info); if (binfo->pixmap_list) { clean_pixmap_list(info, binfo->pixmap_list); binfo->pixmap_list = NULL; } #ifdef SHAPE if (p && p->pixmask != -1) { XFreePixmap(info->disp, p->pixmask); XShapeCombineMask(info->disp, info->win, ShapeBounding, 0, 0, None, ShapeSet); p->pixmask = -1; } #endif erase_info_string(info, binfo); if (info->top_image) { /* save image size to determine clear full-screen window later */ binfo->x_prev = p->width; binfo->y_prev = p->height; image_destroy(info->top_image); info->top_image = NULL; } image_destroy(info->image); if (info->comment) { free(info->comment); info->comment = NULL; } info->image = NULL; event = _LOAD; break; case _END: enfle_archive_close(info); t = NULL; break; default: fprintf(stderr, "Unknown event %d\n", event); exit(1); } } if (info->handler.alarmoff != NULL) (*info->handler.alarmoff)(); if (info->handler.destroy != NULL) (*info->handler.destroy)(info); if (binfo->pixmap_list) clean_pixmap_list(info, binfo->pixmap_list); #ifdef SHAPE if (p && p->pixmask != -1) XFreePixmap(info->disp, p->pixmask); #endif if (info->xdata != NULL) render_free_ximage(info, binfo); info->xdata = NULL; image_destroy(info->top_image); info->top_image = NULL; image_destroy(info->image); info->image = NULL; if (info->comment) free(info->comment); info->comment = NULL; if (info->gc != NULL) XFreeGC(info->disp, info->gc); info->gc = NULL; if (if_mapped) XUnmapWindow(info->disp, info->win); if (!binfo->if_convert) { XDestroyWindow(info->disp, info->win); XCloseDisplay(info->disp); } }