You are not logged in.
I want to store the root window background, as it is atm, but without any open windows, conkys or panels.
so just a bitmap that is the size of my screen, regardless of what image or tile or bg color i used for the background.
is it possible?
is there an application?
i tried most of the *setroot apps that are out there, but none of them have this reverse feature.
imagemagick's "import -window root somefile.png" just makes a screenshot...
but the naked root window bg must be stored somewhere for apps to access it?
thanks in advance,
o.
Last edited by ondoho (2013-11-29 07:29:44)
Offline
I'm just trying to imagine when this would be useful…
All the best,
-HG
Offline
i was expecting that kind of question...
well, while you wrote i added some more info to post #1.
i want to write a wallpaper creator with immediate effect, and that file would be the backup.
so that in the end of the script i could ask: "Do you like what you see (y/n)?"
Last edited by ondoho (2013-11-29 07:34:43)
Offline
I think I'm missing something here. You want to save the background, but how did you generate that background in the first place?
Offline
Q: why do i not query the program that set the bg in the first place?
A: because there's various programs doing that and most of them use manipulations that result in a wallpaper that is quite different from the originally used image file. but i want the actual wallpaper as it looks right now, minus the windows/panels/...., i.e. a bitmap of the exact size of my screen.
Q: and why do i think this wallpaper can be extracted in the desired way?
A: example (without compositing): i open a terminal window with a transparent background, like 'urxvt -tr', and maximize this window --> urxvt shows the original wallpaper regardless of what other windows or conkys or panels are underneath. from this i conclude that this wallpaper is available _somewhere_ for applications to access.
ps: it will become more apparent if you look at how imlibsetroot works.
Last edited by ondoho (2013-11-29 09:07:24)
Offline
Can´t you just copy the root window using xcb or Xlib? (Don't ask me how to do it though)
This might be a lead.
hsetroot has an option(-write) to save an image file of the exact rendered image,so maybe you could use that too.
I believe conky can draw directly to the root window though, so if that setting is used that'll be a problem.
I think tomk means that he thinks(and I do, too) it would be weird to have wallpaper software restore a wallpaper set by different wallpaper software. If the previous wallpaper was set using your software you wouldn't need to have a screen copy, but just to reset the previous state.
Offline
It is very possible - quite easy in fact. But I don't know of any program that will do just that, as there doesn't seem much reason to need to do that.
If you know any C, you'd just open the display, get the root window, xcopyarea from root to pixmap, then use an image lib to convert the pixmap and save it to a file. Using cairo as an example, you'd set the root window as a source surface, create a png surface as a target, and paint it. All in all it'd probably be under 20 lines of code.
But if you have many programs running that are setting the background, and you don't know which one is setting the current background - nor where the image came from - you should really get back in control of your system. If you know the source image, just use `convert` to size it to the size of your monitor.
EDIT: in hindsight it isn't quite this simple. If the root window is not currently fully visible, there is no data to copy from. If the root window isn't visible, you'd have to move all other windows, XFlush, then copy from the root window.
Last edited by Trilby (2013-11-29 12:18:16)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
I think tomk means that he thinks(and I do, too) it would be weird to have wallpaper software restore a wallpaper set by different wallpaper software. If the previous wallpaper was set using your software you wouldn't need to have a screen copy, but just to reset the previous state.
That's one possibility. My first thought was that if you can set the root window background, you already have the image, so what on earth do you need a screenshot (that the op insists isn't a screenshot) for? Ondoho, you still haven't said exactly what you're trying to accomplish here; you might want to explain what it is you expect other people to spend their time helping you do. And you're correct that, in your urxvt example the image needs to be accessed from somewhere, but then that's true of the root window; how do you know that both don't access it from the same place, namely the file on your disk?
Offline
If you think this thread is a waste of your precious time, please do NOT read on.
I will get back to the "Why" in a moment, but let me clarify one more time:
The root window background image is not the same as a screenshot. A screenshot displays what is visible on my screen.
But I want to get hold of the current root window background image, even the parts that are not visible atm.
Where does my *setroot app write to? I strongly suspect that it first creates a pixmap that is exactly my screen size, then passes it to X, and X stores it somewhere in memory because it is being accessed all the time. The way Linux works i wouldn't be surprised if it's an actual file in my filesystem.
I'm not a coder or IT professional, but i'm sure i'm making sense even if terms are slightly different.
i noticed while reading up on this that the terms "root window" and "root window background" seem to be somewhat interchangeable or not clearly defined, but i hope i made it clear now ;-)
btw, if you were using a desktop environment (i am not), things are a bit different since their desktops are not the root window.
.....
It seems there is no program readily available that does what i want.
using "hsetroot -write" will write what i created in that same command line, and not the actual background.
so i'm warming up to the idea of writing my own little c program. i did some c and c++ 18 years ago, maybe i can remember sth...
i'm still hoping that i can steal the relevant part of code from some other utility.
anyhow, it seems the solution lies with xlib or xcb, as steef435 (and trillby?) suggested.
i followed this link and extracted the c code:
xcb_connect()
xcb_create_window()
xcb_create_pixmap( connection,screen->root_depth, pixmap, screen->root, width, height)
xcb_create_gc( connection, graphic_context, pixmap, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, gc_values_mask)
xcb_map_window
xcb_wait_for_event
xcb_get_property / xcb_get_property_reply / xcb_get_property_value
xcb_copy_area_checked(backbone.connection,
rootpix,
my_window,
graphic_context,
x, y,
0, 0,
width, height)this of course is not an actual c program, and i'm not sure what it does, and i still wouldn't know how to save the root window bg to a file.
also, afaiu xcb offers the same features as xlib, but faster. since speed is not important for my purposes, i guess i could achieve the same with xlib.
....
Now the long explanation of the "Why":
For a while now i've been using nitrogen to choose wallpapers, but have been setting them at login with hsetroot grep'ing the info from nitrogen's bg-saved file, because i have the feeling that nitrogen wastes precious microseconds during the login process (well, so does the grep'ing but please let's not start a discussion about it).
so it _is_ possible to set the background with another app than the one that chose it.
But more often i like to create my wallpaper from 2 or 3 components: a background color, a transparent tile, and some centerpiece (let's call it an emblem).
nitrogen does not provide that, and firing up the gimp seems a bit too much for the task.
then i noticed imlibsetroot, which has all the desired functionality.
also it writes directly to the root window bg, without saving to a file first (it still has an option to save to a file).
that's when i got the idea to write my own script/utility to compose wallpapers directly on the root window.
and how nice if it had some kind of undo mechanism (that's where the topic of this thread comes in!), so i don't have to log out/in if i don't like the result.
Last edited by ondoho (2013-12-02 08:06:50)
Offline
... and X stores it somewhere in memory because it is being accessed all the time. The way Linux works i wouldn't be surprised if it's an actual file in my filesystem.
....
so i'm warming up to the idea of writing my own little c program.
...
it seems the solution lies with xlib or xcb, as steef435 (and trillby?) suggested.
X does store it somewhere - is stores it in the X server's data. It is not a file. Xlib does not provide any way to access this information. When programs like urxvt set their background to the root background, they do not get the root background image. Instead they just tell the X server to draw their background like the root windows. The client window effectively says "I'll have what he's having" never needing to know what 'he' (to root window) actually has.
Without a compositor, you cannot copy visual data from an x window (like the root window) that isn't currently visible: there is no visual data to copy.
I'm pretty sure the simplest way to acheive what you want is to create a fullscreen window (XCreateSimpleWindow), set the background pixmap to ParentRelative (XSetWindowAttributes), raise that window to the top (XRaiseWindow), flush (XFlush), then copy the visual data (XCopyArea).
This would show a flash of the background as it runs, but if this is happening as your x session is starting anyways, no other windows would likely be visible - so there would be no apparent flash.
I suspect the only way to do this that would not require such a flash would be to 1) write/modify a compositor, or 2) rewrite the X server.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
thanks, this is very precious information.
so a little c program that creates a full screen transparent window with nothing in it, and a screen shot, should do the trick.
i think i just want to give that a try and see if it has any major flaws.
btw, i am not planning to use the wallpaper creator script at login.
Offline
Depending on your WM/DE it may be easier to write quick script using wmctrl or xdotool to hide/minimize every window, then take a screenshot.
In fact, many WM/DE's have a "show desktop" command. As long as you can also hide any taskbars, this would be - by far - the easiest approach.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
dzen2 proves very resilient to this approach, also conky and tint2.
but i thought of a(nother) hackish workaround with conky - just create a huge transparent window for a second or so and take a screenshot without the mouse pointer.
i have to see if this approach has any disadvantages, like the resulting screenshot image wouldn't be exactly the same as the original root window bg, or another application manages to get in the way...
i guess the whole script is just going to be one huge hack and might prove utterly useless in the end, but i like the challenge.
Offline
I just thought, why don't you turn it around and let the background preview be a bottom-layer window, just on top of the root window? It'll require for the WM to support it, but I believe the support for those hints is quite big.
Offline
I stumbled upon this thread while working on the same issue. I apologize for resurrecting an old thread, but I wanted to post the solution in case OP is still working on this, or if anyone else is looking to read the root window background and save it as a bitmap file.
It's possible to read the root pixmap (_XROOTPMAP_ID) to get the background image set by some apps (e.g. feh), and you don't need to draw a window on top of all other windows or anything like that. After a lot of frustrating work due to lacking XCB docs and me being a C noob I discovered how to read the pixmap and save it as a BMP file in a project I'm working on. Here's the commit with all the related code and a short explanation: https://github.com/Lokaltog/wkline/comm … 97e5909280. The code that fetches and stores the bg pixmap is here: https://github.com/Lokaltog/wkline/blob … c#L104-152. The code should be pretty straightforward, but let me know if you have any questions.
Offline
thanks for coming back here!
no, i don't think it's dead.
i tried compiling your code, but i really don't know what i'm doing there.
i added some headers and now try to eliminate compiling errors 1 by 1 but maybe you could just take a look and give some pointers?
last error message was
"rootbg.c:77:74: error: ‘widget’ undeclared (first use in this function)"
but taking in widget.h just wants to pull in more and more stuff i don't have...
here it is: http://iki.fi/danter/files/rootbg.c
edit: for now i just replaced the widget pointers with my actual screen resolution. of course some subroutine should be getting the actual resolution there.
it seems the compiler got over the first check, but now there's a new flood of errors:
In function `main':
rootbg.c:(.text+0x4d): undefined reference to `xcb_connect'
rootbg.c:(.text+0x5d): undefined reference to `xcb_connection_has_error'
rootbg.c:(.text+0x70): undefined reference to `LOG_ERR'
rootbg.c:(.text+0x8b): undefined reference to `screen_of_display'
rootbg.c:(.text+0xc4): undefined reference to `xcb_intern_atom_unchecked'
rootbg.c:(.text+0xdd): undefined reference to `xcb_intern_atom_reply'
rootbg.c:(.text+0xfe): undefined reference to `LOG_ERR'
rootbg.c:(.text+0x134): undefined reference to `xcb_get_property_unchecked'
rootbg.c:(.text+0x14d): undefined reference to `xcb_get_property_reply'
rootbg.c:(.text+0x172): undefined reference to `LOG_ERR'
rootbg.c:(.text+0x183): undefined reference to `xcb_get_property_value'
rootbg.c:(.text+0x1bc): undefined reference to `xcb_get_image'
rootbg.c:(.text+0x1da): undefined reference to `xcb_get_image_reply'
rootbg.c:(.text+0x1f6): undefined reference to `LOG_ERR'
rootbg.c:(.text+0x204): undefined reference to `xcb_get_image_data_length'
rootbg.c:(.text+0x216): undefined reference to `xcb_get_image_data'
rootbg.c:(.text+0x235): undefined reference to `rgb_to_bmp'
rootbg.c:(.text+0x258): undefined reference to `g_free'
rootbg.c:(.text+0x262): undefined reference to `DestroyMagick'
rootbg.c:(.text+0x275): undefined reference to `xcb_disconnect'
collect2: error: ld returned 1 exit statusit's probably something really simple and straightforward, if you're a C programmer...
Last edited by ondoho (2014-03-22 19:23:16)
Offline
If you don't know any C I'm not sure if this code will help you that much. For my use case (in the code I've referred to) I'm storing the BMP file in memory. If you want the image as a file you'll have to add code to write it to a file. The code isn't meant as copy/paste, I just wanted to share a possible solution to this problem that doesn't involve drawing GTK windows or whatever, you'll have to rewrite the code to fit your use case anyways. Regarding XCB, you'll have to install xcb + xcb-util (not sure if you'll need even more dependencies), if you have that installed add "-lxcb-util -lxcb" to the gcc command.
Offline
i'd love to reactivate my C, but i'll probably start with simpler stuff...
but hey, thanks for the pointers.
at least it's some kind of proof that my ideas about this aren't complete nonsense ;-)
Last edited by ondoho (2014-03-30 20:06:26)
Offline
For those that happen to fall on this discussion, I've found a small example in C using only basic Xlib functions that seems to run fine.
Offline
...and it runs fine!
strangely, i had to remove the comments in the first 2 lines to make it compile.
when i find some time i'll try to make it create .png files instead of .jpg.
thanks for the link!
Offline