How to draw directly on the desktop?
Asked Answered
P

1

9

I'm wondering how to draw directly on the root window in an X11 environment with Cairo (in C), in order to make widgets. I've copied some parts of the code of tint2, but it's quite enormous, and the only result I have is not satisfying. I would be pleased to have a complete working sample code, or at least some tips or little programs to study. Thank you guys !

Pentagon answered 23/8, 2011 at 17:55 Comment(6)
I don't know if drawing directly on the desktop is the best way to do this. You know you can have windows without borders/titlebars in X11 and set them to never minimize.. and be on the bottom of the stack. I think that is what most widgets do.Proclivity
Here's a similar thread with a link that my help: #1934942Lynsey
but if that's what you want look at xosd and xsnow.. although they don't use cairo, just xlib.Proclivity
I really would like to use Cairo :/ Any program that uses cairo to draw the root window ?Pentagon
Here is a little code I've written by copying parts of tint2 : link I'm not sure to understand the whole code, but I think I get the idea. However, it's not working very well. When you move a window on the top of the widget, it flickers. Maybe you guys will be able to correct it, or to give me some hints.Pentagon
Does your example print "Real Transparency Off"? If yes, and/or the depth is not 32, you will get flicker with this method. Try enabling compositing (a.k.a. desktop effects) if this is the case. There's no good method to get what you want (antialiased fonts etc and no flicker) without a working compositing manager.Pi
W
8

The "bottom" window is the root window. The problem is that in some desktop environments we have windows on top of the root window, so if you change the root window, you won't see your changes: you need to change the window that's on the top.

This program does what you ask for: draw on the root window. To test it, I suggest you to:

  • ctrl+alt+f1
  • login as root
  • stop your desktop environment ("/etc/init.d/gdm stop", "/etc/init.d/kdm stop" or whatever is needed in your distro)
  • X -noreset -retro &
  • DISPLAY=:0.0 xterm &
  • DISPLAY=:0.0 metacity &

Then, go back to X (ctrl+alt+f7 or maybe f8) and run the program.

If you want to draw on Nautilus' top window, you will need to find out its window ID and then use it as the "w" variable. The "xwininfo" command might help you testing...

#include <assert.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <cairo.h>
#include <cairo-xlib.h>

int width, height;

void draw(cairo_t *cr) {
    int quarter_w = width / 4;
    int quarter_h = height / 4;
    cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
    cairo_rectangle(cr, quarter_w, quarter_h, quarter_w * 2, quarter_h * 2);
    cairo_fill(cr);
}

int main() {
    Display *d = XOpenDisplay(NULL);
    assert(d);

    int s = DefaultScreen(d);
    Window w = RootWindow(d, s);
    width = DisplayWidth(d, s);
    height = DisplayHeight(d, s);

    cairo_surface_t *surf = cairo_xlib_surface_create(d, w,
                                  DefaultVisual(d, s),
                                  width, height);
    cairo_t *cr = cairo_create(surf);

    XSelectInput(d, w, ExposureMask);

    draw(cr);

    XEvent ev;
    while (1) {
    XNextEvent(d, &ev);
        printf("Event!\n");
        if (ev.type == Expose) {
            draw(cr);
        }
    }

    cairo_destroy(cr);
    cairo_surface_destroy(surf);
    XCloseDisplay(d);
    return 0;
}
Whitfield answered 7/10, 2011 at 14:12 Comment(3)
This worked for me. I was able to draw on another window (Sublime Text) by using xwininfo to get the window ID, then changing the RootWindow() line to: Window w = (Window) 0x2400041;, using your own value for the ID of course. One thing I noticed is that it doesn't work for every window. Using the ID for the Desktop and for Chrome didn't work. Do you have any idea why?Vituline
Actually, interestingly enough, I see the red square on Chrome when I change tabs, and an instant later it disappears...Vituline
My guess is that the application is just drawing on top of your rectangle. You can't really start drawing on another app's window since you don't know when they're going to draw again on top of the things you did. If you want to do fancy things with the desktop background then I suggest you to look at the source code of whatever app is responsible for drawing there and then change it. Or just kill it :)Whitfield

© 2022 - 2024 — McMap. All rights reserved.