Efficient Thumbnailing Here!

Don’t you just love those really sweet screenshots with the thumbnails as iconified windows? Then when you try it out, it’s laggy as hell. Well, here is my way of doing thumbnails. The following functions make all of your iconified windows show as screenshots of the window, AND provide a menu of window screenshots (FvwmReveal). And they do it efficiently without any noticably slowdown (with about a 10-25% increase in CPU utilization every now and then).

Fell free to modify any of these to your liking or for your specific system, and post any suggestions.

Here is the function which actually captures a window. Rather than raise the window when I want to capture it, I’ve made it so that the window must be raised in order to capture it (otherwise, break).

[code]# don’t expect the image to be available IMMEDIATELY

make sure xwd and convert aren’t running first (if they are, break)

DestroyFunc CaptureWindow
AddToFunc CaptureWindow

  • I ThisWindow (Raised, !Iconic, !Shaded, CurrentPage, !FvwmIdent)
  • I TestRc (NoMatch) Break
  • I PipeRead ‘if [[ ps aux | grep xwd | grep -v grep
    || ps aux | grep convert | grep -v grep ]]; then echo Break; fi’
  • I WindowId $[w.id] Exec exec xwd -silent -id $[w.id] | convert -scale 128 -frame 1x1 -mattecolor black -quality 0 xwd:- png:/tmp/$[w.id].png
  • I WindowId $[w.id] WindowStyle IconOverride, Icon /tmp/$[w.id].png [/code]

Here is the function that opens up a menu of all windows, showing each one as a thumbnail:

[code]# open a menu that consists of the latest screenshots of all windows
DestroyFunc FvwmReveal
AddToFunc FvwmReveal

  • I AddToMenu FvwmExposeMenu “” Title
  • I All (CurrentPage, !Sticky) And
    ‘AddToMenu FvwmExposeMenu “$[w.name]”%/tmp/$[w.id].png% WindowID $[w.id]\
    And Raise “Iconify off” “WindowShade off” “WarpToWindow 50 50”’
  • I AddToMenu FvwmExposeMenu DynamicPopDownAction And
    “DestroyMenu recreate FvwmExposeMenu”
  • I Menu FvwmExposeMenu [/code]

I have two ways that I grab screenshots. One way is by periodically polling, capturing the currently focused window. This helps get changes from the window that you are using, and updating the thumbnail accordinly. The other way is by using FvwmEvent to capture windows whenever they are created, focused, raised, etc…

[code]DestroyFunc StartFunction
AddToFunc StartFunction

  • I Module FvwmEvent
  • I Test (Restart) LoadCaptured
  • I RepeatedCapture 5000

if it gets laggy you can turn some of these off

the ‘schedule’ is necessary here because many windows

are not available as soon as they are added/deiconified/unshaded

*FvwmEvent raise_window CaptureWindow
*FvwmEvent add_window “Schedule 250 CaptureWindow”
#*FvwmEvent enter_window CaptureWindow
*FvwmEvent focus_change CaptureWindow
*FvwmEvent deiconify “Schedule 500 CaptureWindow”
*FvwmEvent dewindowshade “Schedule 500 CaptureWindow” [/code]

If you’re wondering what the heck that LoadCaptured thing is in my StartFunction, here it is:

[code]# whenever we restart fvwm, we have to set all the icons as their screenshots…

otherwise, they’ll revert to icons

DestroyFunc LoadCaptured
AddToFunc LoadCaptured

  • I All (*) PipeRead if [ -e /tmp/$[w.id].png ]; then \ echo WindowId $[w.id] WindowStyle IconOverride, Icon /tmp/$[w.id].png; fi [/code]

Then I like to have mouse bindings like this:

Mouse 2 R N NoWindow FvwmReveal Mouse 2 A 4 NoWindow FvwmReveal

Note: Just call Iconify the way you always do. No changes to it are necessary.

I’ve got a fun idea for this if I can make it all work…

Um… “RepeatedCapture?” Whassat then guv?

“RepeatedCapture 5000” tells it to capture all raised windows every 5 seconds.

mmm… only it isn’t defined in your code, or on the manual page, so I was wondering if it was something you wrote and didn’t include or some arcane feature of FVWM that I totally missed is all.

Sorry - I could have been a bit less cryptic I suppose.

Try imlib instead of xwd and convert…

short example:

