rust-x-bindings / rust-xcb

Rust bindings and wrapper for XCB.
MIT License
165 stars 64 forks source link

Add example for drawing on the root window (v1) #208

Closed rogarb closed 2 years ago

rogarb commented 2 years ago

After messing around, I managed to make the draw_root_window.rs example work with the current API, so I am contributing it back.

rtbo commented 2 years ago

When I test your code, it stays in wait_for_event. Expose or key event are never reached. Does it draw on your system?

rogarb commented 2 years ago

As far as I remember, the example was working when I made the PR, but it was not working anymore tonight. It seems that defining a x::Function value in the graphical context was preventing the drawing of the rectangle on the root window. While there I removed the key press events which are not relevant for the root window, AFAIK. I just tested it now and it worked.

rtbo commented 2 years ago

On my side still nothing visible (expose is not received). In order to see the rectangle, I have to add SubwindowMode and force drawing without waiting for event. I guess it depends on the compositing manager or desktop and how it redraws the screen.

    conn.send_request(&x::CreateGc {
        cid: gc,
        drawable: x::Drawable::Window(window),
        value_list: &[
            x::Gc::Foreground(screen.black_pixel()),
            x::Gc::LineWidth(1),
            x::Gc::LineStyle(x::LineStyle::OnOffDash),
            x::Gc::SubwindowMode(x::SubwindowMode::IncludeInferiors),
        ],
    });

    loop {
        /* Draw a rectangle on screen using the graphical context */
        conn.send_request(&x::PolyRectangle {
            drawable: x::Drawable::Window(window),
            gc,
            rectangles,
        });

        /* We flush the request */
        conn.flush()?;
    }

My code is of course bad because of 100% CPU load. I don't know how to properly wait for expose event on the root window. I don't want to take too much of your time digging for this. Can you please only uncomment the relevant example section in Cargo.toml and I'll be OK to merge.

rogarb commented 2 years ago

On my computer (I am running i3 wm), the rectangle appears with a graphical context as minimal as:

      conn.send_request(&x::CreateGc {                                            
          cid: gc,                                                                
          drawable: x::Drawable::Window(window),                                  
          value_list: &[                                                          
              x::Gc::Foreground(screen.black_pixel()),                                             
              x::Gc::LineWidth(1),                                                
              x::Gc::LineStyle(x::LineStyle::OnOffDash),                          
          ],                                                                      
      });                                                                         

Could it be related to your wm using a virtual root window? After digging a bit, I found this in the Xlib documentation:

The default GC values are:

Component | Default function | GXcopy plane_mask | All ones foreground | 0 background | 1 line_width | 0 line_style | LineSolid cap_style | CapButt join_style | JoinMiter fill_style | FillSolid fill_rule | EvenOddRule arc_mode | ArcPieSlice tile | Pixmap of unspecified size filled with foreground pixel (that is, client specified pixel if any, else 0) (subsequent changes to foreground do not affect this pixmap) stipple | Pixmap of unspecified size filled with ones ts_x_origin | 0 ts_y_origin | 0 font | \<implementation dependent> subwindow_mode | ClipByChildren graphics_exposures | True clip_x_origin | 0 clip_y_origin | 0 clip_mask | None dash_offset | 0 dashes | 4 (that is, the list [4, 4])

If setting the value x::Gc::SubwindowMode(x::SubwindowMode::IncludeInferiors) helps, I will add it to the PR, since it doesn't seem to hurt.

Regarding the Expose event, it should be activated by this request:

      conn.send_request(&x::ChangeWindowAttributes {                              
          window,                                                                 
          value_list: &[                                                          
              x::Cw::BackPixel(screen.white_pixel()),                             
              // events that will be waited for                                   
              x::Cw::EventMask(x::EventMask::EXPOSURE),                           
          ],                                                                      
      });                                                                         

Does mapping the root window before the event loop (maybe even before the creation of the gc) help?

conn.send_request(&x::MapWindow { window });
rtbo commented 2 years ago

I'm using Gnome. I guess this example can't work on such DE.