Skip to content
This repository has been archived by the owner on Nov 26, 2020. It is now read-only.

Commit

Permalink
Merge branch 'master' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
mzabaluev committed Jul 2, 2015
2 parents d332d3e + 3067651 commit a64d601
Show file tree
Hide file tree
Showing 5 changed files with 426 additions and 28 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "grust"
version = "0.1.3"
version = "0.2.0-dev"
authors = ["Mikhail Zabaluev <[email protected]>"]
license = "LGPL-2.1+"
readme = "README.md"
Expand All @@ -15,6 +15,6 @@ generated crates.
repository = "https://github.com/gi-rust/grust.git"

[dependencies]
glib-2_0-sys = "0.1.0"
glib-2_0-sys = "0.1.1"
gobject-2_0-sys = "0.1.0"
libc = "0.1"
46 changes: 23 additions & 23 deletions src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

use gtype::GType;
use types::gpointer;
use util::{box_free, box_from_pointer, box_into_pointer};

use gobject as ffi;

Expand All @@ -35,37 +36,36 @@ pub fn type_of<T>() -> GType where T: BoxedType
<T as BoxedType>::get_type()
}

unsafe fn box_from_raw<T>(ptr: gpointer) -> Box<T> {
mem::transmute(ptr)
}

unsafe fn box_into_raw<T>(b: Box<T>) -> gpointer {
mem::transmute(b)
}

extern "C" fn box_copy<T>(raw: gpointer) -> gpointer
unsafe extern "C" fn box_copy<T>(raw: gpointer) -> gpointer
where T: Clone
{
let boxed: Box<T> = unsafe { box_from_raw(raw) };
let boxed: Box<T> = box_from_pointer(raw);
let copy: Box<T> = boxed.clone();
unsafe {
// Prevent the original value from being dropped
box_into_raw(boxed);
box_into_raw(copy) as gpointer
}
// Prevent the original value from being dropped
mem::forget(boxed);
box_into_pointer(copy)
}

extern "C" fn box_free<T>(raw: gpointer) {
let boxed: Box<T> = unsafe { box_from_raw(raw) };
mem::drop(boxed);
unsafe fn into_boxed_copy_func(callback: unsafe extern "C" fn(gpointer) -> gpointer)
-> ffi::GBoxedCopyFunc
{
mem::transmute(callback)
}

pub fn register_box_type<T>(name: &str) -> GType where T: Clone + Send {
unsafe fn into_boxed_free_func(callback: unsafe extern "C" fn(gpointer))
-> ffi::GBoxedFreeFunc
{
mem::transmute(callback)
}

pub fn register_box_type<T>(name: &str) -> GType
where T: Clone + Send + 'static
{
let c_name = CString::new(name).unwrap();
let raw = unsafe {
ffi::g_boxed_type_register_static(c_name.as_ptr(),
box_copy::<T>,
box_free::<T>)
into_boxed_copy_func(box_copy::<T>),
into_boxed_free_func(box_free::<T>))
};
assert!(raw != 0, "failed to register type \"{}\"", name);
unsafe { GType::from_raw(raw) }
Expand All @@ -82,10 +82,10 @@ impl<T> BoxedType for Box<T> where T: BoxRegistered {
}

unsafe fn from_ptr(raw: gpointer) -> Box<T> {
box_from_raw(raw)
box_from_pointer(raw)
}

unsafe fn into_ptr(self) -> gpointer {
box_into_raw(self) as gpointer
box_into_pointer(self)
}
}
213 changes: 211 additions & 2 deletions src/mainloop.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014 Mikhail Zabaluev <[email protected]>
// Copyright (C) 2014, 2015 Mikhail Zabaluev <[email protected]>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
Expand All @@ -17,12 +17,103 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

use refcount::{Refcount, Ref};
use types::FALSE;
use types::{FALSE, TRUE};
use types::{gboolean, gint, gpointer, guint};
use util::{box_free, box_from_pointer, box_into_pointer, into_destroy_notify};
use wrap;
use wrap::Wrapper;

use glib as ffi;
use gobject;
use std::convert;
use std::marker;
use std::mem;

pub const PRIORITY_DEFAULT : gint = ffi::G_PRIORITY_DEFAULT;
pub const PRIORITY_DEFAULT_IDLE : gint = ffi::G_PRIORITY_DEFAULT_IDLE;
pub const PRIORITY_HIGH : gint = ffi::G_PRIORITY_HIGH;
pub const PRIORITY_HIGH_IDLE : gint = ffi::G_PRIORITY_HIGH_IDLE;
pub const PRIORITY_LOW : gint = ffi::G_PRIORITY_LOW;

pub enum CallbackResult { Remove, Continue }
pub use self::CallbackResult::*;

pub struct RawCallback {
func: ffi::GSourceFunc,
data: gpointer,
destroy: ffi::GDestroyNotify
}

impl Drop for RawCallback {
fn drop(&mut self) {
(self.destroy)(self.data);
}
}

unsafe fn into_source_func(func: unsafe extern "C" fn(gpointer) -> gboolean)
-> ffi::GSourceFunc
{
mem::transmute(func)
}

unsafe extern "C" fn source_func<F>(callback_data: gpointer) -> gboolean
where F: FnMut() -> CallbackResult
{
let mut callback: Box<F> = box_from_pointer(callback_data);
let res = callback();
mem::forget(callback);
match res {
Remove => FALSE,
Continue => TRUE
}
}

unsafe extern "C" fn source_once_func<F>(callback_data: gpointer) -> gboolean
where F: FnOnce()
{
let mut holder: Box<Option<F>> = box_from_pointer(callback_data);
let callback = holder.take().expect("a callback closure expected");
mem::forget(holder);
callback();
FALSE
}

pub struct SourceCallback(RawCallback);

impl Into<RawCallback> for SourceCallback {
#[inline]
fn into(self) -> RawCallback {
self.0
}
}

impl SourceCallback {
pub fn new<F>(closure: F) -> Self
where F: Send + 'static, F: FnMut() -> CallbackResult
{
let boxed_closure = Box::new(closure);
SourceCallback(unsafe {
RawCallback {
func: into_source_func(source_func::<F>),
data: box_into_pointer(boxed_closure),
destroy: into_destroy_notify(box_free::<F>)
}
})
}

pub fn once<F>(closure: F) -> Self
where F: Send + 'static, F: FnOnce()
{
let holder = Box::new(Some(closure));
SourceCallback(unsafe {
RawCallback {
func: into_source_func(source_once_func::<F>),
data: box_into_pointer(holder),
destroy: into_destroy_notify(box_free::<Option<F>>)
}
})
}
}

#[repr(C)]
pub struct MainContext {
Expand All @@ -41,6 +132,19 @@ impl MainContext {
wrap::from_raw(ffi::g_main_context_default())
}
}

pub fn invoke(&self, callback: SourceCallback) {
self.invoke_full(PRIORITY_DEFAULT, callback)
}

pub fn invoke_full(&self, priority: gint, callback: SourceCallback) {
let raw: RawCallback = callback.into();
unsafe {
ffi::g_main_context_invoke_full(self.as_mut_ptr(),
priority, raw.func, raw.data, Some(raw.destroy));
}
mem::forget(raw);
}
}