[code]#include <X11/Xlib.h>
#include <Imlib2.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
Display *display;
XWindowAttributes windowattr;
Imlib_Image image;
int windowid, thumbwidth, thumbheight;
char *imageformat, *imagepath;

    if ( argc != 4 ) return 1;
    sscanf(argv[1], "%x", &windowid);
    sscanf(argv[2], "%d", &thumbwidth);
    imagepath = argv[3];
    imageformat = strrchr(argv[3], '.');

    if ( (display = XOpenDisplay(NULL)) == NULL ) return 1;
    XGetWindowAttributes(display, windowid, &windowattr);
    thumbheight = (int)((float)windowattr.height / ((float)windowattr.width/(float)thumbwidth));

    imlib_context_set_anti_alias(1);
    imlib_context_set_display(display);
    imlib_context_set_visual(DefaultVisual(display, DefaultScreen(display)));
    imlib_context_set_colormap(DefaultColormap(display, DefaultScreen(display)));
    imlib_context_set_drawable(windowid);

    if ( 4*thumbwidth >= windowattr.width || 4*thumbheight >= windowattr.height ) {
            image = imlib_create_image_from_drawable((Pixmap)0, 0, 0,
                    windowattr.width, windowattr.height, 1);
            imlib_context_set_image(image);
            image = imlib_create_cropped_scaled_image(0, 0, windowattr.width, windowattr.height,
                    thumbwidth, thumbheight);
    } else {
            image = imlib_create_scaled_image_from_drawable((Pixmap)0, 0, 0,
                    windowattr.width, windowattr.height, 4*thumbwidth, 4*thumbheight, 1, 1);
            imlib_context_set_image(image);
            image = imlib_create_cropped_scaled_image(0, 0, 4*thumbwidth, 4*thumbheight,
                    thumbwidth, thumbheight);
    }
    imlib_context_set_image(image);
    imlib_image_set_format(imageformat + 1);
    imlib_save_image(argv[3]);
    return 0;

}
[/code]

compile:

gcc -Wall -Werror -o thumb thumb.c `imlib2-config --cflags` `imlib2-config --libs`

usage:

[code]sascha@armada:~$ time xwd -silent -id 0x1400003 | convert -scale 128 -frame 1x1 -mattecolor black -quality 0 xwd:- png:test.png

real 0m1.195s
user 0m0.281s
sys 0m0.131s
sascha@armada:~$ time thumb 0x1400003 128 test.png

real 0m0.246s
user 0m0.050s
sys 0m0.015s[/code]

I’ve got one somewhere using PerlMagick - using C always feels like cheating with FVWM :wink: On the other hand, if we can get this stuff efficient enough it’s just begging to be made into a module.

Hmm, I dont know something like imlib_create_scaled_image_from_drawable(…) in perl.

You can decrease the thumbnailsize or the quality (4 in the example above) to get this more effizient.

Some examples:


0.102s (1: grab 128x… pixel)
0.128s (2: grab 256x… pixel)
0.172s (3: grab 384x… pixel)
0.280s (4: grab 512x… pixel)
0.475s (100: grab 1024x768 pixel)
1.279s (xwd: grab 1024x768 pixel)


0.082s (1: grab 64x… pixel)
0.066s (2: grab 128x… pixel)
0.083s (3: grab 192x… pixel)
0.113s (4: grab 256x… pixel)
0.458s (100: grab 1024x768 pixel)
1.106s (xwd: grab 1024x768 pixel)

veeery cool, thanks Sascha.

I used it to build a small screenshot-utility in wxbasic:

wxbasic.sourceforge.net/phpBB2/v … =4188#4188

Greetings, Mark

Thank you very much, Sascha, it workd really fine !

I’m kinda like the spirit but facing the results I’ve to admit that Rasterman did a great job with its Imlib2 library. Thank you Sasha for this hint.

Anyway, while waiting for a stable release of the forthcoming perl library that will harness the power of Imlib2 (search.cpan.org/~lbrocard/Image-Imlib2-1.03), I’ve extended Sasha’s work for thus who are using a composition of the window icon and its capture as the regular Taviso’s function was showing it:
For the C part

[code]#include <X11/Xlib.h>
#include <Imlib2.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
Display *display;
XWindowAttributes windowattr;
Imlib_Image image;
Imlib_Image icon;
int windowid, thumbwidth, thumbheight;
char *imageformat, *imagepath;
char *iconformat, *iconpath;
int w, h;

    if ( argc != 5 ) {
    puts("Usage: thumb WindowId ThumbWidth ThumbFile IconFile");
    return 1;
}
    sscanf(argv[1], "%x", &windowid);
    sscanf(argv[2], "%d", &thumbwidth);
    imagepath = argv[3];
    imageformat = strrchr(argv[3], '.');
    iconpath = argv[4];
    iconformat = strrchr(argv[4], '.');


    if ( (display = XOpenDisplay(NULL)) == NULL ) return 1;
    XGetWindowAttributes(display, windowid, &windowattr);
    thumbheight = (int)((float)windowattr.height / ((float)windowattr.width/(float)thumbwidth));

    imlib_context_set_anti_alias(1);
    imlib_context_set_display(display);
    imlib_context_set_visual(DefaultVisual(display, DefaultScreen(display)));
    imlib_context_set_colormap(DefaultColormap(display, DefaultScreen(display)));
    imlib_context_set_drawable(windowid);

    if ( 4*thumbwidth >= windowattr.width || 4*thumbheight >= windowattr.height ) {
            image = imlib_create_image_from_drawable((Pixmap)0, 0, 0,
                    windowattr.width, windowattr.height, 1);
            imlib_context_set_image(image);
            image = imlib_create_cropped_scaled_image(0, 0, windowattr.width, windowattr.height,
                    thumbwidth, thumbheight);
    } else {
            image = imlib_create_scaled_image_from_drawable((Pixmap)0, 0, 0,
                    windowattr.width, windowattr.height, 4*thumbwidth, 4*thumbheight, 1, 1);
            imlib_context_set_image(image);
            image = imlib_create_cropped_scaled_image(0, 0, 4*thumbwidth, 4*thumbheight,
                    thumbwidth, thumbheight);
    }
