コード例 #1
0
ファイル: main.c プロジェクト: decklin/feh
void feh_clean_exit(void)
{
	D_ENTER(4);

	delete_rm_files();

	if (opt.filelistfile)
		feh_write_filelist(filelist, opt.filelistfile);

	D_RETURN_(4);
}
コード例 #2
0
ファイル: main.c プロジェクト: decklin/feh
int main(int argc, char **argv)
{
	D_ENTER(4);
	atexit(feh_clean_exit);

	init_parse_options(argc, argv);

	init_imlib_fonts();

	if (opt.display)
		init_x_and_imlib();

	feh_event_init();

	if (opt.index)
		init_index_mode();
	else if (opt.collage)
		init_collage_mode();
	else if (opt.multiwindow)
		init_multiwindow_mode();
	else if (opt.list || opt.customlist)
		init_list_mode();
	else if (opt.loadables)
		init_loadables_mode();
	else if (opt.unloadables)
		init_unloadables_mode();
	else if (opt.thumbs)
		init_thumbnail_mode();
	else if (opt.bgmode) {
		feh_wm_set_bg_file(opt.output_file, opt.bgmode);
		exit(0);
	}
	else {
		/* Slideshow mode is the default. Because it's spiffy */
		opt.slideshow = 1;
		init_slideshow_mode();
	}

	/* main event loop */
	while (feh_main_iteration(1));

	D_RETURN(4, 0);
}
コード例 #3
0
ファイル: keyevents.c プロジェクト: decklin/feh
void feh_event_invoke_action(winwidget winwid, char *action)
{
	D_ENTER(4);
	D(4, ("action is '%s'\n", action));
	D(4, ("winwid is '%p'\n", winwid));
	if (action) {
		if (opt.slideshow) {
			feh_action_run(FEH_FILE(winwid->file->data), action);
			slideshow_change_image(winwid, SLIDE_NEXT);
		} else if ((winwid->type == WIN_TYPE_SINGLE)
				|| (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)) {
			feh_action_run(FEH_FILE(winwid->file->data), action);
			winwidget_destroy(winwid);
		} else if (winwid->type == WIN_TYPE_THUMBNAIL) {
			printf("actions from the main thumb window aren't currentl supported!\n");
			printf("For now, open the image to perform the action on it.\n");
		}
	}
	D_RETURN_(4);
}
コード例 #4
0
ファイル: ExpTree.cpp プロジェクト: aolko/construct
void ExpDot::Evaluate(ExpReturn* er)
{
	// Next exp stack depth
	//pRuntime->curExpStackDepth++;
	//pRuntime->ExpReturnStack[pRuntime->curExpStackDepth] = er;

	// Parameters exist?  Evaluate them
	if (hasParameters) {

		ExpReturn* expPtr = expParamList;
		ExpPart** curParam = parameters;

		// Evaluate every parameter
		for ( ; curParam != paramsEnd; curParam++)

			// Send to address of corresponding expParamList array entry
			(*curParam)->Evaluate(expPtr++);
	}

	CRunObject* objToCall;

	// Undefined expression call?
	if (unnamedExp) {

		if (this->oid == pCExp->oidCaller)
			objToCall = pCExp->pSelectedObject;
		else {
			SelObjList& rSol = *(pType->pSol);
			if (rSol.selectAll)
				objToCall = pTypeInstances->operator []((pCExp->SolID) % pTypeInstances->size());
			else
				objToCall = rSol.sol[(pCExp->SolID) % rSol.sol.size()];
		}

		objToCall->ReturnUndefinedExpression(fname, expParamList, *er);

		// Decrement the stack depth (call complete)
		//pRuntime->curExpStackDepth--;
		return;
	}

	if (isCallerOid || pCExp->overrideCalledOID) {

		// Call the owner's expression routine
		objToCall = pCExp->pSelectedObject;

		// Still NULL?
		if (objToCall == NULL) {
			if (pType->pSol->selectAll) {

				// No instances
				if (pType->instances.empty()) {
					er->eType = EXPTYPE_INTEGER;
					er->eData.iVal = 0;
					
					// Give a debug warning
#ifdef CONSTRUCT_DEBUGGER
					CString msg;
					msg.Format("Expression '%s': no '%s' objects exist: returning 0", fname, pRuntime->objects[oid]->Name);
					pRuntime->LogMsg(msg);
#endif
					return;
				}

				objToCall = pType->instances.front();
			}
			else if (!(pType->pSol->sol.empty()))
				objToCall = pType->pSol->sol.front();
		}

	}
	else {

		SelObjList& rSol = *(pType->pSol);

		// Call the routine for the paired instance
		if (rSol.selectAll) {

			if (pTypeInstances->size() > 0)

				// SOL index refers to instance list if all selected
				objToCall = pTypeInstances->operator []((pCExp->SolID) % pTypeInstances->size());

			// Zero objects and asking for an expression!  Ouch!  Return 0 for now
			else {
				er->eType = EXPTYPE_INTEGER;
				er->eData.iVal = 0;
				
					// Give a debug warning
#ifdef CONSTRUCT_DEBUGGER
				CString msg;
				msg.Format("Expression '%s': no '%s' objects exist: returning 0", fname, pRuntime->objects[oid]->Name);
				pRuntime->LogMsg(msg);
#endif
				return;
			}
		}

		else

			// Use index to the SOL for pairing
			objToCall = rSol.sol[(pCExp->SolID) % rSol.sol.size()];
	
	}//else

	D_ENTER(DCS_EXPRESSION, objToCall);

	// Override the object type in case a family expression
	// (causes bugs... best leave out)
	//CRunObjType* oldType = objToCall->pType;
	//objToCall->pType = this->pType;

	// Do call
	(objToCall->*expRoutine)(expParamList, *er);

	// Restore type
	//objToCall->pType = oldType;

	D_RUNTIME();

	// Decrement the stack depth (call complete)
	//pRuntime->curExpStackDepth--;
}
コード例 #5
0
ファイル: ExpTree.cpp プロジェクト: aolko/construct
/////////////
// ExpIdent
void ExpIdent::Evaluate(ExpReturn* er)
{
	// Set the expression return location
	//pRuntime->curExpStackDepth++;
	//pRuntime->ExpReturnStack[pRuntime->curExpStackDepth] = er;

	// Parameters exist?  Evaluate them
	if (hasParameters) {

		ExpReturn* expPtr = expParamList;
		ExpPart** curParam = parameters;

		// Evaluate every parameter
		for ( ; curParam != paramsEnd; curParam++)

			// Send to address of corresponding expParamList array entry
			(*curParam)->Evaluate(expPtr++);
	}

	// System call?
	if (this->pType == NULL) {

		D_ENTER(DCS_EXPRESSION, pSystemObject);

		(pSystemObject->*routine)(expParamList, *er);

		D_RUNTIME();
	}
	else {

		CRunObject* objToCall;

		// OID of caller is the OID of this expression call?
		if (this->oid == pCExp->oidCaller || pCExp->overrideCalledOID) {

			// Call the owner's expression routine
			objToCall = pCExp->pSelectedObject;

			// Still NULL?
			if (objToCall == NULL) {
				if (pType->pSol->selectAll)
					objToCall = pType->instances.front();
				else if (!(pType->pSol->sol.empty()))
					objToCall = pType->pSol->sol.front();
			}

		}

		else {

			SelObjList& rSol = *(pType->pSol);

			// Call the routine for the paired instance
			if (rSol.selectAll) {

				if (pTypeInstances->size() > 0)

					// SOL index refers to instance list if all selected
					objToCall = pTypeInstances->operator []((pCExp->SolID) % pTypeInstances->size());

				// No objects to call!  Return zero!
				// TODO - best solution?
				else {
					er->eType = EXPTYPE_INTEGER;
					er->eData.iVal = 0;
					
					// Give a debug warning
#ifdef CONSTRUCT_DEBUGGER
					CString msg;
					msg.Format("Expression '%s': no '%s' objects exist: returning 0", ident, ident);
					pRuntime->LogMsg(msg);
#endif
					return;
				}

			}

			else

				// Use index to the SOL for pairing
				objToCall = rSol.sol[(pCExp->SolID) % rSol.sol.size()];
		
		}//else

		// Do the call
		D_ENTER(DCS_EXPRESSION, objToCall);

		objToCall->ReturnDefaultValue(expParamList, *er);

		D_RUNTIME();
	}

	// Roll back the stack depth
	//pRuntime->curExpStackDepth--;
}
コード例 #6
0
ファイル: main.c プロジェクト: decklin/feh
/* Return 0 to stop iterating, 1 if ok to continue. */
int feh_main_iteration(int block)
{
	static int first = 1;
	static int xfd = 0;
	static int fdsize = 0;
	static double pt = 0.0;
	XEvent ev;
	struct timeval tval;
	fd_set fdset;
	int count = 0;
	double t1 = 0.0, t2 = 0.0;
	fehtimer ft;

	D_ENTER(5);

	if (window_num == 0)
		D_RETURN(5, 0);

	if (first) {
		/* Only need to set these up the first time */
		xfd = ConnectionNumber(disp);
		fdsize = xfd + 1;
		pt = feh_get_time();
		first = 0;
	}

	/* Timers */
	t1 = feh_get_time();
	t2 = t1 - pt;
	pt = t1;
	while (XPending(disp)) {
		XNextEvent(disp, &ev);
		if (ev_handler[ev.type])
			(*(ev_handler[ev.type])) (&ev);

		if (window_num == 0)
			D_RETURN(5, 0);
	}
	XFlush(disp);

	feh_redraw_menus();

	FD_ZERO(&fdset);
	FD_SET(xfd, &fdset);

	/* Timers */
	ft = first_timer;
	/* Don't do timers if we're zooming/panning/etc or if we are paused */
	if (ft && (opt.mode == MODE_NORMAL) && !opt.paused) {
		D(5, ("There are timers in the queue\n"));
		if (ft->just_added) {
			D(5, ("The first timer has just been added\n"));
			D(5, ("ft->in = %f\n", ft->in));
			ft->just_added = 0;
			t1 = ft->in;
		} else {
			D(5, ("The first timer was not just added\n"));
			t1 = ft->in - t2;
			if (t1 < 0.0)
				t1 = 0.0;
			ft->in = t1;
		}

		XSync(disp, False);
		D(5, ("I next need to action a timer in %f seconds\n", t1));
		/* Only do a blocking select if there's a timer due, or no events
		   waiting */
		if (t1 == 0.0 || (block && !XPending(disp))) {
			tval.tv_sec = (long) t1;
			tval.tv_usec = (long) ((t1 - ((double) tval.tv_sec)) * 1000000);
			if (tval.tv_sec < 0)
				tval.tv_sec = 0;
			if (tval.tv_usec <= 1000)
				tval.tv_usec = 1000;
			errno = 0;
			D(5, ("Performing blocking select - waiting for timer or event\n"));
			count = select(fdsize, &fdset, NULL, NULL, &tval);
			if ((count < 0)
					&& ((errno == ENOMEM) || (errno == EINVAL)
						|| (errno == EBADF)))
				eprintf("Connection to X display lost");
			if ((ft) && (count == 0)) {
				/* This means the timer is due to be executed. If count was > 0,
				   that would mean an X event had woken us, we're not interested
				   in that */
				feh_handle_timer();
			}
		}
	} else {
		/* Don't block if there are events in the queue. That's a bit rude ;-) */
		if (block && !XPending(disp)) {
			errno = 0;
			D(5, ("Performing blocking select - no timers, or zooming\n"));
			count = select(fdsize, &fdset, NULL, NULL, NULL);
			if ((count < 0)
					&& ((errno == ENOMEM) || (errno == EINVAL)
						|| (errno == EBADF)))
				eprintf("Connection to X display lost");
		}
	}
	if (window_num == 0)
		D_RETURN(5, 0);
	D_RETURN(5, 1);
}
コード例 #7
0
ファイル: collage.c プロジェクト: decklin/feh
void init_collage_mode(void)
{
	Imlib_Image im_main;
	Imlib_Image im_temp;
	int ww, hh, www, hhh, xxx, yyy;
	int w = 800, h = 600;
	int bg_w = 0, bg_h = 0;
	winwidget winwid = NULL;
	Imlib_Image bg_im = NULL, im_thumb = NULL;
	feh_file *file = NULL;
	unsigned char trans_bg = 0;
	gib_list *l, *last = NULL;
	char *s;

	D_ENTER(4);

	mode = "collage";

	/* Use bg image dimensions for default size */
	if (opt.bg && opt.bg_file) {
		if (!strcmp(opt.bg_file, "trans"))
			trans_bg = 1;
		else {

			D(4, ("Time to apply a background to blend onto\n"));
			if (feh_load_image_char(&bg_im, opt.bg_file) != 0) {
				bg_w = gib_imlib_image_get_width(bg_im);
				bg_h = gib_imlib_image_get_height(bg_im);
			}
		}
	}

	if (!opt.limit_w || !opt.limit_h) {
		if (bg_im) {
			if (opt.verbose)
				fprintf(stdout,
					PACKAGE
					" - No size restriction specified for collage.\n"
					" You did specify a background however, so the\n"
					" collage size has defaulted to the size of the image\n");
			opt.limit_w = bg_w;
			opt.limit_h = bg_h;
		} else {
			if (opt.verbose)
				fprintf(stdout,
					PACKAGE
					" - No size restriction specified for collage.\n"
					" - For collage mode, you need to specify width and height.\n"
					" Using defaults (width 800, height 600)\n");
			opt.limit_w = 800;
			opt.limit_h = 600;
		}
	}

	w = opt.limit_w;
	h = opt.limit_h;
	D(4, ("Limiting width to %d and height to %d\n", w, h));

	im_main = imlib_create_image(w, h);

	if (!im_main)
		eprintf("Imlib error creating image");

	if (bg_im)
		gib_imlib_blend_image_onto_image(im_main, bg_im,
				gib_imlib_image_has_alpha(bg_im), 0, 0,
				bg_w, bg_h, 0, 0, w, h, 1, 0, 0);
	else if (trans_bg) {
		gib_imlib_image_fill_rectangle(im_main, 0, 0, w, h, 0, 0, 0, 0);
		gib_imlib_image_set_has_alpha(im_main, 1);
	} else {
		/* Colour the background */
		gib_imlib_image_fill_rectangle(im_main, 0, 0, w, h, 0, 0, 0, 255);
	}

	/* Create the title string */

	if (!opt.title)
		s = estrdup(PACKAGE " [collage mode]");
	else
		s = estrdup(feh_printf(opt.title, NULL));

	if (opt.display) {
		winwid = winwidget_create_from_image(im_main, s, WIN_TYPE_SINGLE);
		winwidget_show(winwid);
	}

	for (l = filelist; l; l = l->next) {
		file = FEH_FILE(l->data);
		if (last) {
			filelist = feh_file_remove_from_list(filelist, last);
			filelist_len--;
			last = NULL;
		}
		D(3, ("About to load image %s\n", file->filename));
		if (feh_load_image(&im_temp, file) != 0) {
			D(3, ("Successfully loaded %s\n", file->filename));
			if (opt.verbose)
				feh_display_status('.');
			www = opt.thumb_w;
			hhh = opt.thumb_h;
			ww = gib_imlib_image_get_width(im_temp);
			hh = gib_imlib_image_get_height(im_temp);

			if (opt.aspect) {
				double ratio = 0.0;

				/* Keep the aspect ratio for the thumbnail */
				ratio = ((double) ww / hh) / ((double) www / hhh);

				if (ratio > 1.0)
					hhh = opt.thumb_h / ratio;
				else if (ratio != 1.0)
					www = opt.thumb_w * ratio;
			}

			if ((!opt.stretch) && ((www > ww) || (hhh > hh))) {
				/* Don't make the image larger unless stretch is specified */
				www = ww;
				hhh = hh;
			}

			/* pick random coords for thumbnail */
			xxx = ((w - www) * ((double) rand() / RAND_MAX));
			yyy = ((h - hhh) * ((double) rand() / RAND_MAX));
			D(5, ("image going on at x=%d, y=%d\n", xxx, yyy));

			im_thumb = gib_imlib_create_cropped_scaled_image(im_temp,
					0, 0, ww, hh, www, hhh, 1);
			gib_imlib_free_image_and_decache(im_temp);

			if (opt.alpha) {
				DATA8 atab[256];

				D(4, ("Applying alpha options\n"));
				gib_imlib_image_set_has_alpha(im_thumb, 1);
				memset(atab, opt.alpha_level, sizeof(atab));
				gib_imlib_apply_color_modifier_to_rectangle(im_thumb,
						0, 0, www, hhh, NULL, NULL, NULL, atab);
			}
			gib_imlib_blend_image_onto_image(im_main, im_thumb,
					gib_imlib_image_has_alpha(im_thumb), 0, 0, www, hhh, xxx,
					yyy,www, hhh, 1, gib_imlib_image_has_alpha(im_thumb), 0);
			gib_imlib_free_image_and_decache(im_thumb);
		} else {
			last = l;
			if (opt.verbose)
				feh_display_status('x');
		}
		if (opt.display) {
			winwidget_render_image(winwid, 0, 0);
			if (!feh_main_iteration(0))
				exit(0);
		}
	}
	if (opt.verbose)
		fprintf(stdout, "\n");

	if (opt.output && opt.output_file) {
		char output_buf[1024];
		if (opt.output_dir)
			snprintf(output_buf, 1024, "%s/%s", opt.output_dir, opt.output_file);
		else
			strncpy(output_buf, opt.output_file, 1024);
		gib_imlib_save_image(im_main, output_buf);
		if (opt.verbose) {
			int tw, th;

			tw = gib_imlib_image_get_width(im_main);
			th = gib_imlib_image_get_height(im_main);
			fprintf(stdout, PACKAGE " - File saved as %s\n", output_buf);
			fprintf(stdout,
				"    - Image is %dx%d pixels and contains %d thumbnails\n",
				tw, th, (tw / opt.thumb_w) * (th / opt.thumb_h));
		}
	}

	if (!opt.display)
		gib_imlib_free_image_and_decache(im_main);
	free(s);
	D_RETURN_(4);
}
コード例 #8
0
ファイル: keyevents.c プロジェクト: decklin/feh
void feh_event_handle_keypress(XEvent * ev)
{
	int len;
	char kbuf[20];
	KeySym keysym;
	XKeyEvent *kev;
	winwidget winwid = NULL;
	int curr_screen = 0;
	feh_menu_item *selected_item;
	feh_menu *selected_menu;

	D_ENTER(4);

	winwid = winwidget_get_from_window(ev->xkey.window);

	/* nuke dupe events, unless we're typing text */
	if (winwid && !winwid->caption_entry) {
		while (XCheckTypedWindowEvent(disp, ev->xkey.window, KeyPress, ev));
	}

	kev = (XKeyEvent *) ev;
	len = XLookupString(&ev->xkey, (char *) kbuf, sizeof(kbuf), &keysym, NULL);

	/* menus are showing, so this is a menu control keypress */
	if (ev->xbutton.window == menu_cover) {
		selected_item = feh_menu_find_selected_r(menu_root, &selected_menu);
		switch (keysym) {
		case XK_Escape:
			feh_menu_hide(menu_root, True);
			break;
		case XK_Left:
			feh_menu_select_parent(selected_menu, selected_item);
			break;
		case XK_Down:
			feh_menu_select_next(selected_menu, selected_item);
			break;
		case XK_Up:
			feh_menu_select_prev(selected_menu, selected_item);
			break;
		case XK_Right:
			feh_menu_select_submenu(selected_menu, selected_item);
			break;
		case XK_Return:
			feh_menu_item_activate(selected_menu, selected_item);
			break;
		default:
			break;
		}
		if (len <= 0 || len > (int) sizeof(kbuf))
			D_RETURN_(4);
		kbuf[len] = '\0';

		switch (*kbuf) {
		case 'h':
			feh_menu_select_parent(selected_menu, selected_item);
			break;
		case 'j':
			feh_menu_select_next(selected_menu, selected_item);
			break;
		case 'k':
			feh_menu_select_prev(selected_menu, selected_item);
			break;
		case 'l':
			feh_menu_select_submenu(selected_menu, selected_item);
			break;
		case ' ':
			feh_menu_item_activate(selected_menu, selected_item);
			break;
		default:
			break;
		}

		D_RETURN_(4);
	}

	if (winwid == NULL)
		D_RETURN_(4);

	if (winwid->caption_entry) {
		switch (keysym) {
		case XK_Return:
			if (kev->state & ControlMask) {
				/* insert actual newline */
				ESTRAPPEND(FEH_FILE(winwid->file->data)->caption, "\n");
				winwidget_render_image_cached(winwid);
			} else {
				/* finish caption entry, write to captions file */
				FILE *fp;
				char *caption_filename;
				caption_filename = build_caption_filename(FEH_FILE(winwid->file->data));
				winwid->caption_entry = 0;
				winwidget_render_image_cached(winwid);
				XFreePixmap(disp, winwid->bg_pmap_cache);
				winwid->bg_pmap_cache = 0;
				fp = fopen(caption_filename, "w");
				if (!fp) {
					weprintf("couldn't write to captions file %s:", caption_filename);
					D_RETURN_(4);
				}
				fprintf(fp, "%s", FEH_FILE(winwid->file->data)->caption);
				free(caption_filename);
				fclose(fp);
			}
			break;
		case XK_Escape:
			/* cancel, revert caption */
			winwid->caption_entry = 0;
			free(FEH_FILE(winwid->file->data)->caption);
			FEH_FILE(winwid->file->data)->caption = NULL;
			winwidget_render_image_cached(winwid);
			XFreePixmap(disp, winwid->bg_pmap_cache);
			winwid->bg_pmap_cache = 0;
			break;
		case XK_BackSpace:
			/* backspace */
			ESTRTRUNC(FEH_FILE(winwid->file->data)->caption, 1);
			winwidget_render_image_cached(winwid);
			break;
		default:
			if (isascii(keysym)) {
				/* append to caption */
				ESTRAPPEND_CHAR(FEH_FILE(winwid->file->data)->caption, keysym);
				winwidget_render_image_cached(winwid);
			}
			break;
		}
		D_RETURN_(4);
	}

	switch (keysym) {
	case XK_Left:
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_PREV);
		break;
	case XK_Right:
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_NEXT);
		break;
	case XK_Page_Up:
	case XK_KP_Page_Up:
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_JUMP_BACK);
		break;
	case XK_Escape:
		winwidget_destroy_all();
		break;
	case XK_Page_Down:
	case XK_KP_Page_Down:
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_JUMP_FWD);
		break;
	case XK_Delete:
		/* Holding ctrl gets you a filesystem deletion and removal from the * 
		   filelist. Just DEL gets you filelist removal only. */
		if (kev->state & ControlMask) {
			if (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)
				feh_thumbnail_mark_removed(FEH_FILE(winwid->file->data), 1);
			feh_filelist_image_remove(winwid, 1);
		} else {
			if (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)
				feh_thumbnail_mark_removed(FEH_FILE(winwid->file->data), 0);
			feh_filelist_image_remove(winwid, 0);
		}
		break;
	case XK_Home:
	case XK_KP_Home:
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_FIRST);
		break;
	case XK_End:
	case XK_KP_End:
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_LAST);
		break;
	case XK_Return:
		feh_event_invoke_action(winwid, opt.actions[0]);
		break;
	case XK_0:
		feh_event_invoke_action(winwid, opt.actions[0]);
		break;
	case XK_1:
		feh_event_invoke_action(winwid, opt.actions[1]);
		break;
	case XK_2:
		feh_event_invoke_action(winwid, opt.actions[2]);
		break;
	case XK_3:
		feh_event_invoke_action(winwid, opt.actions[3]);
		break;
	case XK_4:
		feh_event_invoke_action(winwid, opt.actions[4]);
		break;
	case XK_5:
		feh_event_invoke_action(winwid, opt.actions[5]);
		break;
	case XK_6:
		feh_event_invoke_action(winwid, opt.actions[6]);
		break;
	case XK_7:
		feh_event_invoke_action(winwid, opt.actions[7]);
		break;
	case XK_8:
		feh_event_invoke_action(winwid, opt.actions[8]);
		break;
	case XK_9:
		feh_event_invoke_action(winwid, opt.actions[9]);
		break;
	case XK_KP_Left:
		winwid->im_x = winwid->im_x - 10;
		winwidget_render_image(winwid, 0, 0);
		break;
	case XK_KP_Right:
		winwid->im_x = winwid->im_x + 10;
		winwidget_render_image(winwid, 0, 0);
		break;
	case XK_KP_Up:
		winwid->im_y = winwid->im_y - 10;
		winwidget_render_image(winwid, 0, 0);
		break;
	case XK_KP_Down:
		winwid->im_y = winwid->im_y + 10;
		winwidget_render_image(winwid, 0, 0);
		break;
	case XK_KP_Add:
		/* erroneously recognized as '+' in the *kbuf switch. Work around this. */
		len = 0;
		winwid->zoom = winwid->zoom * 1.25;
		winwidget_render_image(winwid, 0, 0);
		break;
	case XK_KP_Subtract:
		len = 0;
		winwid->zoom = winwid->zoom * 0.75;
		winwidget_render_image(winwid, 0, 0);
		break;
	case XK_KP_Multiply:
		len = 0;
		winwid->zoom = 1;
		winwidget_render_image(winwid, 0, 0);
		break;
	case XK_KP_Divide:
		len = 0;
		feh_calc_needed_zoom(&winwid->zoom, winwid->im_w, winwid->im_h, winwid->w, winwid->h);
		winwidget_render_image(winwid, 0, 1);
		break;
	case XK_KP_Begin:
		winwidget_render_image(winwid, 0, 1);
		break;
	default:
		break;
	}

	if (len <= 0 || len > (int) sizeof(kbuf))
		D_RETURN_(4);
	kbuf[len] = '\0';

	switch (*kbuf) {
	case 'a':
	case 'A':
		opt.draw_actions = !opt.draw_actions;
		winwidget_rerender_all(0, 1);
		break;
	case 'd':
	case 'D':
		opt.draw_filename = !opt.draw_filename;
		winwidget_rerender_all(0, 1);
		break;
	case 'n':
	case 'N':
	case ' ':
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_NEXT);
		break;
	case 'p':
	case 'P':
	case '\b':
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_PREV);
		break;
	case 'z':
	case 'Z':
		if (opt.slideshow)
			slideshow_change_image(winwid, SLIDE_RAND);
		break;
	case 'q':
	case 'Q':
		winwidget_destroy_all();
		break;
	case 'c':
	case 'C':
		if (opt.caption_path)
			winwid->caption_entry = 1;
		winwidget_render_image(winwid, 0, 1);
		break;
	case 'r':
	case 'R':
		feh_reload_image(winwid, 0, 0);
		break;
	case 'h':
	case 'H':
		slideshow_pause_toggle(winwid);
		break;
	case 's':
	case 'S':
		slideshow_save_image(winwid);
		break;
	case 'f':
	case 'F':
		feh_save_filelist();
		break;
	case 'w':
	case 'W':
		winwidget_size_to_image(winwid);
		break;
	case 'm':
	case 'M':
		winwidget_show_menu(winwid);
		break;
	case 'x':
	case 'X':
		winwidget_destroy(winwid);
		break;
	case '>':
		feh_edit_inplace_orient(winwid, 1);
		break;
	case '<':
		feh_edit_inplace_orient(winwid, 3);
		break;
	case 'v':
	case 'V':
#ifdef HAVE_LIBXINERAMA
		if (opt.xinerama && xinerama_screens) {
			int i, rect[4];

			winwidget_get_geometry(winwid, rect);
			/* printf("window: (%d, %d)\n", rect[0], rect[1]);
			   printf("found %d screens.\n", num_xinerama_screens); */
			for (i = 0; i < num_xinerama_screens; i++) {
				xinerama_screen = 0;
				/* printf("%d: [%d, %d, %d, %d] (%d, %d)\n",
				   i,
				   xinerama_screens[i].x_org, xinerama_screens[i].y_org,
				   xinerama_screens[i].width, xinerama_screens[i].height,
				   rect[0], rect[1]); */
				if (XY_IN_RECT(rect[0], rect[1],
							xinerama_screens[i].x_org,
							xinerama_screens[i].y_org,
							xinerama_screens[i].width,
							xinerama_screens[i].height)) {
					curr_screen = xinerama_screen = i;
					break;
				}
			}
		}
#endif				/* HAVE_LIBXINERAMA */
		winwid->full_screen = !winwid->full_screen;
		winwidget_destroy_xwin(winwid);
		winwidget_create_window(winwid, winwid->im_w, winwid->im_h);
		winwidget_render_image(winwid, 1, 1);
		winwidget_show(winwid);
#ifdef HAVE_LIBXINERAMA
		/* if we have xinerama and we're using it, then full screen the window
		 * on the head that the window was active on */
		if (winwid->full_screen == TRUE && opt.xinerama && xinerama_screens) {
			xinerama_screen = curr_screen;
			winwidget_move(winwid,
					xinerama_screens[curr_screen].x_org, xinerama_screens[curr_screen].y_org);
		}
#endif				/* HAVE_LIBXINERAMA */
	case '=':
	case '+':
		if (opt.reload < SLIDESHOW_RELOAD_MAX)
			opt.reload++;
		else if (opt.verbose)
			weprintf("Cannot set RELOAD higher than %d seconds.", opt.reload);
		break;
	case '-':
	case '_':
		if (opt.reload > 1)
			opt.reload--;
		else if (opt.verbose)
			weprintf("Cannot set RELOAD lower than 1 second.");
		break;
	default:
		break;
	}
	D_RETURN_(4);
}