diff --git a/man/feh.pre b/man/feh.pre index 79aa3551..5e900459 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -1223,6 +1223,9 @@ Tile .Pq repeat the image in case it is too small for the screen . +.It Cm --bg-preserve +Combines the results of the addition of the new background with any possibly existing background. +. .It Cm --no-fehbg . Do not write a diff --git a/src/help.raw b/src/help.raw index 18469084..61eac06c 100644 --- a/src/help.raw +++ b/src/help.raw @@ -82,6 +82,8 @@ OPTIONS fill the whole background, but the images' aspect ratio may not be preserved --bg-tile FILE Set FILE as tiled desktop background + --bg-preserve Combines the results of the addition of the new + background with any possibly existing background. --no-fehbg Do not write a ~/.fehbg file -C, --fontpath PATH Specify an extra directory to look in for fonts, can be used multiple times to add multiple paths. diff --git a/src/options.c b/src/options.c index 4744bb0c..85a80d7e 100644 --- a/src/options.c +++ b/src/options.c @@ -434,6 +434,7 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) {"class" , 1, 0, 249}, {"no-conversion-cache", 0, 0, 250}, {"window-id", 1, 0, 251}, + {"bg-preserve", 0, 0, 252}, {0, 0, 0, 0} }; int optch = 0, cmdx = 0; @@ -837,6 +838,9 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) case 251: opt.x11_windowid = atol(optarg); break; + case 252: + opt.bg_preserve = 1; + break; default: break; } diff --git a/src/options.h b/src/options.h index 7ca699b3..eb8d5a71 100644 --- a/src/options.h +++ b/src/options.h @@ -91,6 +91,7 @@ struct __fehoptions { char *output_dir; char *bg_file; char *image_bg; + int bg_preserve; char *font; char *title_font; char *title; diff --git a/src/wallpaper.c b/src/wallpaper.c index b62d28b2..3c69fe10 100644 --- a/src/wallpaper.c +++ b/src/wallpaper.c @@ -103,25 +103,45 @@ static void feh_wm_set_bg_centered(Pixmap pmap, Imlib_Image im, int use_filelist int x, int y, int w, int h) { int offset_x, offset_y; + int img_w, img_h; if (use_filelist) feh_wm_load_next(&im); + img_w = gib_imlib_image_get_width(im); + img_h = gib_imlib_image_get_height(im); + if (opt.geom_w != 0 && opt.geom_h != 0) { + if (opt.geom_w == 0) { + double ratio = (double)img_w / (double)img_h; + opt.geom_w = (int) ((double)opt.geom_h * ratio); + } else if (opt.geom_h == 0) { + double ratio = (double)img_h / (double)img_w; + opt.geom_h = (int) ((double)opt.geom_w * ratio); + } + + Imlib_Image im_old = im; + im = gib_imlib_create_cropped_scaled_image(im_old, 0, 0, img_w, img_h, opt.geom_w, opt.geom_h, 1); + gib_imlib_free_image_and_decache(im_old); + + img_w = opt.geom_w; + img_h = opt.geom_h; + } + if(opt.geom_flags & XValue) if(opt.geom_flags & XNegative) - offset_x = (w - gib_imlib_image_get_width(im)) + opt.geom_x; + offset_x = (w - img_w) + opt.geom_x; else offset_x = opt.geom_x; else - offset_x = (w - gib_imlib_image_get_width(im)) >> 1; + offset_x = (w - img_w) >> 1; if(opt.geom_flags & YValue) if(opt.geom_flags & YNegative) - offset_y = (h - gib_imlib_image_get_height(im)) + opt.geom_y; + offset_y = (h - img_h) + opt.geom_y; else offset_y = opt.geom_y; else - offset_y = (h - gib_imlib_image_get_height(im)) >> 1; + offset_y = (h - img_h) >> 1; gib_imlib_render_image_part_on_drawable_at_size(pmap, im, ((offset_x < 0) ? -offset_x : 0), @@ -421,6 +441,7 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, unsigned long length, after; unsigned char *data_root = NULL, *data_esetroot = NULL; Pixmap pmap_d1, pmap_d2; + unsigned int pmap_d1_freeable = 0; /* local display to set closedownmode on */ Display *disp2; @@ -465,10 +486,40 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, D(("centering\n")); - pmap_d1 = XCreatePixmap(disp, root, scr->width, scr->height, depth); - gcval.foreground = color.pixel; - gc = XCreateGC(disp, root, GCForeground, &gcval); - XFillRectangle(disp, pmap_d1, gc, 0, 0, scr->width, scr->height); + + + unsigned char *data = NULL; + if (opt.bg_preserve) { + Atom act_type; + int act_format; + unsigned long nitems, bytes_after; + Atom _XROOTPMAP_ID; + + _XROOTPMAP_ID = XInternAtom(disp, "_XROOTPMAP_ID", False); + + if (XGetWindowProperty(disp, root, _XROOTPMAP_ID, 0, 1, False, XA_PIXMAP, + &act_type, &act_format, &nitems, &bytes_after, + &data) == Success) { + if (data) { + D(("preserving background\n")); + pmap_d1 = *((Pixmap *) data); + XFree(data); + } + } else { + // XOrg documentation is not clear if a non-success event can + // set data. + data = NULL; + } + } + + // if bg_preserve wasn't run or bg_preserve found no existing background + if (!data) { + pmap_d1 = XCreatePixmap(disp, root, scr->width, scr->height, depth); + gcval.foreground = color.pixel; + gc = XCreateGC(disp, root, GCForeground, &gcval); + XFillRectangle(disp, pmap_d1, gc, 0, 0, scr->width, scr->height); + pmap_d1_freeable = 1; + } #ifdef HAVE_LIBXINERAMA if (opt.xinerama && xinerama_screens) { @@ -485,7 +536,8 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, feh_wm_set_bg_centered(pmap_d1, im, use_filelist, 0, 0, scr->width, scr->height); - XFreeGC(disp, gc); + if (!data) + XFreeGC(disp, gc); } else if (filled == 1) { @@ -564,7 +616,8 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, XFreeGC(disp2, gc); XSync(disp2, False); XSync(disp, False); - XFreePixmap(disp, pmap_d1); + if(pmap_d1_freeable) + XFreePixmap(disp, pmap_d1); prop_root = XInternAtom(disp2, "_XROOTPMAP_ID", True); prop_esetroot = XInternAtom(disp2, "ESETROOT_PMAP_ID", True); @@ -599,9 +652,10 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, if (prop_root == None || prop_esetroot == None) eprintf("creation of pixmap property failed."); - XChangeProperty(disp2, root2, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pmap_d2, 1); + XChangeProperty(disp2, root2, prop_root, XA_PIXMAP, 32, + PropModeReplace, (unsigned char *) &pmap_d2, 1); XChangeProperty(disp2, root2, prop_esetroot, XA_PIXMAP, 32, - PropModeReplace, (unsigned char *) &pmap_d2, 1); + PropModeReplace, (unsigned char *) &pmap_d2, 1); XSetWindowBackgroundPixmap(disp2, root2, pmap_d2); XClearWindow(disp2, root2);