diff options
author | Daniel Silverstone <daniel.silverstone@codethink.co.uk> | 2020-04-24 10:58:43 +0100 |
---|---|---|
committer | Daniel Silverstone <daniel.silverstone@codethink.co.uk> | 2020-04-24 10:58:43 +0100 |
commit | ee9f96b8369867ccc06ce312df04e6f62afeef95 (patch) | |
tree | e7fc41bd2158ea1c494976261dbd00d22a15a702 | |
parent | 3095ae240fe2d7e4746d0037ebd93e81ddc2028c (diff) | |
download | gtkplay-ee9f96b8369867ccc06ce312df04e6f62afeef95.tar.bz2 |
working closer, still buggered background
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/systray.rs | 202 |
3 files changed, 175 insertions, 31 deletions
@@ -326,11 +326,13 @@ name = "gtkplay" version = "0.1.0" dependencies = [ "cairo-rs", + "cairo-sys-rs", "gdk", "gdk-sys", "gio", "glib", "gtk", + "gtk-sys", "x11", ] @@ -8,9 +8,11 @@ edition = "2018" [dependencies] gtk = {git="https://github.com/gtk-rs/gtk"} +gtk-sys = {git="https://github.com/gtk-rs/sys"} gdk = {git="https://github.com/gtk-rs/gdk"} gdk-sys = {git="https://github.com/gtk-rs/sys"} gio = {git="https://github.com/gtk-rs/gio"} glib = {git="https://github.com/gtk-rs/glib"} cairo-rs = {git="https://github.com/gtk-rs/cairo"} +cairo-sys-rs = {git="https://github.com/gtk-rs/cairo"} x11 = {version = "*", features = ["xlib"]}
\ No newline at end of file diff --git a/src/systray.rs b/src/systray.rs index 25c5707..3370c73 100644 --- a/src/systray.rs +++ b/src/systray.rs @@ -171,11 +171,9 @@ impl SystrayInner { } fn create_dock(&self, xid: gtk::xlib::Window) { - let socket = gtk::Socket::new(); - let client = client::TrayClient::new(&socket); + let client = client::TrayClient::new(self.display.unwrap(), xid); self.tray_widget.pack_start(&client, false, false, 0); - client.show_all(); - socket.add_id(xid); + client.begin_embed() } fn notify_clients(&self) { @@ -230,7 +228,6 @@ mod client { use std::cell::RefCell; use gdk::prelude::*; - use gio::prelude::*; use gtk::prelude::*; use glib::subclass; @@ -241,12 +238,14 @@ mod client { // Properties for tray clients static PROPERTIES: [glib::subclass::Property; 1] = - [glib::subclass::Property("socket", |name| { - glib::ParamSpec::object( + [glib::subclass::Property("window", |name| { + glib::ParamSpec::int( name, - "Socket", - "Socket to be embedded", - gtk::Socket::static_type(), + "Window", + "Window to be embedded", + std::os::raw::c_int::MIN, + std::os::raw::c_int::MAX, + 0, glib::ParamFlags::CONSTRUCT_ONLY | glib::ParamFlags::READABLE | glib::ParamFlags::WRITABLE, @@ -255,9 +254,11 @@ mod client { #[derive(Debug)] pub struct TrayClientPrivate { - socket: RefCell<Option<gtk::Socket>>, - has_alpha: bool, - parent_relative: bool, + window: RefCell<gtk::xlib::Window>, + display: RefCell<*mut x11::xlib::Display>, + socket: gtk::Socket, + has_alpha: RefCell<bool>, + parent_relative: RefCell<bool>, } impl ObjectSubclass for TrayClientPrivate { @@ -270,9 +271,11 @@ mod client { fn new() -> Self { Self { - socket: RefCell::new(None), - has_alpha: false, - parent_relative: false, + window: RefCell::new(0), + display: RefCell::new(std::ptr::null_mut()), + socket: gtk::Socket::new(), + has_alpha: RefCell::new(false), + parent_relative: RefCell::new(false), } } @@ -287,12 +290,13 @@ mod client { fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; match *prop { - subclass::Property("socket", ..) => { - let socket = value + subclass::Property("window", ..) => { + let window = value .get() - .expect("Conformity expected in Object::set_property"); - println!("Replacing socket with {:?}", socket); - self.socket.replace(socket); + .expect("Conformity expected in Object::set_property") + .expect("Expected window to be provided"); + println!("Replacing socket with {:?}", window); + self.window.replace(window); } _ => unimplemented!(), } @@ -301,7 +305,7 @@ mod client { fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> { let prop = &PROPERTIES[id]; match *prop { - subclass::Property("socket", ..) => Ok(self.socket.borrow().to_value()), + subclass::Property("window", ..) => Ok(self.window.borrow().to_value()), _ => unimplemented!(), } } @@ -309,7 +313,7 @@ mod client { fn constructed(&self, obj: &glib::Object) { self.parent_constructed(obj); let self_ = obj.downcast_ref::<TrayClient>().expect("Not a TrayClient"); - self_.add(self.socket.borrow().as_ref().unwrap()); + self_.add(&self.socket); } } @@ -343,17 +347,143 @@ mod client { } fn draw(&self, widget: >k::Widget, context: &cairo::Context) -> glib::signal::Inhibit { - // TODO: Implement - self.parent_draw(widget, context); - context.set_source_rgba(0.0, 0.0, 0.0, 0.0); - context.set_operator(cairo::Operator::Source); - context.paint(); + if *self.has_alpha.borrow() { + context.set_source_rgba(0.0, 0.0, 0.0, 0.0); + context.set_operator(cairo::Operator::Source); + context.paint(); + } else { + if let Some(clip) = context.get_clip_rectangle() { + let target = context.get_group_target(); + target.flush(); + + // get xid for widget + let window = { + extern "C" { + pub fn gdk_x11_window_get_xid( + window: *mut glib::object::GObject, + ) -> *mut std::os::raw::c_void; + } + let window = widget.get_window().expect("What, no window?"); + unsafe { gdk_x11_window_get_xid(window.as_ptr() as *mut _) as u64 } + }; + gdk::error_trap_push(); + unsafe { + x11::xlib::XClearArea( + *self.display.borrow(), + window, + clip.x, + clip.y, + clip.width as u32, + clip.height as u32, + 0, + ); + } + gdk::error_trap_pop(); + + //target.mark_dirty_rectangle(); + extern "C" { + pub fn cairo_surface_mark_dirty_rectangle( + cr: *mut cairo_sys::cairo_surface_t, + x: std::os::raw::c_int, + y: std::os::raw::c_int, + w: std::os::raw::c_int, + h: std::os::raw::c_int, + ); + } + unsafe { + cairo_surface_mark_dirty_rectangle( + target.to_raw_none(), + clip.x, + clip.y, + clip.width, + clip.height, + ) + } + } + } glib::signal::Inhibit(false) } } impl ContainerImpl for TrayClientPrivate {} impl BinImpl for TrayClientPrivate {} + impl TrayClientPrivate { + fn learn_about_window(&self) { + // Our goal here is to learn about the window, especially in terms + // of its visual, so that we can learn more about how to render + // the icon usefully + gdk::error_trap_push(); + let attr = unsafe { + let mut attr: x11::xlib::XWindowAttributes = + std::mem::MaybeUninit::zeroed().assume_init(); + x11::xlib::XGetWindowAttributes( + *self.display.borrow(), + *self.window.borrow() as u64, + &mut attr as *mut _, + ); + attr + }; + gdk::error_trap_pop(); + let screen = unsafe { gdk_sys::gdk_screen_get_default() }; + + let visual = { + extern "C" { + pub fn gdk_x11_screen_lookup_visual( + screen: *mut gdk_sys::GdkScreen, + xvisualid: x11::xlib::VisualID, + ) -> *mut gdk_sys::GdkVisual; + } + unsafe { gdk_x11_screen_lookup_visual(screen, (*attr.visual).visualid) } + }; + unsafe { + extern "C" { + pub fn gtk_widget_set_visual( + widget: *mut gtk_sys::GtkWidget, + visual: *mut gdk_sys::GdkVisual, + ); + } + gtk_widget_set_visual( + self.socket.upcast_ref::<gtk::Widget>().to_glib_none().0, + visual, + ); + } + let (r, g, b, d) = unsafe { + let mut red = 0; + gdk_sys::gdk_visual_get_red_pixel_details( + visual, + std::ptr::null_mut(), + std::ptr::null_mut(), + &mut red as *mut _, + ); + let mut green = 0; + gdk_sys::gdk_visual_get_red_pixel_details( + visual, + std::ptr::null_mut(), + std::ptr::null_mut(), + &mut green as *mut _, + ); + let mut blue = 0; + gdk_sys::gdk_visual_get_red_pixel_details( + visual, + std::ptr::null_mut(), + std::ptr::null_mut(), + &mut blue as *mut _, + ); + (red, green, blue, gdk_sys::gdk_visual_get_depth(visual)) + }; + let visual_alpha = (r + g + b) < d; + self.has_alpha.replace( + visual_alpha + && unsafe { + gdk_sys::gdk_display_supports_composite(gdk_sys::gdk_screen_get_display( + screen, + )) != 0 + }, + ); + println!("Has alpha: {}", self.has_alpha.borrow()); + } + } + glib_wrapper! { pub struct TrayClient( Object<subclass::simple::InstanceStruct<TrayClientPrivate>, @@ -368,11 +498,21 @@ mod client { } impl TrayClient { - pub fn new(socket: >k::Socket) -> Self { - glib::Object::new(Self::static_type(), &[("socket", socket)]) + pub fn new(display: *mut x11::xlib::Display, window: gtk::xlib::Window) -> Self { + let ret = glib::Object::new(Self::static_type(), &[("window", &window)]) .expect("Failed to create TrayClient") .downcast::<TrayClient>() - .expect("TrayClient is not of expected type") + .expect("TrayClient is not of expected type"); + let priv_ = TrayClientPrivate::from_instance(&ret); + priv_.display.replace(display); + ret + } + + pub fn begin_embed(&self) { + let priv_ = TrayClientPrivate::from_instance(self); + priv_.learn_about_window(); + self.show_all(); + priv_.socket.add_id(*priv_.window.borrow()); } } } |