1 // Container.cs - customizations to Gtk.Container
2 //
3 // Authors: Mike Kestner  <mkestner@ximian.com>
4 //
5 // Copyright (c) 2004 Novell, Inc.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of version 2 of the Lesser GNU General
9 // Public License as published by the Free Software Foundation.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this program; if not, write to the
18 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 // Boston, MA 02111-1307, USA.
20 
21 namespace Gtk {
22 
23 	using System;
24 	using System.Collections;
25 	using System.Runtime.InteropServices;
26 
27 	public partial class Container : IEnumerable {
28 
29 		[DllImport("gtksharpglue-3")]
gtksharp_container_child_get_property(IntPtr container, IntPtr child, IntPtr property, ref GLib.Value value)30 		static extern void gtksharp_container_child_get_property (IntPtr container, IntPtr child, IntPtr property, ref GLib.Value value);
31 
ChildGetProperty(Gtk.Widget child, string property_name)32 		public GLib.Value ChildGetProperty (Gtk.Widget child, string property_name) {
33 			GLib.Value value = new GLib.Value ();
34 
35 			IntPtr native = GLib.Marshaller.StringToPtrGStrdup (property_name);
36 			gtksharp_container_child_get_property (Handle, child.Handle, native, ref value);
37 			GLib.Marshaller.Free (native);
38 			return value;
39 		}
40 
GetEnumerator()41 		public IEnumerator GetEnumerator ()
42 		{
43 			return Children.GetEnumerator ();
44 		}
45 
46 		class ChildAccumulator {
47 			public ArrayList Children = new ArrayList ();
48 
Add(Gtk.Widget widget)49 			public void Add (Gtk.Widget widget)
50 			{
51 				Children.Add (widget);
52 			}
53 		}
54 
55 		public IEnumerable AllChildren {
56 			get {
57 				ChildAccumulator acc = new ChildAccumulator ();
58 				Forall (new Gtk.Callback (acc.Add));
59 				return acc.Children;
60 			}
61 		}
62 
63 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_container_get_focus_chain(IntPtr raw, out IntPtr list_ptr)64 		static extern bool gtk_container_get_focus_chain (IntPtr raw, out IntPtr list_ptr);
65 
66 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_container_set_focus_chain(IntPtr raw, IntPtr list_ptr)67 		static extern void gtk_container_set_focus_chain (IntPtr raw, IntPtr list_ptr);
68 
69 		public Widget[] FocusChain {
70 			get {
71 				IntPtr list_ptr;
72 				bool success = gtk_container_get_focus_chain (Handle, out list_ptr);
73 				if (!success)
74 					return new Widget [0];
75 
76 				GLib.List list = new GLib.List (list_ptr);
77 				Widget[] result = new Widget [list.Count];
78 				for (int i = 0; i < list.Count; i++)
79 					result [i] = list [i] as Widget;
80 				return result;
81 			}
82 			set {
83 				GLib.List list = new GLib.List (IntPtr.Zero);
84 				foreach (Widget val in value)
85 					list.Append (val.Handle);
86 				gtk_container_set_focus_chain (Handle, list.Handle);
87 			}
88 
89 		}
90 
91 		[DllImport("gtksharpglue-3")]
gtksharp_container_base_forall(IntPtr handle, bool include_internals, IntPtr cb, IntPtr data)92 		static extern void gtksharp_container_base_forall (IntPtr handle, bool include_internals, IntPtr cb, IntPtr data);
93 
94 		[DllImport("gtksharpglue-3")]
gtksharp_container_override_forall(IntPtr gtype, ForallDelegate cb)95 		static extern void gtksharp_container_override_forall (IntPtr gtype, ForallDelegate cb);
96 
97 		[DllImport("gtksharpglue-3")]
gtksharp_container_invoke_gtk_callback(IntPtr cb, IntPtr handle, IntPtr data)98 		static extern void gtksharp_container_invoke_gtk_callback (IntPtr cb, IntPtr handle, IntPtr data);
99 
100 		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
ForallDelegate(IntPtr container, bool include_internals, IntPtr cb, IntPtr data)101 		delegate void ForallDelegate (IntPtr container, bool include_internals, IntPtr cb, IntPtr data);
102 
103 		static ForallDelegate ForallOldCallback;
104 		static ForallDelegate ForallCallback;
105 
106 		public struct CallbackInvoker {
107 			IntPtr cb;
108 			IntPtr data;
109 
CallbackInvokerGtk.Container.CallbackInvoker110 			internal CallbackInvoker (IntPtr cb, IntPtr data)
111 			{
112 				this.cb = cb;
113 				this.data = data;
114 			}
115 
116 			internal IntPtr Data {
117 				get {
118 					return data;
119 				}
120 			}
121 
122 			internal IntPtr Callback {
123 				get {
124 					return cb;
125 				}
126 			}
127 
InvokeGtk.Container.CallbackInvoker128 			public void Invoke (Widget w)
129 			{
130 				gtksharp_container_invoke_gtk_callback (cb, w.Handle, data);
131 			}
132 		}
133 
ForallOld_cb(IntPtr container, bool include_internals, IntPtr cb, IntPtr data)134 		static void ForallOld_cb (IntPtr container, bool include_internals, IntPtr cb, IntPtr data)
135 		{
136 			try {
137 				//GtkContainer's unmanaged dispose calls forall, but by that time the managed object is gone
138 				//so it couldn't do anything useful, and resurrecting it would cause a resurrection cycle.
139 				//In that case, just chain to the native base in case it can do something.
140 				Container obj = (Container) GLib.Object.TryGetObject (container);
141 				if (obj != null) {
142 					CallbackInvoker invoker = new CallbackInvoker (cb, data);
143 					obj.ForAll (include_internals, invoker);
144 				} else {
145 					gtksharp_container_base_forall (container, include_internals, cb, data);
146 				}
147 			} catch (Exception e) {
148 				GLib.ExceptionManager.RaiseUnhandledException (e, false);
149 			}
150 		}
151 
OverrideForallOld(GLib.GType gtype)152 		static void OverrideForallOld (GLib.GType gtype)
153 		{
154 			if (ForallOldCallback == null)
155 				ForallOldCallback = new ForallDelegate (ForallOld_cb);
156 			gtksharp_container_override_forall (gtype.Val, ForallOldCallback);
157 		}
158 
159 		[Obsolete ("Override the ForAll(bool,Gtk.Callback) method instead")]
160 		[GLib.DefaultSignalHandler (Type=typeof(Gtk.Container), ConnectionMethod="OverrideForallOld")]
ForAll(bool include_internals, CallbackInvoker invoker)161 		protected virtual void ForAll (bool include_internals, CallbackInvoker invoker)
162 		{
163 			gtksharp_container_base_forall (Handle, include_internals, invoker.Callback, invoker.Data);
164 		}
165 
Forall_cb(IntPtr container, bool include_internals, IntPtr cb, IntPtr data)166 		static void Forall_cb (IntPtr container, bool include_internals, IntPtr cb, IntPtr data)
167 		{
168 			try {
169 				//GtkContainer's unmanaged dispose calls forall, but by that time the managed object is gone
170 				//so it couldn't do anything useful, and resurrecting it would cause a resurrection cycle.
171 				//In that case, just chain to the native base in case it can do something.
172 				Container obj = (Container) GLib.Object.TryGetObject (container);
173 				if (obj != null) {
174 					CallbackInvoker invoker = new CallbackInvoker (cb, data);
175 					obj.ForAll (include_internals, new Gtk.Callback (invoker.Invoke));
176 				} else {
177 					gtksharp_container_base_forall (container, include_internals, cb, data);
178 				}
179 			} catch (Exception e) {
180 				GLib.ExceptionManager.RaiseUnhandledException (e, false);
181 			}
182 		}
183 
OverrideForall(GLib.GType gtype)184 		static void OverrideForall (GLib.GType gtype)
185 		{
186 			if (ForallCallback == null)
187 				ForallCallback = new ForallDelegate (Forall_cb);
188 			gtksharp_container_override_forall (gtype.Val, ForallCallback);
189 		}
190 
191 		[GLib.DefaultSignalHandler (Type=typeof(Gtk.Container), ConnectionMethod="OverrideForall")]
ForAll(bool include_internals, Gtk.Callback callback)192 		protected virtual void ForAll (bool include_internals, Gtk.Callback callback)
193 		{
194 			CallbackInvoker invoker;
195 			try {
196 				invoker = (CallbackInvoker)callback.Target;
197 			} catch {
198 				throw new ApplicationException ("ForAll can only be called as \"base.ForAll()\". Use Forall() or Foreach().");
199 			}
200 			gtksharp_container_base_forall (Handle, include_internals, invoker.Callback, invoker.Data);
201 		}
202 
203 		// Compatibility code for old ChildType() virtual method
ObsoleteChildType_cb(IntPtr raw)204 		static IntPtr ObsoleteChildType_cb (IntPtr raw)
205 		{
206 			try {
207 				Container obj = GLib.Object.GetObject (raw, false) as Container;
208 				GLib.GType gtype = obj.ChildType ();
209 				return gtype.Val;
210 			} catch (Exception e) {
211 				GLib.ExceptionManager.RaiseUnhandledException (e, false);
212 			}
213 
214 			return GLib.GType.Invalid.Val;
215 		}
216 
217 		static ChildTypeNativeDelegate ObsoleteChildTypeVMCallback;
218 
OverrideObsoleteChildType(GLib.GType gtype)219 		static void OverrideObsoleteChildType (GLib.GType gtype)
220 		{
221 			if (ObsoleteChildTypeVMCallback == null)
222 				ObsoleteChildTypeVMCallback = new ChildTypeNativeDelegate (ObsoleteChildType_cb);
223 			OverrideChildType (gtype, ObsoleteChildTypeVMCallback); // -> autogenerated method
224 		}
225 
226 		[Obsolete ("Replaced by OnChildType for implementations and SupportedChildType for callers.")]
227 		[GLib.DefaultSignalHandler (Type=typeof(Gtk.Container), ConnectionMethod="OverrideObsoleteChildType")]
ChildType()228 		public virtual GLib.GType ChildType() {
229 			return InternalChildType (); // -> autogenerated method
230 		}
231 
232 		public class ContainerChild {
233 			protected Container parent;
234 			protected Widget child;
235 
ContainerChild(Container parent, Widget child)236 			public ContainerChild (Container parent, Widget child)
237 			{
238 				this.parent = parent;
239 				this.child = child;
240 			}
241 
242 			public Container Parent {
243 				get {
244 					return parent;
245 				}
246 			}
247 
248 			public Widget Child {
249 				get {
250 					return child;
251 				}
252 			}
253 		}
254 
255 		public virtual ContainerChild this [Widget w] {
256 			get {
257 				return new ContainerChild (this, w);
258 			}
259 		}
260 	}
261 }
262