From c2d90eb2823345ada94fd4382d49985fce2097fe Mon Sep 17 00:00:00 2001 From: Bob Smith Date: Tue, 18 Sep 2001 03:57:16 +0000 Subject: [PATCH] Reworked the event system. Added partial Button and Label classes. Notes added asking many important questions. svn path=/trunk/gtk-sharp/; revision=858 --- NOTES | 30 +++++++ gtk/Button.cs | 70 +++++++++++++++ gtk/Label.cs | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++ gtk/Object.cs | 24 ++++- gtk/Widget.cs | 54 ++++++------ gtk/Window.cs | 18 +++- 6 files changed, 405 insertions(+), 31 deletions(-) create mode 100644 NOTES create mode 100644 gtk/Button.cs create mode 100644 gtk/Label.cs diff --git a/NOTES b/NOTES new file mode 100644 index 000000000..72429e394 --- /dev/null +++ b/NOTES @@ -0,0 +1,30 @@ +Mike, + +We have some problems. Some methods are going to return a gtk widget which +will need to be wrapped again into a c# class. This will have a nasty +reaction when callbacks are added to the wrapper, then the wrapper is nuked +when complete. It will leave a rogue pointer of some kind laying around, and +callbacks won't work as expected. + +Proposed solution: +Every GTK# class is a wrapper class. With a constructor for a GtkWidget* and +one for a default _new. Events are done as in CVS, except that the events +object will need to be bound to the GtkWidget owning it, and when a wrapper +is created, that Events object is resurected. This way, even if there is no +wrapper in existance, signals will function properly, and multiple wrappers +will work properly too. The event object will register a delete signal with +the widget so that when its nuked, it has a chance to free itself. Are we +going to have to tell the garbage collector to stay away from this class? +We might need our own class for this, and this class might not be able to be +written in c#. + + +Problem number two is with taking an arbitrary GtkWidget, and constructing a +wrapper as needed. Which wrapper is created? A simple GtkWidget wouldnt work +too well if the GtkWidget is really a button. We need to deside how to +handle this. Should we just return a GtkWidget, and force the developer to +pass the GtkWidget back to a constructor for the desided apon Widget wrapper? +How does gtk itself deal with this? Are we going to need a database of +widget wrappers for this? + +Bob diff --git a/gtk/Button.cs b/gtk/Button.cs new file mode 100644 index 000000000..b6961f276 --- /dev/null +++ b/gtk/Button.cs @@ -0,0 +1,70 @@ +// GTK.Button.cs - GTK Button class implementation +// +// Author: Bob Smith +// +// (c) 2001 Bob Smith + +namespace GTK { + + using System; + using System.Runtime.InteropServices; + + public class Button : Widget { + + private static readonly object ClickedEvent = new object (); + public event EventHandler Clicked + { + add + { + if (Events[ClickedEvent] == null) + { + ConnectSignal ("clicked", new SimpleCallback (EmitDeleteEvent)); + } + Events.AddHandler (ClickedEvent, value); + } + remove + { + Events.RemoveHandler (ClickedEvent, value); + } + } + + private void EmitClickedEvent (IntPtr obj) + { + EventHandler eh = (EventHandler)(_events[ClickedEvent]); + if (eh != null) + { + EventArgs args = new EventArgs (); + eh(this, args); + } + } + + /// + /// Button Object Constructor + /// + /// + /// + /// Constructs a Button Wrapper. + /// + + public Button (IntPtr o) + { + Object = o; + } + + /// + /// Button Constructor + /// + /// + /// + /// Constructs a new Button with the specified content. + /// + + [DllImport("gtk-1.3")] + static extern IntPtr gtk_label_new_with_label (String str); + + public Button (String str) + { + Object = gtk_button_new_with_label (str); + } + } +} diff --git a/gtk/Label.cs b/gtk/Label.cs new file mode 100644 index 000000000..d3dc62fb6 --- /dev/null +++ b/gtk/Label.cs @@ -0,0 +1,240 @@ +// GTK.Label.cs - GTK Label class implementation +// +// Author: Bob Smith +// +// (c) 2001 Bob Smith + +namespace GTK { + + using System; + using System.Runtime.InteropServices; + + public class Label : Widget { + + /// + /// Label Object Constructor + /// + /// + /// + /// Constructs a Label Wrapper. + /// + + public Label (IntPtr o) + { + Object = o; + } + + /// + /// Label Constructor + /// + /// + /// + /// Constructs a new Label with the specified content. + /// + + [DllImport("gtk-1.3")] + static extern IntPtr gtk_label_new (String str); + + public Label (String str) + { + Object = gtk_label_new (str); + } + + /// + /// Text Property + /// + /// + /// + /// The raw text of the label. + /// + + [DllImport("gtk-1.3")] + static extern void gtk_label_set_text (IntPtr hnd, const String str); + [DllImport("gtk-1.3")] + static extern String gtk_label_get_text (IntPtr hnd); + + public String Text { + get + { + return gtk_label_get_text (Object); + } + set + { + gtk_label_set_text (Object, value); + } + } + + /// + /// Markup Property + /// + /// + /// + /// Text to parse. + /// + + [DllImport("gtk-1.3")] + static extern void gtk_label_set_markup (IntPtr hnd, const String str); + + public String Markup { + set + { + gtk_label_set_markup (Object, value); + } + } + + /// + /// Label Property + /// + /// + /// + /// Parsed content. + /// + + [DllImport("gtk-1.3")] + static extern void gtk_label_set_label (IntPtr hnd, const String str); + [DllImport("gtk-1.3")] + static extern String gtk_label_get_label (IntPtr hnd); + + public String Label { + get + { + return gtk_label_get_label (Object); + } + set + { + gtk_label_set_label (Object, value); + } + } + + /// + /// Selectable Property + /// + /// + /// + /// Is the user able to select text from the label. + /// + + [DllImport("gtk-1.3")] + static extern void gtk_label_set_selectable (IntPtr hnd, bool setting); + [DllImport("gtk-1.3")] + static extern bool gtk_label_get_selectable (IntPtr hnd); + + public bool Selectable { + get + { + return gtk_label_get_selectable (Object); + } + set + { + gtk_label_set_selectable (Object, value, value); + } + } + + /// + /// UseUnderline Property + /// + /// + /// + /// Indicates that the next character after an underline should be the accelerator key. + /// + + [DllImport("gtk-1.3")] + static extern void gtk_label_set_use_underline (IntPtr hnd, bool setting); + [DllImport("gtk-1.3")] + static extern bool gtk_label_get_use_underline (IntPtr hnd); + + public bool UseUnderline { + get + { + return gtk_label_get_use_underline (Object); + } + set + { + gtk_label_set_use_underline (Object, value, value); + } + } + + /// + /// UseMarkup Property + /// + /// + /// + /// Indicates that the text contains markup. + /// + + [DllImport("gtk-1.3")] + static extern void gtk_label_set_use_markup (IntPtr hnd, bool setting); + [DllImport("gtk-1.3")] + static extern bool gtk_label_get_use_markup (IntPtr hnd); + + public bool UseMarkup { + get + { + return gtk_label_get_use_markup (Object); + } + set + { + gtk_label_set_use_markup (Object, value, value); + } + } + + /// + /// LineWrap Property + /// + /// + /// + /// Indicates that the text is automatically wrapped if to long. + /// + + [DllImport("gtk-1.3")] + static extern void gtk_label_set_line_wrap (IntPtr hnd, bool setting); + [DllImport("gtk-1.3")] + static extern bool gtk_label_get_line_wrap (IntPtr hnd); + + public bool LineWrap { + get + { + return gtk_label_get_line_wrap (Object); + } + set + { + gtk_label_set_line_wrap (Object, value, value); + } + } + + +/* +TODO: + +void gtk_label_set_attributes(GtkLabel *label, PangoAttrList *attrs); +void gtk_label_set_markup_with_mnemonic(GtkLabel *label, const gchar *str); +void gtk_label_set_pattern(GtkLabel *label, const gchar *pattern); +void gtk_label_set_justify(GtkLabel *label, GtkJustification jtype); +guint gtk_label_parse_uline(GtkLabel *label, const gchar *string); +void gtk_label_get_layout_offsets (GtkLabel *label, + gint *x, + gint *y); +guint gtk_label_get_mnemonic_keyval (GtkLabel *label); +GtkWidget* gtk_label_new_with_mnemonic (const char *str); +void gtk_label_select_region (GtkLabel *label, + gint start_offset, + gint end_offset); +void gtk_label_set_mnemonic_widget (GtkLabel *label, + GtkWidget *widget); +void gtk_label_set_text_with_mnemonic +(GtkLabel *label, + const gchar *str); +PangoAttrList* gtk_label_get_attributes (GtkLabel *label); +GtkJustification gtk_label_get_justify (GtkLabel *label); +PangoLayout* gtk_label_get_layout (GtkLabel *label); + +GtkWidget* gtk_label_get_mnemonic_widget (GtkLabel *label); +gboolean gtk_label_get_selection_bounds (GtkLabel *label, + gint *start, + gint *end); + +*/ + + + } +} diff --git a/gtk/Object.cs b/gtk/Object.cs index 152f94fc0..21b8217cd 100755 --- a/gtk/Object.cs +++ b/gtk/Object.cs @@ -11,8 +11,30 @@ namespace GTK { using System.Runtime.InteropServices; public abstract class Object { + private EventHandlerList _events; + protected EventHandlerList Events + { + get + { + if (_events != null) return _events; + _events = new EventHandlerList (); + } + } - protected IntPtr obj; + private IntPtr _obj; + + IntPtr Object + { + get + { + return _obj; + } + set + { + _events = null; + _obj = value; + } + } protected delegate void SimpleCallback (IntPtr obj); diff --git a/gtk/Widget.cs b/gtk/Widget.cs index d3280dfaa..bcfd8a501 100755 --- a/gtk/Widget.cs +++ b/gtk/Widget.cs @@ -11,32 +11,6 @@ namespace GTK { public abstract class Widget : Object { - /// - /// ConnectEvents method - /// - /// - /// - /// Connects event handlers to the wrapped GTK widget. - /// It is not possible to perform this connection in a - /// constructor, since the leaf class constructor in which - /// the wrapped object is created is not executed until - /// after the base class' constructor. - /// - - protected void PrepareEvents () - { - ConnectSignal ("delete-event", - new SimpleCallback (EmitDeleteEvent)); - } - - private void EmitDeleteEvent (IntPtr obj) - { - if (Delete != null) { - EventArgs args = new EventArgs (); - Delete (this, args); - } - } - /// /// Delete Event /// @@ -46,7 +20,33 @@ namespace GTK { /// manager. /// - public event EventHandler Delete; + private static readonly object DeleteEvent = new object (); + + public event EventHandler Delete + { + add + { + if (Events[DeleteEvent] == null) + { + ConnectSignal ("delete-event", new SimpleCallback (EmitDeleteEvent)); + } + Events.AddHandler (DeleteEvent, value); + } + remove + { + Events.RemoveHandler (DeleteEvent, value); + } + } + + private void EmitDeleteEvent (IntPtr obj) + { + EventHandler eh = (EventHandler)(_events[DeleteEvent]); + if (eh != null) + { + EventArgs args = new EventArgs (); + eh(this, args); + } + } /// /// Show Method diff --git a/gtk/Window.cs b/gtk/Window.cs index 16ad39e05..5a0b70eae 100755 --- a/gtk/Window.cs +++ b/gtk/Window.cs @@ -17,6 +17,19 @@ namespace GTK { public class Window : Widget { + /// + /// Window Object Constructor + /// + /// + /// + /// Constructs a Window Wrapper. + /// + + public Window (IntPtr o) + { + Object = o; + } + /// /// Window Constructor /// @@ -30,8 +43,7 @@ namespace GTK { public Window () { - obj = gtk_window_new (WindowType.TopLevel); - base.PrepareEvents (); + Object = gtk_window_new (WindowType.TopLevel); } /// @@ -155,7 +167,7 @@ namespace GTK { public String Title { set { - gtk_window_set_title (obj, value); + gtk_window_set_title (Object, value); } } }