gtk/
widget.rs

1// Copyright 2015-2016, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5use gdk;
6use gdk::{DragAction, Event, ModifierType};
7use gdk_sys;
8use glib::object::{Cast, IsA, WeakRef};
9use glib::signal::{connect_raw, SignalHandlerId};
10use glib::translate::*;
11use glib::ObjectExt;
12use glib_sys::gboolean;
13use gtk_sys;
14use pango;
15use std::mem::transmute;
16use std::ptr;
17
18use {Continue, DestDefaults, Inhibit, Rectangle, TargetEntry, Widget};
19
20pub struct TickCallbackId {
21    id: u32,
22    widget: WeakRef<Widget>,
23}
24
25impl TickCallbackId {
26    pub fn remove(self) {
27        if let Some(widget) = self.widget.upgrade() {
28            unsafe {
29                gtk_sys::gtk_widget_remove_tick_callback(widget.to_glib_none().0, self.id);
30            }
31        }
32    }
33}
34
35pub trait WidgetExtManual: 'static {
36    fn drag_dest_set(&self, flags: DestDefaults, targets: &[TargetEntry], actions: DragAction);
37
38    fn drag_source_set(
39        &self,
40        start_button_mask: ModifierType,
41        targets: &[TargetEntry],
42        actions: DragAction,
43    );
44
45    fn intersect(&self, area: &Rectangle, intersection: Option<&mut Rectangle>) -> bool;
46
47    fn override_font(&self, font: &pango::FontDescription);
48
49    fn connect_map_event<F: Fn(&Self, &Event) -> Inhibit + 'static>(&self, f: F)
50        -> SignalHandlerId;
51
52    fn connect_unmap_event<F: Fn(&Self, &Event) -> Inhibit + 'static>(
53        &self,
54        f: F,
55    ) -> SignalHandlerId;
56
57    fn add_tick_callback<P: Fn(&Self, &gdk::FrameClock) -> Continue + 'static>(
58        &self,
59        callback: P,
60    ) -> TickCallbackId;
61
62    fn add_events(&self, events: gdk::EventMask);
63    fn get_events(&self) -> gdk::EventMask;
64    fn set_events(&self, events: gdk::EventMask);
65}
66
67impl<O: IsA<Widget>> WidgetExtManual for O {
68    fn drag_dest_set(&self, flags: DestDefaults, targets: &[TargetEntry], actions: DragAction) {
69        let stashes: Vec<_> = targets.iter().map(|e| e.to_glib_none()).collect();
70        let t: Vec<_> = stashes.iter().map(|stash| unsafe { *stash.0 }).collect();
71        let t_ptr: *mut gtk_sys::GtkTargetEntry = if !t.is_empty() {
72            t.as_ptr() as *mut _
73        } else {
74            ptr::null_mut()
75        };
76        unsafe {
77            gtk_sys::gtk_drag_dest_set(
78                self.as_ref().to_glib_none().0,
79                flags.to_glib(),
80                t_ptr,
81                t.len() as i32,
82                actions.to_glib(),
83            )
84        };
85    }
86
87    fn drag_source_set(
88        &self,
89        start_button_mask: ModifierType,
90        targets: &[TargetEntry],
91        actions: DragAction,
92    ) {
93        let stashes: Vec<_> = targets.iter().map(|e| e.to_glib_none()).collect();
94        let t: Vec<_> = stashes.iter().map(|stash| unsafe { *stash.0 }).collect();
95        let t_ptr: *mut gtk_sys::GtkTargetEntry = if !t.is_empty() {
96            t.as_ptr() as *mut _
97        } else {
98            ptr::null_mut()
99        };
100        unsafe {
101            gtk_sys::gtk_drag_source_set(
102                self.as_ref().to_glib_none().0,
103                start_button_mask.to_glib(),
104                t_ptr,
105                t.len() as i32,
106                actions.to_glib(),
107            )
108        };
109    }
110
111    fn intersect(&self, area: &Rectangle, mut intersection: Option<&mut Rectangle>) -> bool {
112        unsafe {
113            from_glib(gtk_sys::gtk_widget_intersect(
114                self.as_ref().to_glib_none().0,
115                area.to_glib_none().0,
116                intersection.to_glib_none_mut().0,
117            ))
118        }
119    }
120
121    fn override_font(&self, font: &pango::FontDescription) {
122        unsafe {
123            gtk_sys::gtk_widget_override_font(self.as_ref().to_glib_none().0, font.to_glib_none().0)
124        }
125    }
126
127    fn connect_map_event<F: Fn(&Self, &Event) -> Inhibit + 'static>(
128        &self,
129        f: F,
130    ) -> SignalHandlerId {
131        unsafe extern "C" fn event_any_trampoline<T, F: Fn(&T, &Event) -> Inhibit + 'static>(
132            this: *mut gtk_sys::GtkWidget,
133            event: *mut gdk_sys::GdkEventAny,
134            f: &F,
135        ) -> gboolean
136        where
137            T: IsA<Widget>,
138        {
139            f(
140                &Widget::from_glib_borrow(this).unsafe_cast(),
141                &from_glib_borrow(event),
142            )
143            .to_glib()
144        }
145        unsafe {
146            let f: Box<F> = Box::new(f);
147            connect_raw(
148                self.to_glib_none().0 as *mut _,
149                b"map-event\0".as_ptr() as *mut _,
150                Some(transmute(event_any_trampoline::<Self, F> as usize)),
151                Box::into_raw(f),
152            )
153        }
154    }
155
156    fn connect_unmap_event<F: Fn(&Self, &Event) -> Inhibit + 'static>(
157        &self,
158        f: F,
159    ) -> SignalHandlerId {
160        unsafe extern "C" fn event_any_trampoline<T, F: Fn(&T, &Event) -> Inhibit + 'static>(
161            this: *mut gtk_sys::GtkWidget,
162            event: *mut gdk_sys::GdkEventAny,
163            f: &F,
164        ) -> gboolean
165        where
166            T: IsA<Widget>,
167        {
168            f(
169                &Widget::from_glib_borrow(this).unsafe_cast(),
170                &from_glib_borrow(event),
171            )
172            .to_glib()
173        }
174        unsafe {
175            let f: Box<F> = Box::new(f);
176            connect_raw(
177                self.to_glib_none().0 as *mut _,
178                b"unmap-event\0".as_ptr() as *mut _,
179                Some(transmute(event_any_trampoline::<Self, F> as usize)),
180                Box::into_raw(f),
181            )
182        }
183    }
184
185    fn add_tick_callback<P: Fn(&Self, &gdk::FrameClock) -> Continue + 'static>(
186        &self,
187        callback: P,
188    ) -> TickCallbackId {
189        let callback_data: Box<P> = Box::new(callback);
190
191        unsafe extern "C" fn callback_func<
192            O: IsA<Widget>,
193            P: Fn(&O, &gdk::FrameClock) -> Continue + 'static,
194        >(
195            widget: *mut gtk_sys::GtkWidget,
196            frame_clock: *mut gdk_sys::GdkFrameClock,
197            user_data: glib_sys::gpointer,
198        ) -> glib_sys::gboolean {
199            let widget: Widget = from_glib_borrow(widget);
200            let widget = widget.downcast().unwrap();
201            let frame_clock = from_glib_borrow(frame_clock);
202            let callback: &P = &*(user_data as *mut _);
203            let res = (*callback)(&widget, &frame_clock);
204            res.to_glib()
205        }
206        let callback = Some(callback_func::<Self, P> as _);
207
208        unsafe extern "C" fn notify_func<
209            O: IsA<Widget>,
210            P: Fn(&O, &gdk::FrameClock) -> Continue + 'static,
211        >(
212            data: glib_sys::gpointer,
213        ) {
214            let _callback: Box<P> = Box::from_raw(data as *mut _);
215        }
216        let destroy_call = Some(notify_func::<Self, P> as _);
217
218        let id = unsafe {
219            gtk_sys::gtk_widget_add_tick_callback(
220                self.as_ref().to_glib_none().0,
221                callback,
222                Box::into_raw(callback_data) as *mut _,
223                destroy_call,
224            )
225        };
226        TickCallbackId {
227            id,
228            widget: self.upcast_ref().downgrade(),
229        }
230    }
231
232    fn add_events(&self, events: gdk::EventMask) {
233        unsafe {
234            gtk_sys::gtk_widget_add_events(self.as_ref().to_glib_none().0, events.to_glib() as i32);
235        }
236    }
237
238    fn get_events(&self) -> gdk::EventMask {
239        unsafe { from_glib(gtk_sys::gtk_widget_get_events(self.as_ref().to_glib_none().0) as u32) }
240    }
241
242    fn set_events(&self, events: gdk::EventMask) {
243        unsafe {
244            gtk_sys::gtk_widget_set_events(self.as_ref().to_glib_none().0, events.to_glib() as i32);
245        }
246    }
247}