1use 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}