use cairo::{self, Surface};
use gdk_pixbuf;
use gdk_sys;
use glib::object::IsA;
use glib::translate::*;
use libc::{c_char, c_int};
use std::ptr;
use Cursor;
use Visual;
use Window;
use {WindowType, WindowTypeHint, WindowWindowClass};
pub struct WindowAttr {
pub title: Option<String>,
pub event_mask: i32,
pub x: Option<i32>,
pub y: Option<i32>,
pub width: i32,
pub height: i32,
pub wclass: WindowWindowClass,
pub visual: Option<Visual>,
pub window_type: WindowType,
pub cursor: Option<Cursor>,
pub override_redirect: bool,
pub type_hint: Option<WindowTypeHint>,
}
impl Default for WindowAttr {
fn default() -> WindowAttr {
skip_assert_initialized!();
WindowAttr {
title: None,
event_mask: 0,
x: None,
y: None,
width: 400,
height: 300,
wclass: WindowWindowClass::InputOutput,
visual: None,
window_type: WindowType::Toplevel,
cursor: None,
override_redirect: false,
type_hint: None,
}
}
}
impl WindowAttr {
fn get_mask(&self) -> u32 {
let mut mask: gdk_sys::GdkWindowAttributesType = 0;
if self.title.is_some() {
mask |= gdk_sys::GDK_WA_TITLE;
}
if self.x.is_some() {
mask |= gdk_sys::GDK_WA_X;
}
if self.y.is_some() {
mask |= gdk_sys::GDK_WA_Y;
}
if self.cursor.is_some() {
mask |= gdk_sys::GDK_WA_CURSOR;
}
if self.visual.is_some() {
mask |= gdk_sys::GDK_WA_VISUAL;
}
if self.override_redirect {
mask |= gdk_sys::GDK_WA_NOREDIR;
}
if self.type_hint.is_some() {
mask |= gdk_sys::GDK_WA_TYPE_HINT;
}
mask
}
}
#[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
impl<'a> ToGlibPtr<'a, *mut gdk_sys::GdkWindowAttr> for WindowAttr {
type Storage = (
Box<gdk_sys::GdkWindowAttr>,
Stash<'a, *mut gdk_sys::GdkVisual, Option<Visual>>,
Stash<'a, *mut gdk_sys::GdkCursor, Option<Cursor>>,
Stash<'a, *const c_char, Option<String>>,
);
fn to_glib_none(&'a self) -> Stash<'a, *mut gdk_sys::GdkWindowAttr, Self> {
let title = self.title.to_glib_none();
let visual = self.visual.to_glib_none();
let cursor = self.cursor.to_glib_none();
let mut attrs = Box::new(gdk_sys::GdkWindowAttr {
title: title.0 as *mut c_char,
event_mask: self.event_mask,
x: self.x.unwrap_or(0),
y: self.y.unwrap_or(0),
width: self.width,
height: self.height,
wclass: self.wclass.to_glib(),
visual: visual.0,
window_type: self.window_type.to_glib(),
cursor: cursor.0,
wmclass_name: ptr::null_mut(),
wmclass_class: ptr::null_mut(),
override_redirect: self.override_redirect.to_glib(),
type_hint: self.type_hint.unwrap_or(WindowTypeHint::Normal).to_glib(),
});
Stash(&mut *attrs, (attrs, visual, cursor, title))
}
}
impl Window {
pub fn new(parent: Option<&Window>, attributes: &WindowAttr) -> Window {
assert_initialized_main_thread!();
unsafe {
from_glib_full(gdk_sys::gdk_window_new(
parent.to_glib_none().0,
attributes.to_glib_none().0,
attributes.get_mask() as c_int,
))
}
}
pub fn create_similar_surface(
&self,
content: cairo::Content,
width: i32,
height: i32,
) -> Option<Surface> {
unsafe {
from_glib_full(gdk_sys::gdk_window_create_similar_surface(
self.to_glib_none().0,
content.into(),
width,
height,
))
}
}
}
pub trait WindowExtManual: 'static {
unsafe fn set_user_data<T>(&self, user_data: &mut T);
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
unsafe fn get_user_data<T>(&self) -> &mut T;
fn get_default_root_window() -> Window;
fn offscreen_window_set_embedder(&self, embedder: &Window);
fn offscreen_window_get_embedder(&self) -> Option<Window>;
fn offscreen_window_get_surface(&self) -> Option<Surface>;
fn get_pixbuf(
&self,
src_x: i32,
src_y: i32,
width: i32,
height: i32,
) -> Option<gdk_pixbuf::Pixbuf>;
fn get_background_pattern(&self) -> Option<cairo::Pattern>;
fn set_background_pattern(&self, pattern: Option<&cairo::Pattern>);
}
impl<O: IsA<Window>> WindowExtManual for O {
unsafe fn set_user_data<T>(&self, user_data: &mut T) {
gdk_sys::gdk_window_set_user_data(
self.as_ref().to_glib_none().0,
user_data as *mut T as *mut _,
)
}
unsafe fn get_user_data<T>(&self) -> &mut T {
let mut pointer = ::std::ptr::null_mut();
gdk_sys::gdk_window_get_user_data(self.as_ref().to_glib_none().0, &mut pointer);
&mut *(pointer as *mut T)
}
fn get_default_root_window() -> Window {
assert_initialized_main_thread!();
unsafe { from_glib_none(gdk_sys::gdk_get_default_root_window()) }
}
fn offscreen_window_set_embedder(&self, embedder: &Window) {
unsafe {
gdk_sys::gdk_offscreen_window_set_embedder(
self.as_ref().to_glib_none().0,
embedder.to_glib_none().0,
)
}
}
fn offscreen_window_get_embedder(&self) -> Option<Window> {
unsafe {
from_glib_none(gdk_sys::gdk_offscreen_window_get_embedder(
self.as_ref().to_glib_none().0,
))
}
}
fn offscreen_window_get_surface(&self) -> Option<Surface> {
skip_assert_initialized!();
unsafe {
from_glib_none(gdk_sys::gdk_offscreen_window_get_surface(
self.as_ref().to_glib_none().0,
))
}
}
fn get_pixbuf(
&self,
src_x: i32,
src_y: i32,
width: i32,
height: i32,
) -> Option<gdk_pixbuf::Pixbuf> {
skip_assert_initialized!();
unsafe {
from_glib_full(gdk_sys::gdk_pixbuf_get_from_window(
self.as_ref().to_glib_none().0,
src_x,
src_y,
width,
height,
))
}
}
fn get_background_pattern(&self) -> Option<cairo::Pattern> {
unsafe {
let ret = gdk_sys::gdk_window_get_background_pattern(self.as_ref().to_glib_none().0);
if ret.is_null() {
None
} else {
Some(cairo::Pattern::from_raw_none(ret))
}
}
}
fn set_background_pattern(&self, pattern: Option<&cairo::Pattern>) {
unsafe {
let ptr = if let Some(pattern) = pattern {
pattern.to_raw_none()
} else {
::std::ptr::null_mut()
};
gdk_sys::gdk_window_set_background_pattern(self.as_ref().to_glib_none().0, ptr);
}
}
}