icon = imlib_load_image(argv[4]);
    imlib_context_set_image(icon);
w = imlib_image_get_width();
h = imlib_image_get_height();
    imlib_context_set_image(image);
imlib_blend_image_onto_image(	icon, 0,
				0, 0, w, h,
				0, 0, w, h);
    imlib_image_set_format(imageformat + 1);
    imlib_save_image(argv[3]);

fprintf(stdout, "WindowStyle IconOverride, Icon %s\n", argv[3]);
    return 0;

}
[/code]
And its Makefile

[code]CC := gcc
CFLAGS := -Wall -O3 -fomit-frame-pointer
imlib2-config --cflags
CPPFLAGS :=
CXXFLAGS := $(CFLAGS)
TARGET_ARCH := -march=athlon-xp -mcpu=athlon-xp
LDFLAGS := -Wl,-O1
imlib2-config --libs
PRODUCTS := thumb

.PHONY: clean

all: $(PRODUCTS)

clean:
find *.o -exec rm {} ; && echo || echo

mrproper: clean
for product in $(PRODUCTS);
do [ -f $$product ] && rm $$product;
done && echo || echo

rebuild: mrproper all

thumb: thumb.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
strip $@[/code]
Finally, the Taviso’s thumbnail function a bit modified:

[code]SetEnv fvwm_icon_size 150
DestroyFunc Thumbnail
AddToFunc Thumbnail

  • I Raise
  • I SetEnv Icon-$[w.id] $[w.IconFile]
  • I ThisWindow (!Shaded, Iconifiable, !Iconic) PipeRead
    “$./thumb/thumb $[w.id] $[fvwm_icon_size] /dev/shm/icon.tmp.$[w.id].png $[w.IconFile]”
  • I Iconify[/code]

Hum … im not getting it to work properly … for some reason it geaves me an error .

sh: w.IconFile: syntax error in expression (error token is ".IconFile")

really dunno whats happening , Pem how did you compiled it ??
I

It comed from the fact that $[w.iconfile] is unchaged if no icon file is associated with the window, and the shell try to interpret it. From man fvwm

$[w.name] $[w.iconname] $[w.iconfile] $[w.miniiconfile] $[w.class] $[w.resource] The window's name, icon name, file name of its icon or mini icon defined with the Icon or MiniIcon style including the path information if the file was found on disk, resource class or resource name respectivelly, or unexpended "$[w.<attribute>]" string if no window is associated with the command.

You have to replace this line

"$./thumb/thumb $[w.id] $[fvwm_icon_size] /dev/shm/icon.tmp.$[w.id].png $[w.IconFile]"

by

"$./thumb/thumb $[w.id] $[fvwm_icon_size] /dev/shm/icon.tmp.$[w.id].png '$[w.IconFile]'"

and test in thumb script or program wether the last argument is $[w.IconFile] litteraly.

btw, I don’t think your new avatar is a good way to show your disapprobation towards the moderators, and is quite socking :imp: .

the same for your avatar! what does that mean? did you turn up?

:imp: :imp: :imp:

With GCC :wink:

For the rest zonk’s got it right. All my apps have a MiniIcon defined. That avoids unecessary tests:

Style * EWMHMiniIconOverride, Icon big_icon.png, MiniIcon small_icon.png

edited by author: deleted, reason: off-topic

cof this is Fvwm cof forum so if you guys whant politics why dont you go someplace else, and no this has nothing to do with moderators nor administrators nor Style ** Nothing , I like some of Hitler’s ideas, thats my problem , so please keep those comment either on the pm or in an apropriate forum ! txs

BTW tanks for those who helped me out :wink:

edited by author: deleted, reason: off-topic

I have to agree with the previous posters, politics don’t belong in an Fvwm forum, so please do keep them out of it. Besides that Nazism (and as a cosequence Hitler) are very offending to a lot Europeans so it would be very innapropriate to remind them of it every time they visit this board.
So I have to ask you to change your avatar to something more neutral for both of the aforementioned reasons.

I do hope you understand our position in this.

Thanks in advance.

Bert

PS: there’s a 80x80 limit to the size of an avatar, phpBB doesn’t seem to enforce this, so I’ve added it to the Guidelines along with a statement about politics.

Thank you Bert, and sorry for my hard words.

Mark

From your name I assume you are German, so your reaction is quite understandable. I no action has been taken by this time tomorrow I’ll remove it myself.

And now, let’s put this thread back on-topic :slight_smile: