summaryrefslogtreecommitdiff
path: root/src/winwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/winwidget.c')
-rw-r--r--src/winwidget.c619
1 files changed, 399 insertions, 220 deletions
diff --git a/src/winwidget.c b/src/winwidget.c
index 26a43e2..3b90158 100644
--- a/src/winwidget.c
+++ b/src/winwidget.c
@@ -1,6 +1,7 @@
/* winwidget.c
Copyright (C) 1999-2003 Tom Gilbert.
+Copyright (C) 2010-2025 Birte Kristina Friesel.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
@@ -27,6 +28,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "filelist.h"
#include "winwidget.h"
#include "options.h"
+#include "events.h"
+#include "timers.h"
+
+#ifdef HAVE_INOTIFY
+#include <sys/inotify.h>
+#endif
static void winwidget_unregister(winwidget win);
static void winwidget_register(winwidget win);
@@ -41,6 +48,7 @@ static winwidget winwidget_allocate(void)
winwidget ret = NULL;
ret = emalloc(sizeof(_winwidget));
+ memset(ret, 0, sizeof(_winwidget));
ret->win = 0;
ret->w = 0;
@@ -54,9 +62,11 @@ static winwidget winwidget_allocate(void)
ret->im = NULL;
ret->name = NULL;
ret->file = NULL;
+ ret->errstr = NULL;
ret->type = WIN_TYPE_UNSET;
ret->visible = 0;
ret->caption_entry = 0;
+ ret->force_aliasing = opt.force_aliasing;
/* Zoom stuff */
ret->mode = MODE_NORMAL;
@@ -73,10 +83,14 @@ static winwidget winwidget_allocate(void)
ret->click_offset_y = 0;
ret->has_rotated = 0;
+#ifdef HAVE_INOTIFY
+ ret->inotify_wd = -1;
+#endif
+
return(ret);
}
-winwidget winwidget_create_from_image(Imlib_Image im, char *name, char type)
+winwidget winwidget_create_from_image(Imlib_Image im, char type)
{
winwidget ret = NULL;
@@ -90,20 +104,20 @@ winwidget winwidget_create_from_image(Imlib_Image im, char *name, char type)
ret->w = ret->im_w = gib_imlib_image_get_width(ret->im);
ret->h = ret->im_h = gib_imlib_image_get_height(ret->im);
- if (name)
- ret->name = estrdup(name);
- else
- ret->name = estrdup(PACKAGE);
-
- if (opt.full_screen && (type != WIN_TYPE_THUMBNAIL))
+ if (opt.full_screen && (type != WIN_TYPE_THUMBNAIL)) {
ret->full_screen = True;
+ } else if (opt.default_zoom) {
+ ret->zoom = 0.01 * opt.default_zoom;
+ ret->w *= ret->zoom;
+ ret->h *= ret->zoom;
+ }
winwidget_create_window(ret, ret->w, ret->h);
- winwidget_render_image(ret, 1, 1);
+ winwidget_render_image(ret, 1, 0);
return(ret);
}
-winwidget winwidget_create_from_file(gib_list * list, char *name, char type)
+winwidget winwidget_create_from_file(gib_list * list, char type)
{
winwidget ret = NULL;
feh_file *file = FEH_FILE(list->data);
@@ -114,12 +128,8 @@ winwidget winwidget_create_from_file(gib_list * list, char *name, char type)
ret = winwidget_allocate();
ret->file = list;
ret->type = type;
- if (name)
- ret->name = estrdup(name);
- else
- ret->name = estrdup(file->filename);
- if (winwidget_loadimage(ret, file) == 0) {
+ if ((winwidget_loadimage(ret, file) == 0) || feh_should_ignore_image(ret->im)) {
winwidget_destroy(ret);
return(NULL);
}
@@ -128,10 +138,15 @@ winwidget winwidget_create_from_file(gib_list * list, char *name, char type)
ret->w = ret->im_w = gib_imlib_image_get_width(ret->im);
ret->h = ret->im_h = gib_imlib_image_get_height(ret->im);
D(("image is %dx%d pixels, format %s\n", ret->w, ret->h, gib_imlib_image_format(ret->im)));
- if (opt.full_screen)
+ if (opt.full_screen) {
ret->full_screen = True;
+ } else if (opt.default_zoom) {
+ ret->zoom = 0.01 * opt.default_zoom;
+ ret->w *= ret->zoom;
+ ret->h *= ret->zoom;
+ }
winwidget_create_window(ret, ret->w, ret->h);
- winwidget_render_image(ret, 1, 1);
+ winwidget_render_image(ret, 1, 0);
}
return(ret);
@@ -139,14 +154,22 @@ winwidget winwidget_create_from_file(gib_list * list, char *name, char type)
void winwidget_create_window(winwidget ret, int w, int h)
{
+ XWindowAttributes window_attr;
XSetWindowAttributes attr;
XEvent ev;
XClassHint *xch;
MWMHints mwmhints;
Atom prop = None;
+ pid_t pid;
int x = 0;
int y = 0;
char *tmpname;
+#ifdef HOST_NAME_MAX
+ char hostname[HOST_NAME_MAX];
+#else /* ! HOST_NAME_MAX */
+ long host_name_max;
+ char *hostname;
+#endif /* HOST_NAME_MAX */
D(("winwidget_create_window %dx%d\n", w, h));
@@ -200,7 +223,6 @@ void winwidget_create_window(winwidget ret, int w, int h)
}
if (opt.paused) {
- printf("name %s\n", ret->name);
tmpname = estrjoin(" ", ret->name, "[Paused]", NULL);
free(ret->name);
ret->name = tmpname;
@@ -224,6 +246,7 @@ void winwidget_create_window(winwidget ret, int w, int h)
KeyPressMask | KeyReleaseMask | ButtonMotionMask | ExposureMask
| FocusChangeMask | PropertyChangeMask | VisibilityChangeMask;
+ memset(&mwmhints, 0, sizeof(mwmhints));
if (opt.borderless || ret->full_screen) {
prop = XInternAtom(disp, "_MOTIF_WM_HINTS", True);
if (prop == None) {
@@ -236,14 +259,33 @@ void winwidget_create_window(winwidget ret, int w, int h)
mwmhints.flags = MWM_HINTS_DECORATIONS;
mwmhints.decorations = 0;
}
- } else
- mwmhints.flags = 0;
+ }
- ret->win =
- XCreateWindow(disp, DefaultRootWindow(disp), x, y, w, h, 0,
- depth, InputOutput, vis,
- CWOverrideRedirect | CWSaveUnder | CWBackingStore
- | CWColormap | CWBackPixel | CWBorderPixel | CWEventMask, &attr);
+ if (opt.x11_windowid == 0) {
+ ret->win =
+ XCreateWindow(disp, DefaultRootWindow(disp), x, y, w, h, 0,
+ depth, InputOutput, vis,
+ CWOverrideRedirect | CWSaveUnder | CWBackingStore
+ | CWColormap | CWBackPixel | CWBorderPixel | CWEventMask,
+ &attr);
+ } else {
+ /* x11_windowid is a pointer to the window */
+ ret->win = (Window) opt.x11_windowid;
+
+ /* set our attributes on the window */
+ XChangeWindowAttributes(disp, ret->win,
+ CWOverrideRedirect | CWSaveUnder | CWBackingStore
+ | CWColormap | CWBackPixel | CWBorderPixel
+ | CWEventMask, &attr);
+
+ /* determine the size and visibility of the window */
+ XGetWindowAttributes(disp, ret->win, &window_attr);
+ ret->visible = (window_attr.map_state == IsViewable);
+ ret->x = window_attr.x;
+ ret->y = window_attr.y;
+ ret->w = window_attr.width;
+ ret->h = window_attr.height;
+ }
if (mwmhints.flags) {
XChangeProperty(disp, ret->win, prop, prop, 32,
@@ -259,18 +301,43 @@ void winwidget_create_window(winwidget ret, int w, int h)
ev.xclient.display = disp;
ev.xclient.window = ret->win;
ev.xclient.format = 32;
- ev.xclient.data.l[0] = (ret->full_screen ? 1 : 0);
+ ev.xclient.data.l[0] = 1;
ev.xclient.data.l[1] = prop_fs;
XChangeProperty(disp, ret->win, prop_state, XA_ATOM, 32,
PropModeReplace, (unsigned char *) &prop_fs, 1);
}
+ pid = getpid();
+ prop = XInternAtom(disp, "_NET_WM_PID", False);
+ XChangeProperty(disp, ret->win, prop, XA_CARDINAL, sizeof(pid_t) * 8,
+ PropModeReplace, (const unsigned char *)&pid, 1);
+
+#ifdef HOST_NAME_MAX
+ if (gethostname(hostname, HOST_NAME_MAX) == 0) {
+ hostname[HOST_NAME_MAX-1] = '\0';
+ prop = XInternAtom(disp, "WM_CLIENT_MACHINE", False);
+ XChangeProperty(disp, ret->win, prop, XA_STRING, sizeof(char) * 8,
+ PropModeReplace, (unsigned char *)hostname, strlen(hostname));
+ }
+#else /* ! HOST_NAME_MAX */
+ if ((host_name_max = sysconf(_SC_HOST_NAME_MAX)) != -1 ) {
+ if ((hostname = calloc(1, host_name_max + 1)) != NULL ) {
+ if (gethostname(hostname, host_name_max) == 0) {
+ prop = XInternAtom(disp, "WM_CLIENT_MACHINE", False);
+ XChangeProperty(disp, ret->win, prop, XA_STRING, sizeof(char) * 8,
+ PropModeReplace, (unsigned char *)hostname, strlen(hostname));
+ }
+ free(hostname);
+ }
+ }
+#endif /* HOST_NAME_MAX */
+
XSetWMProtocols(disp, ret->win, &wmDeleteWindow, 1);
winwidget_update_title(ret);
xch = XAllocClassHint();
xch->res_name = "feh";
- xch->res_class = "feh";
+ xch->res_class = opt.x11_class ? opt.x11_class : "feh";
XSetClassHint(disp, ret->win, xch);
XFree(xch);
@@ -293,18 +360,35 @@ void winwidget_create_window(winwidget ret, int w, int h)
XSetCommand(disp, ret->win, cmdargv, cmdargc);
winwidget_register(ret);
+
+ /* do not scale down a thumbnail list window, only those created from it */
+ if (opt.geom_enabled && (ret->type != WIN_TYPE_THUMBNAIL)) {
+ opt.geom_w = w;
+ opt.geom_h = h;
+ opt.geom_flags |= WidthValue | HeightValue;
+ }
+
return;
}
void winwidget_update_title(winwidget ret)
{
char *name;
+ Atom prop_name = XInternAtom(disp, "_NET_WM_NAME", False);
+ Atom prop_icon = XInternAtom(disp, "_NET_WM_ICON_NAME", False);
+ Atom prop_utf8 = XInternAtom(disp, "UTF8_STRING", False);
D(("winwid->name = %s\n", ret->name));
name = ret->name ? ret->name : "feh";
XStoreName(disp, ret->win, name);
XSetIconName(disp, ret->win, name);
- /* XFlush(disp); */
+
+ XChangeProperty(disp, ret->win, prop_name, prop_utf8, 8,
+ PropModeReplace, (const unsigned char *)name, strlen(name));
+
+ XChangeProperty(disp, ret->win, prop_icon, prop_utf8, 8,
+ PropModeReplace, (const unsigned char *)name, strlen(name));
+
return;
}
@@ -338,8 +422,20 @@ void winwidget_setup_pixmaps(winwidget winwid)
if (winwid->gc == None) {
XGCValues gcval;
- gcval.foreground = BlackPixel(disp, DefaultScreen(disp));
- winwid->gc = XCreateGC(disp, winwid->win, GCForeground, &gcval);
+ if (!opt.image_bg || !strcmp(opt.image_bg, "default")) {
+ gcval.foreground = BlackPixel(disp, DefaultScreen(disp));
+ winwid->gc = XCreateGC(disp, winwid->win, GCForeground, &gcval);
+ } else if (!strcmp(opt.image_bg, "checks")) {
+ gcval.tile = feh_create_checks();
+ gcval.fill_style = FillTiled;
+ winwid->gc = XCreateGC(disp, winwid->win, GCTile | GCFillStyle, &gcval);
+ } else {
+ XColor color;
+ Colormap cmap = DefaultColormap(disp, DefaultScreen(disp));
+ XAllocNamedColor(disp, cmap, (char*) opt.image_bg, &color, &color);
+ gcval.foreground = color.pixel;
+ winwid->gc = XCreateGC(disp, winwid->win, GCForeground, &gcval);
+ }
}
winwid->bg_pmap = XCreatePixmap(disp, winwid->win, scr->width, scr->height, depth);
}
@@ -361,130 +457,76 @@ void winwidget_setup_pixmaps(winwidget winwid)
return;
}
-void winwidget_render_image(winwidget winwid, int resize, int alias)
+void winwidget_render_image(winwidget winwid, int resize, int force_alias)
{
int sx, sy, sw, sh, dx, dy, dw, dh;
int calc_w, calc_h;
+ int antialias = 0;
if (!winwid->full_screen && resize) {
- winwidget_resize(winwid, winwid->im_w, winwid->im_h);
+ if (opt.default_zoom) {
+ winwid->zoom = 0.01 * opt.default_zoom;
+ winwidget_resize(winwid, winwid->im_w * winwid->zoom, winwid->im_h * winwid->zoom, 0);
+ } else {
+ winwidget_resize(winwid, winwid->im_w, winwid->im_h, 0);
+ }
winwidget_reset_image(winwid);
}
- /* bounds checks for panning */
- if (winwid->im_x > winwid->w)
- winwid->im_x = winwid->w;
- if (winwid->im_y > winwid->h)
- winwid->im_y = winwid->h;
+ D(("winwidget_render_image resize %d force_alias %d im %dx%d\n",
+ resize, force_alias, winwid->im_w, winwid->im_h));
- D(("winwidget_render_image resize %d alias %d im %dx%d\n",
- resize, alias, winwid->im_w, winwid->im_h));
+ /* winwidget_setup_pixmaps(winwid) resets the winwid->had_resize flag */
+ int had_resize = winwid->had_resize || resize;
winwidget_setup_pixmaps(winwid);
- if (!winwid->full_screen && opt.scale_down && ((winwid->w < winwid->im_w)
- || (winwid->h < winwid->im_h))) {
- D(("scaling down image %dx%d\n", winwid->w, winwid->h));
+ if (had_resize && !opt.keep_zoom_vp && (winwid->type != WIN_TYPE_THUMBNAIL)) {
+ double required_zoom = 1.0;
+ feh_calc_needed_zoom(&required_zoom, winwid->im_w, winwid->im_h, winwid->w, winwid->h);
- feh_calc_needed_zoom(&(winwid->zoom), winwid->im_w, winwid->im_h, winwid->w, winwid->h);
- if (resize)
- winwidget_resize(winwid, winwid->im_w * winwid->zoom, winwid->im_h * winwid->zoom);
- D(("after scaling down image %dx%d\n", winwid->w, winwid->h));
- }
+ winwid->zoom = opt.default_zoom ? (0.01 * opt.default_zoom) : 1.0;
- if (!winwid->full_screen && ((gib_imlib_image_has_alpha(winwid->im)) || (opt.geom_flags)
- || (winwid->im_x || winwid->im_y) || (winwid->zoom != 1.0)
- || (winwid->w > winwid->im_w || winwid->h > winwid->im_h)
- || (winwid->has_rotated)))
- feh_draw_checks(winwid);
+ if ((opt.scale_down || (winwid->full_screen && !opt.default_zoom))
+ && winwid->zoom > required_zoom)
+ winwid->zoom = required_zoom;
+ else if ((opt.zoom_mode && required_zoom > 1)
+ && (!opt.default_zoom || required_zoom < winwid->zoom))
+ winwid->zoom = required_zoom;
- if (resize && (winwid->full_screen || opt.geom_flags)) {
- int smaller; /* Is the image smaller than screen? */
- int max_w = 0, max_h = 0;
-
- if (winwid->full_screen) {
- max_w = scr->width;
- max_h = scr->height;
-#ifdef HAVE_LIBXINERAMA
- if (opt.xinerama && xinerama_screens) {
- max_w = xinerama_screens[xinerama_screen].width;
- max_h = xinerama_screens[xinerama_screen].height;
+ if (opt.offset_flags & XValue) {
+ if (opt.offset_flags & XNegative) {
+ winwid->im_x = winwid->w - (winwid->im_w * winwid->zoom) - opt.offset_x;
+ } else {
+ winwid->im_x = - opt.offset_x * winwid->zoom;
}
-#endif /* HAVE_LIBXINERAMA */
} else {
- if (opt.geom_flags & WidthValue) {
- max_w = opt.geom_w;
- }
- if (opt.geom_flags & HeightValue) {
- max_h = opt.geom_h;
- }
+ winwid->im_x = (int) (winwid->w - (winwid->im_w * winwid->zoom)) >> 1;
}
-
- D(("Calculating for fullscreen/fixed geom render\n"));
- smaller = ((winwid->im_w < max_w)
- && (winwid->im_h < max_h));
-
- if (!smaller || opt.auto_zoom) {
- double ratio = 0.0;
-
- /* Image is larger than the screen (so wants shrinking), or it's
- smaller but wants expanding to fill it */
- ratio = feh_calc_needed_zoom(&(winwid->zoom), winwid->im_w, winwid->im_h, max_w, max_h);
-
- /* contributed by Jens Laas <jens.laas@data.slu.se>
- * What it does:
- * zooms images by a fixed amount but never larger than the screen.
- *
- * Why:
- * This is nice if you got a collection of images where some
- * are small and can stand a small zoom. Large images are unaffected.
- *
- * When does it work, and how?
- * You have to be in fullscreen mode _and_ have auto-zoom turned on.
- * "feh -FZ --zoom 130 imagefile" will do the trick.
- * -zoom percent - the new switch.
- * 100 = orignal size,
- * 130 is 30% larger.
- */
- if (opt.default_zoom) {
- double old_zoom = winwid->zoom;
-
- winwid->zoom = 0.01 * opt.default_zoom;
- if ((winwid->im_h * winwid->zoom) > max_h)
- winwid->zoom = old_zoom;
- if ((winwid->im_w * winwid->zoom) > max_w)
- winwid->zoom = old_zoom;
-
- winwid->im_x = ((int)
- (max_w - (winwid->im_w * winwid->zoom))) >> 1;
- winwid->im_y = ((int)
- (max_h - (winwid->im_h * winwid->zoom))) >> 1;
+ if (opt.offset_flags & YValue) {
+ if (opt.offset_flags & YNegative) {
+ winwid->im_y = winwid->h - (winwid->im_h * winwid->zoom) - opt.offset_y;
} else {
- if (ratio > 1.0) {
- /* height is the factor */
- winwid->im_x = 0;
- winwid->im_y = ((int)
- (max_h - (winwid->im_h * winwid->zoom))) >> 1;
- } else {
- /* width is the factor */
- winwid->im_x = ((int)
- (max_w - (winwid->im_w * winwid->zoom))) >> 1;
- winwid->im_y = 0;
- }
+ winwid->im_y = - opt.offset_y * winwid->zoom;
}
} else {
- /* my modification to jens hack, allow --zoom without auto-zoom mode */
- if (opt.default_zoom) {
- winwid->zoom = 0.01 * opt.default_zoom;
- } else {
- winwid->zoom = 1.0;
- }
- /* Just center the image in the window */
- winwid->im_x = (int) (max_w - (winwid->im_w * winwid->zoom)) >> 1;
- winwid->im_y = (int) (max_h - (winwid->im_h * winwid->zoom)) >> 1;
+ winwid->im_y = (int) (winwid->h - (winwid->im_h * winwid->zoom)) >> 1;
}
}
+ winwid->had_resize = 0;
+
+ if (opt.keep_zoom_vp)
+ winwidget_sanitise_offsets(winwid);
+
+ if (!winwid->full_screen && ((gib_imlib_image_has_alpha(winwid->im))
+ || (opt.geom_flags & (WidthValue | HeightValue))
+ || (winwid->im_x || winwid->im_y)
+ || (winwid->w > winwid->im_w * winwid->zoom)
+ || (winwid->h > winwid->im_h * winwid->zoom)
+ || (winwid->has_rotated)))
+ feh_draw_checks(winwid);
+
/* Now we ensure only to render the area we're looking at */
dx = winwid->im_x;
dy = winwid->im_y;
@@ -507,10 +549,18 @@ void winwidget_render_image(winwidget winwid, int resize, int alias)
calc_h = lround(winwid->im_h * winwid->zoom);
dw = (winwid->w - winwid->im_x);
dh = (winwid->h - winwid->im_y);
- if (calc_w < dw)
+ if (calc_w < dw) {
dw = calc_w;
- if (calc_h < dh)
+ if (!winwid->full_screen) {
+ dx = 0;
+ }
+ }
+ if (calc_h < dh) {
dh = calc_h;
+ if (!winwid->full_screen) {
+ dy = 0;
+ }
+ }
if (dw > winwid->w)
dw = winwid->w;
if (dh > winwid->h)
@@ -522,28 +572,46 @@ void winwidget_render_image(winwidget winwid, int resize, int alias)
D(("sx: %d sy: %d sw: %d sh: %d dx: %d dy: %d dw: %d dh: %d zoom: %f\n",
sx, sy, sw, sh, dx, dy, dw, dh, winwid->zoom));
+ if ((winwid->zoom != 1.0 || winwid->has_rotated) && !force_alias && !winwid->force_aliasing)
+ antialias = 1;
+
D(("winwidget_render(): winwid->im_angle = %f\n", winwid->im_angle));
if (winwid->has_rotated)
gib_imlib_render_image_part_on_drawable_at_size_with_rotation
- (winwid->bg_pmap, winwid->im, sx, sy, sw, sh, dx, dy, dw, dh, winwid->im_angle, 1, 1, alias);
+ (winwid->bg_pmap, winwid->im, sx, sy, sw, sh, dx, dy, dw, dh,
+ winwid->im_angle, 1, 1, antialias);
else
gib_imlib_render_image_part_on_drawable_at_size(winwid->bg_pmap,
winwid->im,
sx, sy, sw,
sh, dx, dy,
dw, dh, 1,
- gib_imlib_image_has_alpha(winwid->im), alias);
+ gib_imlib_image_has_alpha(winwid->im),
+ antialias);
if (opt.mode == MODE_NORMAL) {
if (opt.caption_path)
winwidget_update_caption(winwid);
if (opt.draw_filename)
feh_draw_filename(winwid);
+#ifdef HAVE_LIBEXIF
+ if (opt.draw_exif)
+ feh_draw_exif(winwid);
+#endif
if (opt.draw_actions)
feh_draw_actions(winwid);
- if (opt.info_cmd)
+ if (opt.draw_info && opt.info_cmd)
feh_draw_info(winwid);
- } else if ((opt.mode == MODE_ZOOM) && !alias)
+ if (winwid->errstr)
+ feh_draw_errstr(winwid);
+ if (winwid->file != NULL) {
+ if (opt.title && winwid->type != WIN_TYPE_THUMBNAIL_VIEWER) {
+ winwidget_rename(winwid, feh_printf(opt.title, FEH_FILE(winwid->file->data), winwid));
+ } else if (opt.thumb_title && winwid->type == WIN_TYPE_THUMBNAIL_VIEWER) {
+ winwidget_rename(winwid, feh_printf(opt.thumb_title, FEH_FILE(winwid->file->data), winwid));
+ }
+ }
+ } else if ((opt.mode == MODE_ZOOM) && !antialias)
feh_draw_zoom(winwid);
XSetWindowBackgroundPixmap(disp, winwid->win, winwid->bg_pmap);
@@ -566,7 +634,7 @@ void winwidget_render_image_cached(winwidget winwid)
feh_draw_filename(winwid);
if (opt.draw_actions)
feh_draw_actions(winwid);
- if (opt.info_cmd)
+ if (opt.draw_info && opt.info_cmd)
feh_draw_info(winwid);
XSetWindowBackgroundPixmap(disp, winwid->win, winwid->bg_pmap);
XClearWindow(disp, winwid->win);
@@ -578,6 +646,9 @@ double feh_calc_needed_zoom(double *zoom, int orig_w, int orig_h, int dest_w, in
ratio = ((double) orig_w / orig_h) / ((double) dest_w / dest_h);
+ if (opt.zoom_mode == ZOOM_MODE_FILL)
+ ratio = 1.0 / ratio;
+
if (ratio > 1.0)
*zoom = ((double) dest_w / orig_w);
else
@@ -592,30 +663,20 @@ Pixmap feh_create_checks(void)
Imlib_Image checks = NULL;
if (checks_pmap == None) {
- int onoff, x, y;
-
checks = imlib_create_image(16, 16);
if (!checks)
eprintf("Unable to create a teeny weeny imlib image. I detect problems");
- if (strncmp(opt.image_bg, "white", 5) == 0)
- gib_imlib_image_fill_rectangle(checks, 0, 0, 16, 16, 255, 255, 255, 255);
- else if (strncmp(opt.image_bg, "black", 5) == 0)
- gib_imlib_image_fill_rectangle(checks, 0, 0, 16, 16, 0, 0, 0, 255);
- else {
- for (y = 0; y < 16; y += 8) {
- onoff = (y / 8) & 0x1;
- for (x = 0; x < 16; x += 8) {
- if (onoff)
- gib_imlib_image_fill_rectangle(checks, x, y, 8, 8, 144, 144, 144, 255);
- else
- gib_imlib_image_fill_rectangle(checks, x, y, 8, 8, 100, 100, 100, 255);
- onoff++;
- if (onoff == 2)
- onoff = 0;
- }
- }
+ if (!opt.image_bg || !strcmp(opt.image_bg, "default") || !strcmp(opt.image_bg, "checks")) {
+ gib_imlib_image_fill_rectangle(checks, 0, 0, 16, 16, 144, 144, 144, 255);
+ gib_imlib_image_fill_rectangle(checks, 0, 0, 8, 8, 100, 100, 100, 255);
+ gib_imlib_image_fill_rectangle(checks, 8, 8, 8, 8, 100, 100, 100, 255);
+ } else {
+ XColor color;
+ Colormap cmap = DefaultColormap(disp, DefaultScreen(disp));
+ XAllocNamedColor(disp, cmap, (char*) opt.image_bg, &color, &color);
+ gib_imlib_image_fill_rectangle(checks, 0, 0, 16, 16, color.red, color.green, color.blue, 255);
}
checks_pmap = XCreatePixmap(disp, root, 16, 16, depth);
@@ -625,13 +686,6 @@ Pixmap feh_create_checks(void)
return(checks_pmap);
}
-void winwidget_clear_background(winwidget w)
-{
- XSetWindowBackgroundPixmap(disp, w->win, feh_create_checks());
- /* XClearWindow(disp, w->win); */
- return;
-}
-
void feh_draw_checks(winwidget win)
{
static GC gc = None;
@@ -661,13 +715,15 @@ void winwidget_destroy_xwin(winwidget winwid)
void winwidget_destroy(winwidget winwid)
{
+#ifdef HAVE_INOTIFY
+ winwidget_inotify_remove(winwid);
+#endif
+ if (opt.reload > 0 && opt.multiwindow) {
+ feh_remove_timer_by_data(winwid);
+ }
winwidget_destroy_xwin(winwid);
if (winwid->name)
free(winwid->name);
- if ((winwid->type == WIN_TYPE_ABOUT) && winwid->file) {
- feh_file_free(FEH_FILE(winwid->file->data));
- free(winwid->file);
- }
if (winwid->gc)
XFreeGC(disp, winwid->gc);
if (winwid->im)
@@ -676,6 +732,76 @@ void winwidget_destroy(winwidget winwid)
return;
}
+#ifdef HAVE_INOTIFY
+void winwidget_inotify_remove(winwidget winwid)
+{
+ if (winwid->inotify_wd >= 0) {
+ D(("Removing inotify watch\n"));
+ if (inotify_rm_watch(opt.inotify_fd, winwid->inotify_wd))
+ weprintf("inotify_rm_watch failed:");
+ winwid->inotify_wd = -1;
+ }
+}
+#endif
+
+#ifdef HAVE_INOTIFY
+void winwidget_inotify_add(winwidget winwid, feh_file * file)
+{
+ if (opt.auto_reload && !path_is_url(file->filename)) {
+ D(("Adding inotify watch for %s\n", file->filename));
+ char dir[PATH_MAX];
+ feh_file_dirname(dir, file, PATH_MAX);
+
+ /*
+ * Handle files without directory part, e.g. "feh somefile.jpg".
+ * These always reside in the current directory.
+ */
+ if (dir[0] == '\0') {
+ dir[0] = '.';
+ dir[1] = '\0';
+ }
+ winwid->inotify_wd = inotify_add_watch(opt.inotify_fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO);
+ if (winwid->inotify_wd < 0)
+ weprintf("inotify_add_watch failed:");
+ }
+}
+#endif
+
+#ifdef HAVE_INOTIFY
+#define INOTIFY_BUFFER_LEN (1024 * (sizeof (struct inotify_event)) + 16)
+void feh_event_handle_inotify(void)
+{
+ D(("Received inotify events\n"));
+ char buf[INOTIFY_BUFFER_LEN];
+ int i = 0;
+ int len = read (opt.inotify_fd, buf, INOTIFY_BUFFER_LEN);
+ if (len < 0) {
+ if (errno != EINTR)
+ eprintf("inotify event read failed");
+ } else if (!len)
+ eprintf("inotify event read failed");
+ while (i < len) {
+ struct inotify_event *event;
+ event = (struct inotify_event *) &buf[i];
+ for (int j = 0; j < window_num; j++) {
+ if(windows[j]->inotify_wd == event->wd) {
+ if (event->mask & IN_IGNORED) {
+ D(("inotify watch was implicitly removed\n"));
+ windows[j]->inotify_wd = -1;
+ } else if (event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) {
+ if (strcmp(event->name, FEH_FILE(windows[j]->file->data)->name) == 0) {
+ D(("inotify says file changed\n"));
+ feh_reload_image(windows[j], 0, 0);
+ }
+ }
+ break;
+ }
+ }
+ i += sizeof(struct inotify_event) + event->len;
+ }
+}
+#endif
+
void winwidget_destroy_all(void)
{
int i;
@@ -686,13 +812,13 @@ void winwidget_destroy_all(void)
return;
}
-void winwidget_rerender_all(int resize, int alias)
+void winwidget_rerender_all(int resize)
{
int i;
/* Have to DESCEND the list here, 'cos of the way _unregister works */
for (i = window_num - 1; i >= 0; i--)
- winwidget_render_image(windows[i], resize, alias);
+ winwidget_render_image(windows[i], resize, 0);
return;
}
@@ -709,7 +835,16 @@ winwidget winwidget_get_first_window_of_type(unsigned int type)
int winwidget_loadimage(winwidget winwid, feh_file * file)
{
D(("filename %s\n", file->filename));
- return(feh_load_image(&(winwid->im), file));
+#ifdef HAVE_INOTIFY
+ winwidget_inotify_remove(winwid);
+#endif
+ int res = feh_load_image(&(winwid->im), file);
+#ifdef HAVE_INOTIFY
+ if (res) {
+ winwidget_inotify_add(winwid, file);
+ }
+#endif
+ return(res);
}
void winwidget_show(winwidget winwid)
@@ -724,6 +859,17 @@ void winwidget_show(winwidget winwid)
/* wait for the window to map */
D(("Waiting for window to map\n"));
XMaskEvent(disp, StructureNotifyMask, &ev);
+ winwidget_get_geometry(winwid, NULL);
+
+ /* Unfortunately, StructureNotifyMask does not only mask
+ * the events of type MapNotify (which we want to mask here)
+ * but also such of type ConfigureNotify (and others, see
+ * https://tronche.com/gui/x/xlib/events/processing-overview.html),
+ * which should be handled, especially on tiling wm's. To
+ * remedy this, the handler is executed explicitly:
+ */
+ if (ev.type == ConfigureNotify)
+ feh_event_handle_ConfigureNotify(&ev);
D(("Window mapped\n"));
winwid->visible = 1;
}
@@ -733,8 +879,6 @@ void winwidget_show(winwidget winwid)
void winwidget_move(winwidget winwid, int x, int y)
{
if (winwid && ((winwid->x != x) || (winwid->y != y))) {
- winwid->x = x;
- winwid->y = y;
winwid->x = (x > scr->width) ? scr->width : x;
winwid->y = (y > scr->height) ? scr->height : y;
XMoveWindow(disp, winwid->win, winwid->x, winwid->y);
@@ -745,55 +889,87 @@ void winwidget_move(winwidget winwid, int x, int y)
return;
}
-void winwidget_resize(winwidget winwid, int w, int h)
+void winwidget_resize(winwidget winwid, int w, int h, int force_resize)
{
- Window ignored_window;
XWindowAttributes attributes;
- int tc_x, tc_y;
+ int tc_x, tc_y, px, py;
+ int scr_width = scr->width;
+ int scr_height = scr->height;
+
+ /* discarded */
+ Window dw;
+ int di, i;
+ unsigned int du;
+
+ XGetWindowAttributes(disp, winwid->win, &attributes);
- if (opt.geom_flags) {
+#ifdef HAVE_LIBXINERAMA
+ if (opt.xinerama && xinerama_screens) {
+ xinerama_screen = 0;
+ XQueryPointer(disp, root, &dw, &dw, &px, &py, &di, &di, &du);
+ for (i = 0; i < num_xinerama_screens; i++) {
+ if (XY_IN_RECT(px, py,
+ xinerama_screens[i].x_org,
+ xinerama_screens[i].y_org,
+ xinerama_screens[i].width,
+ xinerama_screens[i].height)) {
+ xinerama_screen = i;
+ break;
+ }
+
+ }
+ if (opt.xinerama_index >= 0)
+ xinerama_screen = opt.xinerama_index;
+
+ scr_width = xinerama_screens[xinerama_screen].width;
+ scr_height = xinerama_screens[xinerama_screen].height;
+ }
+#endif
+
+
+ D((" x %d y %d w %d h %d\n", attributes.x, attributes.y, winwid->w,
+ winwid->h));
+
+ if ((opt.geom_flags & (WidthValue | HeightValue)) && !force_resize) {
winwid->had_resize = 1;
return;
}
if (winwid && ((winwid->w != w) || (winwid->h != h))) {
- D(("Really doing a resize\n"));
- /* winwidget_clear_background(winwid); */
if (opt.screen_clip) {
- winwid->w = (w > scr->width) ? scr->width : w;
- winwid->h = (h > scr->height) ? scr->height : h;
+ double required_zoom = winwid->zoom;
+ if (opt.scale_down && !opt.keep_zoom_vp) {
+ int max_w = (w > scr_width) ? scr_width : w;
+ int max_h = (h > scr_height) ? scr_height : h;
+ feh_calc_needed_zoom(&required_zoom, winwid->im_w, winwid->im_h, max_w, max_h);
+ }
+ int desired_w = winwid->im_w * required_zoom;
+ int desired_h = winwid->im_h * required_zoom;
+ winwid->w = (desired_w > scr_width) ? scr_width : desired_w;
+ winwid->h = (desired_h > scr_height) ? scr_height : desired_h;
}
- /* XResizeWindow(disp, winwid->win, winwid->w, winwid->h); */
- XGetWindowAttributes(disp, winwid->win, &attributes);
- XTranslateCoordinates(disp, winwid->win, attributes.root,
- -attributes.border_width -
- attributes.x,
- -attributes.border_width - attributes.y, &tc_x, &tc_y, &ignored_window);
- winwid->x = tc_x;
- winwid->y = tc_y;
- XMoveResizeWindow(disp, winwid->win, tc_x, tc_y, winwid->w, winwid->h);
+ if (winwid->full_screen) {
+ XTranslateCoordinates(disp, winwid->win, attributes.root,
+ -attributes.border_width - attributes.x,
+ -attributes.border_width - attributes.y, &tc_x, &tc_y, &dw);
+ winwid->x = tc_x;
+ winwid->y = tc_y;
+ XMoveResizeWindow(disp, winwid->win, tc_x, tc_y, winwid->w, winwid->h);
+ } else
+ XResizeWindow(disp, winwid->win, winwid->w, winwid->h);
winwid->had_resize = 1;
XFlush(disp);
-#ifdef HAVE_LIBXINERAMA
- if (opt.xinerama && xinerama_screens) {
- int i;
-
- for (i = 0; i < num_xinerama_screens; i++) {
- xinerama_screen = 0;
- if (XY_IN_RECT(winwid->x, winwid->y,
- xinerama_screens[i].x_org,
- xinerama_screens[i].y_org,
- xinerama_screens[i].width, xinerama_screens[i].height)) {
- xinerama_screen = i;
- break;
- }
+ winwidget_get_geometry(winwid, NULL);
- }
- if (getenv("XINERAMA_SCREEN"))
- xinerama_screen = atoi(getenv("XINERAMA_SCREEN"));
+ if (force_resize && (opt.geom_flags & (WidthValue | HeightValue))
+ && (winwid->type != WIN_TYPE_THUMBNAIL)) {
+ opt.geom_w = winwid->w;
+ opt.geom_h = winwid->h;
}
-#endif /* HAVE_LIBXINERAMA */
+
+ D(("-> x %d y %d w %d h %d\n", winwid->x, winwid->y, winwid->w,
+ winwid->h));
} else {
D(("No resize actually needed\n"));
@@ -882,8 +1058,9 @@ void winwidget_rename(winwidget winwid, char *newname)
void winwidget_free_image(winwidget w)
{
- if (w->im)
- gib_imlib_free_image_and_decache(w->im);
+ if (w->im) {
+ gib_imlib_free_image(w->im);
+ }
w->im = NULL;
w->im_w = 0;
w->im_h = 0;
@@ -907,9 +1084,12 @@ void feh_debug_print_winwid(winwidget w)
void winwidget_reset_image(winwidget winwid)
{
- winwid->zoom = 1.0;
- winwid->im_x = 0;
- winwid->im_y = 0;
+ if (!opt.keep_zoom_vp) {
+ winwid->zoom = 1.0;
+ winwid->old_zoom = 1.0;
+ winwid->im_x = 0;
+ winwid->im_y = 0;
+ }
winwid->im_angle = 0.0;
winwid->has_rotated = 0;
return;
@@ -934,11 +1114,11 @@ void winwidget_center_image(winwidget winwid)
winwid->im_y = (scr_height - lround(winwid->im_h * winwid->zoom)) >> 1;
} else {
if (opt.geom_flags & WidthValue)
- winwid->im_x = (opt.geom_w - lround(winwid->im_w * winwid->zoom)) >> 1;
+ winwid->im_x = ((int)opt.geom_w - lround(winwid->im_w * winwid->zoom)) >> 1;
else
winwid->im_x = 0;
if (opt.geom_flags & HeightValue)
- winwid->im_y = (opt.geom_h - lround(winwid->im_h * winwid->zoom)) >> 1;
+ winwid->im_y = ((int)opt.geom_h - lround(winwid->im_h * winwid->zoom)) >> 1;
else
winwid->im_y = 0;
}
@@ -980,9 +1160,9 @@ void winwidget_sanitise_offsets(winwidget winwid)
void winwidget_size_to_image(winwidget winwid)
{
- winwidget_resize(winwid, winwid->im_w * winwid->zoom, winwid->im_h * winwid->zoom);
+ winwidget_resize(winwid, winwid->im_w * winwid->zoom, winwid->im_h * winwid->zoom, 1);
winwid->im_x = winwid->im_y = 0;
- winwidget_render_image(winwid, 0, 1);
+ winwidget_render_image(winwid, 0, 0);
return;
}
@@ -1022,8 +1202,11 @@ void winwidget_get_geometry(winwidget winwid, int *rect)
{
unsigned int bw, bp;
Window child;
+
+ int inner_rect[4];
+
if (!rect)
- return;
+ rect = inner_rect;
XGetGeometry(disp, winwid->win, &root, &(rect[0]), &(rect[1]), (unsigned
int *)&(rect[2]), (unsigned int *)&(rect[3]), &bw, &bp);
@@ -1045,11 +1228,7 @@ void winwidget_show_menu(winwidget winwid)
Window r;
XQueryPointer(disp, winwid->win, &r, &r, &x, &y, &b, &b, &c);
- if (winwid->type == WIN_TYPE_ABOUT) {
- if (!menu_about_win)
- feh_menu_init_about_win();
- feh_menu_show_at_xy(menu_about_win, winwid, x, y);
- } else if (winwid->type == WIN_TYPE_SINGLE) {
+ if (winwid->type == WIN_TYPE_SINGLE) {
if (!menu_single_win)
feh_menu_init_single_win();
feh_menu_show_at_xy(menu_single_win, winwid, x, y);