summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <daniel.silverstone@codethink.co.uk>2020-04-24 10:58:43 +0100
committerDaniel Silverstone <daniel.silverstone@codethink.co.uk>2020-04-24 10:58:43 +0100
commitee9f96b8369867ccc06ce312df04e6f62afeef95 (patch)
treee7fc41bd2158ea1c494976261dbd00d22a15a702
parent3095ae240fe2d7e4746d0037ebd93e81ddc2028c (diff)
downloadgtkplay-ee9f96b8369867ccc06ce312df04e6f62afeef95.tar.bz2
working closer, still buggered background
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--src/systray.rs202
3 files changed, 175 insertions, 31 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 574e545..b03422a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
]
diff --git a/Cargo.toml b/Cargo.toml
index 59688c5..3eb9073 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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: &gtk::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: &gtk::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());
}
}
}