impl Refcount for MainContext {
Expand All @@ -56,6 +160,111 @@ impl Refcount for MainContext {

g_impl_boxed_type_for_ref!(MainContext, gobject::g_main_context_get_type);

#[repr(C)]
pub struct Source<Callback = SourceCallback> {
raw: ffi::GSource,
phantom_data: marker::PhantomData<Callback>
}

#[repr(C)]
pub struct AttachedSource<Callback> {
raw: ffi::GSource,
phantom_data: marker::PhantomData<Callback>
}

unsafe impl<C> Send for Source<C> where C: Into<RawCallback> { }

unsafe impl<C> Send for AttachedSource<C> where C: Into<RawCallback> { }
unsafe impl<C> Sync for AttachedSource<C> where C: Into<RawCallback> { }

macro_rules! common_source_impls {
($name:ident) => {
unsafe impl<C> Wrapper for $name<C> {
type Raw = ffi::GSource;
}

impl<C> Refcount for $name<C> {
unsafe fn inc_ref(&self) {
ffi::g_source_ref(self.as_mut_ptr());
}
unsafe fn dec_ref(&self) {
ffi::g_source_unref(self.as_mut_ptr());
}
}
}
}

common_source_impls!(Source);
common_source_impls!(AttachedSource);

impl<C> Source<C> where C: Into<RawCallback> {
pub fn set_callback(&self, callback: C)
{
let raw: RawCallback = callback.into();
unsafe {
ffi::g_source_set_callback(self.as_mut_ptr(),
raw.func, raw.data, Some(raw.destroy));
}
mem::forget(raw);
}

pub fn set_priority(&self, priority: gint) {
unsafe {
ffi::g_source_set_priority(self.as_mut_ptr(), priority);
}
}
}

impl<C> Ref<Source<C>> {
pub fn attach(self, ctx: &MainContext) -> Ref<AttachedSource<C>> {
unsafe {
let source_ptr = self.as_mut_ptr();
ffi::g_source_attach(source_ptr, ctx.as_mut_ptr());
mem::forget(self);
Ref::from_raw(source_ptr)
}
}
}

impl<C> AttachedSource<C> {
#[inline]
pub fn as_source(&self) -> &Source<C> {
unsafe { wrap::from_raw(self.as_ptr()) }
}

pub fn destroy(&self) {
unsafe { ffi::g_source_destroy(self.as_mut_ptr()) }
}
}

impl<C> convert::AsRef<Source<C>> for AttachedSource<C> {
#[inline]
fn as_ref(&self) -> &Source<C> {
self.as_source()
}
}

pub fn idle_source_new() -> Ref<Source> {
unsafe {
let source = ffi::g_idle_source_new();
Ref::from_raw(source)
}
}

pub fn timeout_source_new(interval: guint) -> Ref<Source> {
unsafe {
let source = ffi::g_timeout_source_new(interval);
Ref::from_raw(source)
}
}

pub fn timeout_source_new_seconds(interval: guint) -> Ref<Source> {
unsafe {
let source = ffi::g_timeout_source_new_seconds(interval);
Ref::from_raw(source)
}
}

#[repr(C)]
pub struct MainLoop {
raw: ffi::GMainLoop
Expand Down
24 changes: 23 additions & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

use types::{gboolean,FALSE};
use types::{gboolean, gpointer, FALSE};

use glib;

use std::ascii;
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::mem;
use std::str;

#[inline]
Expand All @@ -39,3 +42,22 @@ pub fn escape_bytestring<'a>(s: &'a [u8]) -> Cow<'a, str> {
let string = unsafe { String::from_utf8_unchecked(acc) };
string.into()
}

pub unsafe extern "C" fn box_free<T>(raw: gpointer) {
let b: Box<T> = mem::transmute(raw);
mem::drop(b);
}

pub unsafe fn into_destroy_notify(func: unsafe extern "C" fn(gpointer))
-> glib::GDestroyNotify
{
mem::transmute(func)
}

pub unsafe fn box_from_pointer<T>(p: gpointer) -> Box<T> {
mem::transmute(p)
}

pub fn box_into_pointer<T>(b: Box<T>) -> gpointer {
unsafe { mem::transmute(b) }
}
Loading

0 comments on commit a64d601

Please sign in to comment.