gnome-mud r799 - in trunk: . src src/handlers src/zmp ui



Author: lharris
Date: Wed Mar 18 05:57:45 2009
New Revision: 799
URL: http://svn.gnome.org/viewvc/gnome-mud?rev=799&view=rev

Log:
Subwindow support, Zmp subwindow package support

Added:
   trunk/src/mud-subwindow.c
   trunk/src/mud-subwindow.h
Modified:
   trunk/ChangeLog
   trunk/src/Makefile.am
   trunk/src/gnome-mud-marshallers.list
   trunk/src/handlers/mud-telnet-zmp.c
   trunk/src/mud-connection-view.c
   trunk/src/mud-connection-view.h
   trunk/src/zmp/zmp-core.c
   trunk/src/zmp/zmp-main.c
   trunk/src/zmp/zmp-main.h
   trunk/src/zmp/zmp-package-interface.c
   trunk/src/zmp/zmp-subwindow.c
   trunk/src/zmp/zmp-subwindow.h
   trunk/ui/main.glade

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Wed Mar 18 05:57:45 2009
@@ -56,6 +56,8 @@
 	mud-profile.h				\
 	mud-regex.c				\
 	mud-regex.h				\
+	mud-subwindow.c				\
+	mud-subwindow.h				\
 	mud-telnet.c				\
 	mud-telnet.h				\
 	mud-tray.c				\

Modified: trunk/src/gnome-mud-marshallers.list
==============================================================================
--- trunk/src/gnome-mud-marshallers.list	(original)
+++ trunk/src/gnome-mud-marshallers.list	Wed Mar 18 05:57:45 2009
@@ -1 +1,2 @@
 VOID:INT,INT
+VOID:UINT,UINT

Modified: trunk/src/handlers/mud-telnet-zmp.c
==============================================================================
--- trunk/src/handlers/mud-telnet-zmp.c	(original)
+++ trunk/src/handlers/mud-telnet-zmp.c	Wed Mar 18 05:57:45 2009
@@ -53,7 +53,8 @@
     PROP_MUD_TELNET_ZMP_0,
     PROP_ENABLED,
     PROP_HANDLES_OPTION,
-    PROP_TELNET
+    PROP_TELNET,
+    PROP_ZMPMAIN
 };
 
 /* Class Functions */
@@ -122,6 +123,14 @@
     g_object_class_override_property(object_class,
                                      PROP_TELNET,
                                      "telnet");
+
+    g_object_class_install_property(object_class,
+            PROP_ZMPMAIN,
+            g_param_spec_object("zmp-main",
+                                "ZMP Main",
+                                "The ZMP Dispatcher",
+                                ZMP_TYPE_MAIN,
+                                G_PARAM_READABLE));
 }
 
 static void
@@ -244,6 +253,10 @@
             g_value_take_object(value, self->priv->telnet);
             break;
 
+        case PROP_ZMPMAIN:
+            g_value_take_object(value, self->priv->main_zmp);
+            break;
+
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
             break;

Modified: trunk/src/mud-connection-view.c
==============================================================================
--- trunk/src/mud-connection-view.c	(original)
+++ trunk/src/mud-connection-view.c	Wed Mar 18 05:57:45 2009
@@ -38,6 +38,7 @@
 #include "mud-log.h"
 #include "mud-parse-base.h"
 #include "mud-telnet.h"
+#include "mud-subwindow.h"
 
 #include "handlers/mud-telnet-handlers.h"
 
@@ -57,6 +58,9 @@
     GQueue *history;
     gint current_history_index;
 
+    gchar *current_output;
+    GList *subwindows;
+
 #ifdef ENABLE_GST
     GQueue *download_queue;
     GConnHttp *dl_conn;
@@ -151,6 +155,13 @@
 static void mud_connection_view_reread_profile(MudConnectionView *view);
 static void mud_connection_view_feed_text(MudConnectionView *view,
                                           gchar *message);
+static void mud_connection_view_set_size_force_grid (MudConnectionView *window,
+                                                     VteTerminal *screen,
+                                                     gboolean        even_if_mapped,
+                                                     int             force_grid_width,
+                                                     int             force_grid_height);
+
+static void mud_connection_view_update_geometry (MudConnectionView *window);
 
 #ifdef ENABLE_GST
 static void mud_connection_view_http_cb(GConnHttp *conn,
@@ -380,6 +391,9 @@
 
     self->terminal = NULL;
     self->ui_vbox = NULL;
+
+    self->priv->subwindows = NULL;
+    self->priv->current_output = g_strdup("main");
 }
 
 static GObject *
@@ -400,10 +414,7 @@
     gchar *buf;
     gchar *proxy_host;
     gchar *version;
-    gint xpad, ypad;
-    gint char_width, char_height;
     gboolean use_proxy;
-    GdkGeometry hints;
     
     MudConnectionView *self;
     GObject *obj;
@@ -443,12 +454,12 @@
     self->ui_vbox = GTK_VBOX(box);
     self->terminal = VTE_TERMINAL(vte_terminal_new());
     self->priv->scrollbar = gtk_vscrollbar_new(NULL);
+    term_box = gtk_hbox_new(FALSE, 0);
 
 #ifdef ENABLE_GST
     /* Setup Download UI */
     dl_vbox = gtk_vbox_new(FALSE, 0);
     dl_hbox = gtk_hbox_new(FALSE, 0);
-    term_box = gtk_hbox_new(FALSE, 0);
 
     self->priv->dl_label = gtk_label_new("Downloading...");
     self->priv->progressbar = gtk_progress_bar_new();
@@ -513,31 +524,12 @@
     /* Setup VTE */
     vte_terminal_set_encoding(self->terminal, "ISO-8859-1");
     vte_terminal_set_emulation(self->terminal, "xterm");
-    vte_terminal_get_padding(self->terminal, &xpad, &ypad);
-
-    char_width = self->terminal->char_width;
-    char_height = self->terminal->char_height;
-
-    hints.base_width = xpad;
-    hints.base_height = ypad;
-    hints.width_inc = char_width;
-    hints.height_inc = char_height;
-
-    hints.min_width =  hints.base_width + hints.width_inc * 4;
-    hints.min_height = hints.base_height+ hints.height_inc * 2;
 
     g_object_get(self->window,
                  "window", &main_window,
                  "tray", &tray,
                  NULL);
 
-    gtk_window_set_geometry_hints(GTK_WINDOW(main_window),
-            GTK_WIDGET(self->terminal),
-            &hints,
-            GDK_HINT_RESIZE_INC |
-            GDK_HINT_MIN_SIZE |
-            GDK_HINT_BASE_SIZE);
-
     self->connection = gnet_conn_new(self->hostname, self->port,
             mud_connection_view_network_event_cb, self);
     gnet_conn_ref(self->connection);
@@ -603,6 +595,8 @@
     /* Show everything */
     gtk_widget_show_all(box);
 
+    mud_connection_view_update_geometry (self);
+
 #ifdef ENABLE_GST
     /* Hide UI until download starts */
     gtk_widget_hide(self->priv->progressbar);
@@ -621,6 +615,7 @@
     MudConnectionView *connection_view;
     GObjectClass *parent_class;
     gchar *history_item;
+    GList *entry;
 
 #ifdef ENABLE_GST                               
     MudMSPDownloadItem *item;
@@ -672,6 +667,19 @@
     g_object_unref(connection_view->parse);
     g_object_unref(connection_view->profile);
 
+    entry = g_list_first(connection_view->priv->subwindows);
+
+    while(entry)
+    {
+        MudSubwindow *sub = MUD_SUBWINDOW(entry->data);
+
+        g_object_unref(sub);
+
+        entry = g_list_next(entry);
+    }
+
+    g_list_free(connection_view->priv->subwindows);
+
     parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
     parent_class->finalize(object);
 }
@@ -939,6 +947,8 @@
 static void
 mud_connection_view_profile_changed_cb(MudProfile *profile, MudProfileMask *mask, MudConnectionView *view)
 {
+    GList *entry;
+
     if (mask->ScrollOnOutput)
         mud_connection_view_set_terminal_scrolloutput(view);
     if (mask->Scrollback)
@@ -947,6 +957,17 @@
         mud_connection_view_set_terminal_font(view);
     if (mask->Foreground || mask->Background || mask->Colors)
         mud_connection_view_set_terminal_colors(view);
+
+    entry = g_list_first(view->priv->subwindows);
+
+    while(entry)
+    {
+        MudSubwindow *sub = MUD_SUBWINDOW(entry->data);
+
+        mud_subwindow_reread_profile(sub);
+
+        entry = g_list_next(entry);
+    }
 }
 
 static gboolean
@@ -1164,8 +1185,24 @@
 
                     if(!gag)
                     {
-                        vte_terminal_feed(view->terminal,
-                                buf, length);
+                        if(g_str_equal(view->priv->current_output, "main"))
+                            vte_terminal_feed(view->terminal,
+                                              buf,
+                                              length);
+                        else
+                        {
+                            MudSubwindow *sub =
+                                mud_connection_view_get_subwindow(view,
+                                        view->priv->current_output);
+
+                            if(!sub)
+                                vte_terminal_feed(view->terminal,
+                                        buf,
+                                        length);
+                            else
+                                mud_subwindow_feed(sub, buf, length);
+                        }
+
                         mud_log_write_hook(view->log, buf, length);
                     }
 
@@ -1209,6 +1246,101 @@
 }
 
 /* Private Methods */
+static void
+mud_connection_view_set_size_force_grid (MudConnectionView *window,
+                                         VteTerminal *screen,
+                                         gboolean        even_if_mapped,
+                                         int             force_grid_width,
+                                         int             force_grid_height)
+{
+    /* Owen's hack from gnome-terminal */
+    GtkWidget *widget;
+    GtkWidget *app;
+    GtkWidget *mainwindow;
+    GtkRequisition toplevel_request;
+    GtkRequisition widget_request;
+    int w, h;
+    int char_width;
+    int char_height;
+    int grid_width;
+    int grid_height;
+    int xpad;
+    int ypad;
+
+    g_return_if_fail(IS_MUD_CONNECTION_VIEW(window));
+
+    /* be sure our geometry is up-to-date */
+    mud_connection_view_update_geometry (window);
+    widget = GTK_WIDGET (screen);
+
+    g_object_get(window->window, "window", &app, NULL);
+
+    gtk_widget_size_request (app, &toplevel_request);
+    gtk_widget_size_request (widget, &widget_request);
+
+    w = toplevel_request.width - widget_request.width;
+    h = toplevel_request.height - widget_request.height;
+
+    char_width = VTE_TERMINAL(screen)->char_width;
+    char_height = VTE_TERMINAL(screen)->char_height;
+
+    grid_width = VTE_TERMINAL(screen)->column_count;
+    grid_height = VTE_TERMINAL(screen)->row_count;
+
+    if (force_grid_width >= 0)
+        grid_width = force_grid_width;
+    if (force_grid_height >= 0)
+        grid_height = force_grid_height;
+
+    vte_terminal_get_padding (VTE_TERMINAL (screen), &xpad, &ypad);
+
+    w += xpad * 2 + char_width * grid_width;
+    h += ypad * 2 + char_height * grid_height;
+
+    if (even_if_mapped && GTK_WIDGET_MAPPED (app)) {
+        gtk_window_resize (GTK_WINDOW (app), w, h);
+    }
+    else {
+        gtk_window_set_default_size (GTK_WINDOW (app), w, h);
+    }
+}
+
+static void
+mud_connection_view_update_geometry (MudConnectionView *window)
+{
+    GtkWidget *widget = GTK_WIDGET(window->terminal);
+    GtkWidget *mainwindow;
+    GdkGeometry hints;
+    gint char_width;
+    gint char_height;
+    gint xpad, ypad;
+
+    char_width = VTE_TERMINAL(widget)->char_width;
+    char_height = VTE_TERMINAL(widget)->char_height;
+
+    vte_terminal_get_padding (VTE_TERMINAL (window->terminal), &xpad, &ypad);
+
+    hints.base_width = xpad;
+    hints.base_height = ypad;
+
+#define MIN_WIDTH_CHARS 4
+#define MIN_HEIGHT_CHARS 2
+
+    hints.width_inc = char_width;
+    hints.height_inc = char_height;
+
+    /* min size is min size of just the geometry widget, remember. */
+    hints.min_width = hints.base_width + hints.width_inc * MIN_WIDTH_CHARS;
+    hints.min_height = hints.base_height + hints.height_inc * MIN_HEIGHT_CHARS;
+
+    g_object_get(window->window, "window", &mainwindow, NULL);
+    gtk_window_set_geometry_hints (GTK_WINDOW (mainwindow),
+            widget,
+            &hints,
+            GDK_HINT_RESIZE_INC |
+            GDK_HINT_MIN_SIZE |
+            GDK_HINT_BASE_SIZE);
+}
 
 static GtkWidget*
 append_stock_menuitem(GtkWidget *menu, const gchar *text, GCallback callback, gpointer data)
@@ -1345,6 +1477,159 @@
 }
 
 /* Public Methods */
+MudSubwindow *
+mud_connection_view_create_subwindow(MudConnectionView *view,
+                                     const gchar *title,
+                                     const gchar *identifier,
+                                     guint width,
+                                     guint height)
+{
+    MudSubwindow *sub;
+
+    if(!IS_MUD_CONNECTION_VIEW(view))
+        return NULL;
+
+    if(mud_connection_view_has_subwindow(view, identifier))
+        return mud_connection_view_get_subwindow(view, identifier);
+
+    sub = g_object_new(MUD_TYPE_SUBWINDOW,
+                       "title", title,
+                       "identifier", identifier,
+                       "width", width,
+                       "height", height,
+                       "parent-view", view,
+                       NULL);
+
+
+    view->priv->subwindows = g_list_append(view->priv->subwindows, sub);
+
+    return sub;
+}
+
+gboolean
+mud_connection_view_has_subwindow(MudConnectionView *view,
+                                  const gchar *identifier)
+{
+    GList *entry;
+    gchar *ident;
+
+    if(!IS_MUD_CONNECTION_VIEW(view))
+        return FALSE;
+
+    entry = g_list_first(view->priv->subwindows);
+
+    while(entry)
+    {
+        MudSubwindow *sub = MUD_SUBWINDOW(entry->data);
+
+        g_object_get(sub, "identifier", &ident, NULL);
+
+        if(g_str_equal(identifier, ident))
+        {
+            g_free(ident);
+
+            return TRUE;
+        }
+
+        g_free(ident);
+
+        entry = g_list_next(entry);
+    }
+
+    return FALSE;
+}
+
+void
+mud_connection_view_set_output(MudConnectionView *view,
+                               const gchar *identifier)
+{
+    g_return_if_fail(IS_MUD_CONNECTION_VIEW(view));
+
+    if(mud_connection_view_has_subwindow(view, identifier) ||
+       g_str_equal(identifier, "main"))
+    {
+        g_free(view->priv->current_output);
+        view->priv->current_output = g_strdup(identifier);
+    }
+}
+
+
+void
+mud_connection_view_show_subwindow(MudConnectionView *view,
+                                   const gchar *identifier)
+{
+    g_return_if_fail(IS_MUD_CONNECTION_VIEW(view));
+
+    if(mud_connection_view_has_subwindow(view, identifier))
+    {
+        MudSubwindow *sub =
+            mud_connection_view_get_subwindow(view, identifier);
+
+        mud_subwindow_show(sub);
+    }
+}
+
+MudSubwindow *
+mud_connection_view_get_subwindow(MudConnectionView *view,
+                                  const gchar *identifier)
+{
+    GList *entry;
+    gchar *ident;
+
+    if(!IS_MUD_CONNECTION_VIEW(view))
+        return NULL;
+
+    if(!mud_connection_view_has_subwindow(view, identifier))
+        return NULL;
+
+    entry = view->priv->subwindows;
+
+    while(entry)
+    {
+        MudSubwindow *sub = MUD_SUBWINDOW(entry->data);
+
+        g_object_get(sub, "identifier", &ident, NULL);
+
+        if(g_str_equal(ident, identifier))
+        {
+            g_free(ident);
+
+            return sub;
+        }
+
+        g_free(ident);
+
+        entry = g_list_next(entry);
+    }
+
+    return NULL;
+}
+
+void
+mud_connection_view_remove_subwindow(MudConnectionView *view,
+                                     const gchar *identifier)
+{
+    MudSubwindow *sub;
+
+    g_return_if_fail(IS_MUD_CONNECTION_VIEW(view));
+
+    if(!mud_connection_view_has_subwindow(view, identifier))
+        return;
+
+    sub = mud_connection_view_get_subwindow(view, identifier);
+
+    if(g_str_equal(view->priv->current_output, identifier))
+    {
+        g_free(view->priv->current_output);
+        view->priv->current_output = g_strdup("main");
+    }
+
+    view->priv->subwindows = g_list_remove(view->priv->subwindows, sub);
+
+    g_object_unref(sub);
+
+}
+
 void
 mud_connection_view_add_text(MudConnectionView *view, gchar *message, enum MudConnectionColorType type)
 {

Modified: trunk/src/mud-connection-view.h
==============================================================================
--- trunk/src/mud-connection-view.h	(original)
+++ trunk/src/mud-connection-view.h	Wed Mar 18 05:57:45 2009
@@ -29,6 +29,7 @@
 #include "mud-window.h"
 #include "mud-log.h"
 #include "mud-tray.h"
+#include "mud-subwindow.h"
 
 struct _MudConnectionViewClass
 {
@@ -105,6 +106,27 @@
 void mud_connection_view_start_logging(MudConnectionView *view);
 void mud_connection_view_stop_logging(MudConnectionView *view);
 
+MudSubwindow *mud_connection_view_create_subwindow(MudConnectionView *view,
+                                                   const gchar *title,
+                                                   const gchar *identifier,
+                                                   guint width,
+                                                   guint height);
+
+gboolean mud_connection_view_has_subwindow(MudConnectionView *view,
+                                           const gchar *identifier);
+
+void mud_connection_view_set_output(MudConnectionView *view,
+                                    const gchar *identifier);
+
+void mud_connection_view_show_subwindow(MudConnectionView *view,
+                                        const gchar *identifier);
+
+void mud_connection_view_remove_subwindow(MudConnectionView *view,
+                                          const gchar *identifier);
+
+MudSubwindow *mud_connection_view_get_subwindow(MudConnectionView *view,
+                                                const gchar *identifier);
+
 G_END_DECLS
 
 #endif /* MUD_CONNECTION_VIEW_H */

Added: trunk/src/mud-subwindow.c
==============================================================================
--- (empty file)
+++ trunk/src/mud-subwindow.c	Wed Mar 18 05:57:45 2009
@@ -0,0 +1,901 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-subwindow.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <vte/vte.h>
+#include <glade/glade-xml.h>
+#include <gconf/gconf-client.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gnome-mud.h"
+#include "gnome-mud-marshallers.h"
+#include "mud-connection-view.h"
+#include "mud-subwindow.h"
+
+struct _MudSubwindowPrivate
+{
+    gchar *title;
+    gchar *identifier;
+
+    guint width;
+    guint height;
+
+    gboolean visible;
+    gboolean input_enabled;
+
+    GQueue *history;
+    gint current_history_index;
+
+    gint pixel_width;
+    gint pixel_height;
+
+    GtkWidget *window;
+    GtkWidget *entry;
+    GtkWidget *terminal;
+    GtkWidget *scroll;
+    GtkWidget *vbox;
+
+    MudConnectionView *parent_view;
+};
+
+enum MudSubwindowHistoryDirection
+{
+    SUBWINDOW_HISTORY_UP,
+    SUBWINDOW_HISTORY_DOWN
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_SUBWINDOW_0,
+    PROP_PARENT,
+    PROP_TITLE,
+    PROP_IDENT,
+    PROP_WIDTH,
+    PROP_HEIGHT,
+    PROP_VISIBLE,
+    PROP_INPUT
+};
+
+/* Signal Indices */
+enum
+{
+    RESIZED,
+    INPUT,
+    LAST_SIGNAL
+};
+
+/* Signal Identifier Map */
+static guint mud_subwindow_signal[LAST_SIGNAL] = { 0, 0 };
+
+/* Create the Type */
+G_DEFINE_TYPE(MudSubwindow, mud_subwindow, G_TYPE_OBJECT);
+
+/* Class Functions */
+static void mud_subwindow_init (MudSubwindow *self);
+static void mud_subwindow_class_init (MudSubwindowClass *klass);
+static void mud_subwindow_finalize (GObject *object);
+static GObject *mud_subwindow_constructor (GType gtype,
+                                           guint n_properties,
+                                           GObjectConstructParam *properties);
+static void mud_subwindow_set_property(GObject *object,
+                                       guint prop_id,
+                                       const GValue *value,
+                                       GParamSpec *pspec);
+static void mud_subwindow_get_property(GObject *object,
+                                       guint prop_id,
+                                       GValue *value,
+                                       GParamSpec *pspec);
+
+/* Callback Functions */
+static gboolean mud_subwindow_delete_event_cb(GtkWidget *widget,
+		                   	      GdkEvent *event,
+			                      MudSubwindow *self);
+
+static gboolean mud_subwindow_entry_keypress_cb(GtkWidget *widget,
+                                                GdkEventKey *event,
+                                                MudSubwindow *self);
+
+static gboolean mud_subwindow_configure_event_cb(GtkWidget *widget,
+                                                 GdkEventConfigure *event,
+                                                 gpointer user_data);
+
+/* Private Methods */
+static void mud_subwindow_set_size_force_grid (MudSubwindow *window,
+                                               VteTerminal *screen,
+                                               gboolean        even_if_mapped,
+                                               int             force_grid_width,
+                                               int             force_grid_height);
+
+const gchar *mud_subwindow_get_history_item(MudSubwindow *self,
+                                            enum MudSubwindowHistoryDirection direction);
+
+static void mud_subwindow_update_geometry (MudSubwindow *window);
+static void mud_subwindow_set_terminal_colors(MudSubwindow *self);
+static void mud_subwindow_set_terminal_scrollback(MudSubwindow *self);
+static void mud_subwindow_set_terminal_scrolloutput(MudSubwindow *self);
+static void mud_subwindow_set_terminal_font(MudSubwindow *self);
+
+/* MudSubwindow class functions */
+static void
+mud_subwindow_class_init (MudSubwindowClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_subwindow_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_subwindow_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_subwindow_set_property;
+    object_class->get_property = mud_subwindow_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudSubwindowPrivate));
+
+    /* Install Properties */
+    g_object_class_install_property(object_class,
+            PROP_PARENT,
+            g_param_spec_object("parent-view",
+                "Parent View",
+                "The parent MudSubwindow",
+                MUD_TYPE_CONNECTION_VIEW,
+                G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property(object_class,
+            PROP_TITLE,
+            g_param_spec_string("title",
+                "Title",
+                "The visible Title of the subwindow.",
+                NULL,
+                G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property(object_class,
+            PROP_IDENT,
+            g_param_spec_string("identifier",
+                "Ident",
+                "The identifier of the subwindow.",
+                NULL,
+                G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property(object_class,
+            PROP_WIDTH,
+            g_param_spec_uint("width",
+                "Width",
+                "The width of the terminal in columns.",
+                1,
+                1024,
+                40,
+                G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property(object_class,
+            PROP_HEIGHT,
+            g_param_spec_uint("height",
+                "Height",
+                "The height of the terminal in rows.",
+                1,
+                1024,
+                40,
+                G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property(object_class,
+            PROP_VISIBLE,
+            g_param_spec_boolean("visible",
+                "Visible",
+                "True if subwindow is visible.",
+                TRUE,
+                G_PARAM_READWRITE));
+
+    g_object_class_install_property(object_class,
+            PROP_INPUT,
+            g_param_spec_boolean("input-enabled",
+                "Input Enabled",
+                "True if subwindow accepts input.",
+                TRUE,
+                G_PARAM_READWRITE));
+
+    /* Register Signals */
+    mud_subwindow_signal[RESIZED] =
+        g_signal_new("resized",
+                     G_TYPE_FROM_CLASS(object_class),
+                     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                     0,
+                     NULL,
+                     NULL,
+                     gnome_mud_cclosure_VOID__UINT_UINT,
+                     G_TYPE_NONE,
+                     2,
+                     G_TYPE_UINT,
+                     G_TYPE_UINT);
+
+    mud_subwindow_signal[INPUT] =
+        g_signal_new("input-received",
+                     G_TYPE_FROM_CLASS(object_class),
+                     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                     0,
+                     NULL,
+                     NULL,
+                     g_cclosure_marshal_VOID__STRING,
+                     G_TYPE_NONE,
+                     1,
+                     G_TYPE_STRING); 
+
+}
+
+static void
+mud_subwindow_init (MudSubwindow *self)
+{
+    /* Get our private data */
+    self->priv = MUD_SUBWINDOW_GET_PRIVATE(self);
+
+    /* Set Defaults */
+    self->priv->parent_view = NULL;
+    self->priv->title = NULL;
+    self->priv->identifier = NULL;
+    self->priv->visible = TRUE;
+    self->priv->input_enabled = TRUE;
+    self->priv->history = g_queue_new();
+    self->priv->current_history_index = 0;
+    self->priv->width = 0;
+    self->priv->height = 0;
+
+    self->priv->window = NULL;
+    self->priv->entry = NULL;
+    self->priv->scroll = NULL;
+    self->priv->terminal = NULL;
+    self->priv->vbox = NULL;
+}
+
+static GObject *
+mud_subwindow_constructor (GType gtype,
+                           guint n_properties,
+                           GObjectConstructParam *properties)
+{
+    GtkWidget *term_box;
+
+    MudSubwindow *self;
+    GObject *obj;
+    MudSubwindowClass *klass;
+    GObjectClass *parent_class;
+
+    GladeXML *glade;
+
+    /* Chain up to parent constructor */
+    klass = MUD_SUBWINDOW_CLASS( g_type_class_peek(MUD_TYPE_SUBWINDOW) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_SUBWINDOW(obj);
+
+    if(!self->priv->parent_view)
+    {
+        g_printf("ERROR: Tried to instantiate MudSubwindow without passing parent view\n");
+        g_error("Tried to instantiate MudSubwindow without passing parent view");
+    }
+
+    if(!self->priv->title)
+    {
+        g_printf("ERROR: Tried to instantiate MudSubwindow without passing title\n");
+        g_error("Tried to instantiate MudSubwindow without passing title.");
+    }
+
+    if(!self->priv->identifier)
+    {
+        g_printf("ERROR: Tried to instantiate MudSubwindow without passing identifier\n");
+        g_error("Tried to instantiate MudSubwindow without passing identifier.");
+    }
+
+    if(self->priv->width == 0 || self->priv->height == 0)
+    {
+        g_printf("ERROR: Tried to instantiate MudSubwindow without passing valid width/height\n");
+        g_error("Tried to instantiate MudSubwindow without passing valid width/height.");
+    }
+
+    /* start glading */
+    glade = glade_xml_new(GLADEDIR "/main.glade", "subwindow", NULL);
+
+    self->priv->window = glade_xml_get_widget(glade, "subwindow");
+
+    g_object_unref(glade);
+
+    self->priv->vbox = gtk_vbox_new(FALSE, 0);
+    self->priv->entry = gtk_entry_new();
+
+    self->priv->terminal = vte_terminal_new();
+    self->priv->scroll = gtk_vscrollbar_new(NULL);
+    term_box = gtk_hbox_new(FALSE, 0);
+
+    vte_terminal_set_encoding(VTE_TERMINAL(self->priv->terminal),
+                              "ISO-8859-1");
+
+    vte_terminal_set_emulation(VTE_TERMINAL(self->priv->terminal),
+                               "xterm");
+
+    gtk_box_pack_start(GTK_BOX(term_box),
+                       self->priv->terminal,
+                       TRUE,
+                       TRUE,
+                       0);
+
+    gtk_box_pack_end(GTK_BOX(term_box),
+                     self->priv->scroll, 
+                     FALSE,
+                     FALSE,
+                     0);
+
+    gtk_box_pack_start(GTK_BOX(self->priv->vbox), term_box, TRUE, TRUE, 0);
+    gtk_box_pack_end(GTK_BOX(self->priv->vbox), self->priv->entry, FALSE, FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(self->priv->window), self->priv->vbox);
+
+    gtk_range_set_adjustment(
+            GTK_RANGE(self->priv->scroll),
+            VTE_TERMINAL(self->priv->terminal)->adjustment);
+
+    gtk_widget_show_all(self->priv->window);
+
+    mud_subwindow_update_geometry (self);
+
+    vte_terminal_set_size(VTE_TERMINAL(self->priv->terminal),
+                          self->priv->width,
+                          self->priv->height);
+
+    mud_subwindow_set_size_force_grid(self,
+                                      VTE_TERMINAL(self->priv->terminal),
+                                      TRUE,
+                                      -1,
+                                      -1);
+
+    if(self->priv->input_enabled)
+        gtk_widget_show(self->priv->entry);
+    else
+        gtk_widget_hide(self->priv->entry);
+
+    gtk_window_set_title(GTK_WINDOW(self->priv->window), self->priv->title);
+
+    gtk_window_get_size(GTK_WINDOW(self->priv->window),
+                        &self->priv->pixel_width,
+                        &self->priv->pixel_height);
+
+    g_signal_connect(self->priv->window,
+                     "delete-event",
+                     G_CALLBACK(mud_subwindow_delete_event_cb),
+                     self);
+
+    g_signal_connect(self->priv->window,
+                     "configure-event",
+                     G_CALLBACK(mud_subwindow_configure_event_cb),
+                     self);
+
+    g_signal_connect(self->priv->entry,
+                     "key_press_event",
+                     G_CALLBACK(mud_subwindow_entry_keypress_cb),
+                     self);
+
+    mud_subwindow_reread_profile(self);
+
+    return obj;
+}
+
+static void
+mud_subwindow_finalize (GObject *object)
+{
+    MudSubwindow *self;
+    GObjectClass *parent_class;
+    gchar *history_item;
+
+    self = MUD_SUBWINDOW(object);
+
+    if(self->priv->history && !g_queue_is_empty(self->priv->history))
+        while((history_item = (gchar *)g_queue_pop_head(self->priv->history)) != NULL)
+            g_free(history_item);
+
+    if(self->priv->history)
+        g_queue_free(self->priv->history);
+
+    gtk_widget_destroy(self->priv->window);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_subwindow_set_property(GObject *object,
+                      guint prop_id,
+                      const GValue *value,
+                      GParamSpec *pspec)
+{
+    MudSubwindow *self;
+    gchar *new_string;
+    gboolean new_boolean;
+    guint new_uint;
+
+    self = MUD_SUBWINDOW(object);
+
+    switch(prop_id)
+    {
+        case PROP_INPUT:
+            new_boolean = g_value_get_boolean(value);
+
+            if(new_boolean != self->priv->input_enabled)
+                self->priv->input_enabled = new_boolean;
+
+            if(self->priv->entry)
+                if(self->priv->input_enabled)
+                    gtk_widget_show(self->priv->entry);
+                else
+                    gtk_widget_hide(self->priv->entry);
+            break;
+
+        case PROP_VISIBLE:
+            new_boolean = g_value_get_boolean(value);
+
+            if(new_boolean != self->priv->visible)
+                self->priv->visible = new_boolean;
+            break;
+
+        case PROP_HEIGHT:
+            new_uint = g_value_get_uint(value);
+
+            if(new_uint != self->priv->height)
+                self->priv->height = new_uint;
+            break;
+
+        case PROP_WIDTH:
+            new_uint = g_value_get_uint(value);
+
+            if(new_uint != self->priv->width)
+                self->priv->width = new_uint;
+            break;
+
+        case PROP_IDENT:
+            new_string = g_value_dup_string(value);
+
+            if(!self->priv->identifier)
+                self->priv->identifier = g_strdup(new_string);
+            else if(!g_str_equal(self->priv->identifier, new_string))
+            {
+                g_free(self->priv->identifier);
+                self->priv->identifier = g_strdup(new_string);
+            }
+
+            g_free(new_string);
+
+            break;
+
+        case PROP_TITLE:
+            new_string = g_value_dup_string(value);
+
+            if(!self->priv->title)
+                self->priv->title = g_strdup(new_string);
+            else if(!g_str_equal(self->priv->title, new_string))
+            {
+                g_free(self->priv->title);
+                self->priv->title = g_strdup(new_string);
+            }
+
+            if(GTK_IS_WINDOW(self->priv->window))
+            {
+                g_printf("window\n");
+            }
+
+            g_free(new_string);
+
+            break;
+
+        case PROP_PARENT:
+            self->priv->parent_view = MUD_CONNECTION_VIEW(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_subwindow_get_property(GObject *object,
+                      guint prop_id,
+                      GValue *value,
+                      GParamSpec *pspec)
+{
+    MudSubwindow *self;
+
+    self = MUD_SUBWINDOW(object);
+
+    switch(prop_id)
+    {
+        case PROP_TITLE:
+            g_value_set_string(value, self->priv->title);
+            break;
+
+        case PROP_IDENT:
+            g_value_set_string(value, self->priv->identifier);
+            break;
+
+        case PROP_WIDTH:
+            g_value_set_uint(value, self->priv->width);
+            break;
+
+        case PROP_HEIGHT:
+            g_value_set_uint(value, self->priv->height);
+            break;
+
+        case PROP_VISIBLE:
+            g_value_set_boolean(value, self->priv->visible);
+            break;
+
+        case PROP_INPUT:
+            g_value_set_boolean(value, self->priv->input_enabled);
+            break;
+
+        case PROP_PARENT:
+            g_value_take_object(value, self->priv->parent_view);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Private Methods */
+const gchar *
+mud_subwindow_get_history_item(MudSubwindow *self,
+                               enum MudSubwindowHistoryDirection direction)
+{
+    gchar *history_item;
+
+    if(direction == SUBWINDOW_HISTORY_DOWN)
+        if( !(self->priv->current_history_index <= 0) )
+            self->priv->current_history_index--;
+
+    if(direction == SUBWINDOW_HISTORY_UP)
+        if(self->priv->current_history_index < 
+                (gint)g_queue_get_length(self->priv->history) - 1)
+            self->priv->current_history_index++;
+
+    history_item = (gchar *)g_queue_peek_nth(self->priv->history,
+            self->priv->current_history_index);
+
+    return history_item;
+}
+
+static void
+mud_subwindow_set_terminal_colors(MudSubwindow *self)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    vte_terminal_set_colors(VTE_TERMINAL(self->priv->terminal),
+            &self->priv->parent_view->profile->preferences->Foreground,
+            &self->priv->parent_view->profile->preferences->Background,
+            self->priv->parent_view->profile->preferences->Colors, C_MAX);
+}
+
+static void
+mud_subwindow_set_terminal_scrollback(MudSubwindow *self)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    vte_terminal_set_scrollback_lines(VTE_TERMINAL(self->priv->terminal),
+            self->priv->parent_view->profile->preferences->Scrollback);
+}
+
+static void
+mud_subwindow_set_terminal_scrolloutput(MudSubwindow *self)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    if(self->priv->terminal)
+        vte_terminal_set_scroll_on_output(VTE_TERMINAL(self->priv->terminal),
+                self->priv->parent_view->profile->preferences->ScrollOnOutput);
+}
+
+static void
+mud_subwindow_set_terminal_font(MudSubwindow *self)
+{
+    PangoFontDescription *desc = NULL;
+    char *name;
+
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    name = self->priv->parent_view->profile->preferences->FontName;
+
+    if(name)
+        desc = pango_font_description_from_string(name);
+
+    if(!desc)
+        desc = pango_font_description_from_string("Monospace 10");
+
+    vte_terminal_set_font(VTE_TERMINAL(self->priv->terminal), desc);
+}
+
+static void
+mud_subwindow_set_size_force_grid (MudSubwindow *window,
+                                   VteTerminal *screen,
+                                   gboolean        even_if_mapped,
+                                   int             force_grid_width,
+                                   int             force_grid_height)
+{
+    /* Owen's hack from gnome-terminal */
+    GtkWidget *widget;
+    GtkWidget *app;
+    GtkRequisition toplevel_request;
+    GtkRequisition widget_request;
+    int w, h;
+    int char_width;
+    int char_height;
+    int grid_width;
+    int grid_height;
+    int xpad;
+    int ypad;
+
+    g_return_if_fail(MUD_IS_SUBWINDOW(window));
+
+    /* be sure our geometry is up-to-date */
+    mud_subwindow_update_geometry (window);
+    widget = GTK_WIDGET (screen);
+
+    app = window->priv->window;
+
+    gtk_widget_size_request (app, &toplevel_request);
+    gtk_widget_size_request (widget, &widget_request);
+
+    w = toplevel_request.width - widget_request.width;
+    h = toplevel_request.height - widget_request.height;
+
+    char_width = VTE_TERMINAL(screen)->char_width;
+    char_height = VTE_TERMINAL(screen)->char_height;
+
+    grid_width = VTE_TERMINAL(screen)->column_count;
+    grid_height = VTE_TERMINAL(screen)->row_count;
+
+    if (force_grid_width >= 0)
+        grid_width = force_grid_width;
+    if (force_grid_height >= 0)
+        grid_height = force_grid_height;
+
+    vte_terminal_get_padding (VTE_TERMINAL (screen), &xpad, &ypad);
+
+    w += xpad * 2 + char_width * grid_width;
+    h += ypad * 2 + char_height * grid_height;
+
+    if (even_if_mapped && GTK_WIDGET_MAPPED (app)) {
+        gtk_window_resize (GTK_WINDOW (app), w, h);
+    }
+    else {
+        gtk_window_set_default_size (GTK_WINDOW (app), w, h);
+    }
+}
+
+static void
+mud_subwindow_update_geometry (MudSubwindow *window)
+{
+    GtkWidget *widget = window->priv->terminal;
+    GdkGeometry hints;
+    gint char_width;
+    gint char_height;
+    gint xpad, ypad;
+
+    char_width = VTE_TERMINAL(widget)->char_width;
+    char_height = VTE_TERMINAL(widget)->char_height;
+
+    vte_terminal_get_padding (VTE_TERMINAL (window->priv->terminal), &xpad, &ypad);
+
+    hints.base_width = xpad;
+    hints.base_height = ypad;
+
+#define MIN_WIDTH_CHARS 4
+#define MIN_HEIGHT_CHARS 2
+
+    hints.width_inc = char_width;
+    hints.height_inc = char_height;
+
+    /* min size is min size of just the geometry widget, remember. */
+    hints.min_width = hints.base_width + hints.width_inc * MIN_WIDTH_CHARS;
+    hints.min_height = hints.base_height + hints.height_inc * MIN_HEIGHT_CHARS;
+
+    gtk_window_set_geometry_hints (GTK_WINDOW (window->priv->window),
+            widget,
+            &hints,
+            GDK_HINT_RESIZE_INC |
+            GDK_HINT_MIN_SIZE |
+            GDK_HINT_BASE_SIZE);
+}
+
+/* MudSubwindow Callbacks */
+static gboolean
+mud_subwindow_delete_event_cb(GtkWidget *widget,
+			      GdkEvent *event,
+			      MudSubwindow *self)
+{
+    gtk_widget_hide(self->priv->window);
+    self->priv->visible = FALSE;
+
+    return TRUE;
+}
+
+static gboolean
+mud_subwindow_configure_event_cb(GtkWidget *widget,
+                                 GdkEventConfigure *event,
+                                 gpointer user_data)
+{
+    MudSubwindow *self = MUD_SUBWINDOW(user_data);
+
+    if(event->width != self->priv->pixel_width ||
+       event->height != self->priv->pixel_height)
+    {
+        self->priv->pixel_width = event->width;
+        self->priv->pixel_height = event->height;
+
+        self->priv->width = VTE_TERMINAL(self->priv->terminal)->column_count;
+        self->priv->height = VTE_TERMINAL(self->priv->terminal)->row_count;
+
+        g_signal_emit(self,
+                      mud_subwindow_signal[RESIZED],
+                      0,
+                      self->priv->width,
+                      self->priv->height);
+    }
+
+    gtk_widget_grab_focus(self->priv->entry);
+
+    return FALSE;
+}
+
+static gboolean
+mud_subwindow_entry_keypress_cb(GtkWidget *widget,
+                                GdkEventKey *event,
+                                MudSubwindow *self)
+{
+    const gchar *history;
+    GConfClient *client = gconf_client_get_default();
+
+    if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) &&
+            (event->state & gtk_accelerator_get_default_mod_mask()) == 0)
+    {
+        gchar *head = g_queue_peek_head(self->priv->history);
+        const gchar *text = gtk_entry_get_text(GTK_ENTRY(self->priv->entry));
+
+        if( (head && !g_str_equal(head, text) && head[0] != '\n') 
+                || g_queue_is_empty(self->priv->history))
+            g_queue_push_head(self->priv->history,
+                    (gpointer)g_strdup(text));
+
+        self->priv->current_history_index = -1;
+
+        g_signal_emit(self,
+                      mud_subwindow_signal[INPUT],
+                      0,
+                      text);
+
+        if (gconf_client_get_bool(client,
+                    "/apps/gnome-mud/functionality/keeptext", NULL) == FALSE)
+            gtk_entry_set_text(GTK_ENTRY(self->priv->entry), "");
+        else
+            gtk_editable_select_region(GTK_EDITABLE(self->priv->entry), 0, -1);
+
+        g_object_unref(client);
+
+        return TRUE;
+    }
+
+    g_object_unref(client);
+
+    if(event->keyval == GDK_Up)
+    {
+        history = 
+            mud_subwindow_get_history_item(self, 
+                                           SUBWINDOW_HISTORY_UP);
+
+        if(history)
+        {
+            gtk_entry_set_text(GTK_ENTRY(self->priv->entry), history);
+            gtk_editable_select_region(GTK_EDITABLE(self->priv->entry), 0, -1);
+        }
+
+        return TRUE;
+    }
+
+    if(event->keyval == GDK_Down)
+    {
+        history = 
+            mud_subwindow_get_history_item(self, 
+                                           SUBWINDOW_HISTORY_DOWN);
+
+        if(history)
+        {
+            gtk_entry_set_text(GTK_ENTRY(self->priv->entry), history);
+            gtk_editable_select_region(GTK_EDITABLE(self->priv->entry), 0, -1);
+        }
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Public Methods */
+void
+mud_subwindow_set_size(MudSubwindow *self,
+                       guint width,
+                       guint height)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    self->priv->width = width;
+    self->priv->height = height;
+
+    vte_terminal_set_size(VTE_TERMINAL(self->priv->terminal),
+                          self->priv->width,
+                          self->priv->height);
+
+    mud_subwindow_set_size_force_grid(self,
+                                      VTE_TERMINAL(self->priv->terminal),
+                                      TRUE,
+                                      -1,
+                                      -1);
+}
+
+void
+mud_subwindow_show(MudSubwindow *self)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    gtk_widget_show(self->priv->window);
+    self->priv->visible = TRUE;
+}
+
+void
+mud_subwindow_reread_profile(MudSubwindow *self)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    mud_subwindow_set_terminal_colors(self);
+    mud_subwindow_set_terminal_scrollback(self);
+    mud_subwindow_set_terminal_scrolloutput(self);
+    mud_subwindow_set_terminal_font(self);
+}
+
+void
+mud_subwindow_feed(MudSubwindow *self,
+                   const gchar *data,
+                   guint length)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    vte_terminal_feed(VTE_TERMINAL(self->priv->terminal),
+                      data,
+                      length);
+}
+
+void
+mud_subwindow_set_title(MudSubwindow *self,
+                        const gchar *title)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    gtk_window_set_title(GTK_WINDOW(self->priv->window), title);
+}

Added: trunk/src/mud-subwindow.h
==============================================================================
--- (empty file)
+++ trunk/src/mud-subwindow.h	Wed Mar 18 05:57:45 2009
@@ -0,0 +1,64 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-subwindow.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_SUBWINDOW_H
+#define MUD_SUBWINDOW_H
+
+G_BEGIN_DECLS
+
+#define MUD_TYPE_SUBWINDOW              (mud_subwindow_get_type ())
+#define MUD_SUBWINDOW(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_SUBWINDOW, MudSubwindow))
+#define MUD_SUBWINDOW_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_SUBWINDOW, MudSubwindowClass))
+#define MUD_IS_SUBWINDOW(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_SUBWINDOW))
+#define MUD_IS_SUBWINDOW_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_SUBWINDOW))
+#define MUD_SUBWINDOW_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_SUBWINDOW, MudSubwindowClass))
+#define MUD_SUBWINDOW_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_SUBWINDOW, MudSubwindowPrivate))
+
+typedef struct _MudSubwindow            MudSubwindow;
+typedef struct _MudSubwindowClass       MudSubwindowClass;
+typedef struct _MudSubwindowPrivate     MudSubwindowPrivate;
+
+#include <glib.h>
+
+struct _MudSubwindowClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudSubwindow
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudSubwindowPrivate *priv;
+};
+
+GType mud_subwindow_get_type (void);
+
+void mud_subwindow_set_title(MudSubwindow *self, const gchar *title);
+void mud_subwindow_set_size(MudSubwindow *self, guint width, guint height);
+void mud_subwindow_reread_profile(MudSubwindow *self);
+void mud_subwindow_feed(MudSubwindow *self,
+                        const gchar *data,
+                        guint length);
+
+G_END_DECLS
+
+#endif // MUD_SUBWINDOW_H
+

Modified: trunk/src/zmp/zmp-core.c
==============================================================================
--- trunk/src/zmp/zmp-core.c	(original)
+++ trunk/src/zmp/zmp-core.c	Wed Mar 18 05:57:45 2009
@@ -36,6 +36,7 @@
 {
     /* Interface Properties */
     gchar *package;
+    MudTelnetZmp *parent;
 
     /* Private Instance Members */
 };
@@ -45,6 +46,7 @@
 {
     PROP_ZMP_CORE_0,
     PROP_PACKAGE,
+    PROP_PARENT
 };
 
 /* Class Functions */
@@ -99,6 +101,10 @@
     g_object_class_override_property(object_class,
                                      PROP_PACKAGE,
                                      "package");
+
+    g_object_class_override_property(object_class,
+                                     PROP_PARENT,
+                                     "parent");
 }
 
 static void
@@ -115,6 +121,7 @@
 
     /* Set the defaults */
     self->priv->package = NULL;
+    self->priv->parent = NULL;
 }
 
 static GObject *
@@ -134,7 +141,13 @@
 
     self = ZMP_CORE(obj);
 
-    self->priv->package = g_strdup("zmp.");
+    if(!self->priv->parent)
+    {
+        g_printf("ERROR: Tried to instantiate ZmpSubwindow without passing parent MudTelnetZMP\n");
+        g_error("ERROR: Tried to instantiate ZmpSubwindow without passing parent MudTelnetZMP");
+    }
+
+    self->priv->package = g_strdup("zmp");
 
     return obj;
 }
@@ -165,6 +178,10 @@
 
     switch(prop_id)
     {
+        case PROP_PARENT:
+            self->priv->parent = MUD_TELNET_ZMP(g_value_get_object(value));
+            break;
+
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
             break;
@@ -183,6 +200,10 @@
 
     switch(prop_id)
     {
+        case PROP_PARENT:
+            g_value_take_object(value, self->priv->parent);
+            break;
+
         case PROP_PACKAGE:
             g_value_set_string(value, self->priv->package);
             break;

Modified: trunk/src/zmp/zmp-main.c
==============================================================================
--- trunk/src/zmp/zmp-main.c	(original)
+++ trunk/src/zmp/zmp-main.c	Wed Mar 18 05:57:45 2009
@@ -131,11 +131,15 @@
 
     /* zmp.core */
     self->priv->packages = g_list_append(self->priv->packages,
-                                         g_object_new(ZMP_TYPE_CORE, NULL));
+                                         g_object_new(ZMP_TYPE_CORE,
+                                                      "parent", self->priv->parent,
+                                                      NULL));
 
     /* subwindow */
     self->priv->packages = g_list_append(self->priv->packages,
-                                         g_object_new(ZMP_TYPE_SUBWINDOW, NULL));
+                                         g_object_new(ZMP_TYPE_SUBWINDOW,
+                                                      "parent", self->priv->parent,
+                                                      NULL));
 
     return obj;
 }
@@ -231,3 +235,34 @@
     }
 }
 
+ZmpPackage *
+zmp_main_get_package_by_name(ZmpMain *self, const gchar *package_query)
+{
+    GList *entry;
+
+    if(!ZMP_IS_MAIN(self))
+        return NULL;
+
+    entry = g_list_first(self->priv->packages);
+
+    while(entry)
+    {
+        gchar *name;
+        ZmpPackage *package = ZMP_PACKAGE(entry->data);
+
+        g_object_get(package, "package", &name, NULL);
+
+        if(g_str_equal(package_query, name))
+        {
+            g_free(name);
+            return package;
+        }
+
+        g_free(name);
+
+        entry = g_list_next(entry);
+    }
+
+    return NULL;
+}
+

Modified: trunk/src/zmp/zmp-main.h
==============================================================================
--- trunk/src/zmp/zmp-main.h	(original)
+++ trunk/src/zmp/zmp-main.h	Wed Mar 18 05:57:45 2009
@@ -36,6 +36,9 @@
 typedef struct _ZmpMainClass       ZmpMainClass;
 typedef struct _ZmpMainPrivate     ZmpMainPrivate;
 
+#include <glib.h>
+#include "zmp-package-interface.h"
+
 struct _ZmpMainClass
 {
     GObjectClass parent_class;
@@ -52,6 +55,7 @@
 GType zmp_main_get_type (void);
 
 void zmp_main_register_commands(ZmpMain *self);
+ZmpPackage *zmp_main_get_package_by_name(ZmpMain *self, const gchar *package);
 
 G_END_DECLS
 

Modified: trunk/src/zmp/zmp-package-interface.c
==============================================================================
--- trunk/src/zmp/zmp-package-interface.c	(original)
+++ trunk/src/zmp/zmp-package-interface.c	Wed Mar 18 05:57:45 2009
@@ -72,6 +72,14 @@
                                                 NULL,
                                                 G_PARAM_READABLE));
 
+        g_object_interface_install_property(klass,
+                                            g_param_spec_object(
+                                                "parent",
+                                                "Parent",
+                                                "The parent MudTelnetZMP",
+                                                MUD_TYPE_TELNET_ZMP,
+                                                G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
         initialized = TRUE;
     }
 }

Modified: trunk/src/zmp/zmp-subwindow.c
==============================================================================
--- trunk/src/zmp/zmp-subwindow.c	(original)
+++ trunk/src/zmp/zmp-subwindow.c	Wed Mar 18 05:57:45 2009
@@ -25,10 +25,13 @@
 #include <glib-object.h>
 #include <glib/gi18n.h>
 #include <string.h>
+#include <stdlib.h>
 
 #include "gnome-mud.h"
 #include "mud-telnet.h"
+#include "mud-connection-view.h"
 #include "handlers/mud-telnet-handlers.h"
+#include "zmp-main.h"
 #include "zmp-package-interface.h"
 #include "zmp-subwindow.h"
 
@@ -36,6 +39,7 @@
 {
     /* Interface Properties */
     gchar *package;
+    MudTelnetZmp *parent;
 
     /* Private Instance Members */
 };
@@ -45,6 +49,7 @@
 {
     PROP_ZMP_SUBWINDOW_0,
     PROP_PACKAGE,
+    PROP_PARENT
 };
 
 /* Class Functions */
@@ -70,9 +75,14 @@
 /* Subwindow Commands */
 static void zmp_subwindow_open(MudTelnetZmp *self, gint argc, gchar **argv);
 static void zmp_subwindow_close(MudTelnetZmp *self, gint argc, gchar **argv);
-static void zmp_subwindow_size(MudTelnetZmp *self, gint argc, gchar **argv);
-static void zmp_subwindow_set_input(MudTelnetZmp *self, gint argc, gchar **argv);
 static void zmp_subwindow_select(MudTelnetZmp *self, gint argc, gchar **argv);
+static void zmp_subwindow_do_input(MudSubwindow *sub,
+                                   const gchar *input,
+                                   ZmpSubwindow *self);
+static void zmp_subwindow_size(MudSubwindow *sub,
+                               guint width,
+                               guint height,
+                               ZmpSubwindow *self);
 
 /* Create the Type. We implement ZmpPackageInterface */
 G_DEFINE_TYPE_WITH_CODE(ZmpSubwindow, zmp_subwindow, G_TYPE_OBJECT,
@@ -101,6 +111,10 @@
     g_object_class_override_property(object_class,
                                      PROP_PACKAGE,
                                      "package");
+
+    g_object_class_override_property(object_class,
+                                     PROP_PARENT,
+                                     "parent");
 }
 
 static void
@@ -117,6 +131,7 @@
 
     /* Set the defaults */
     self->priv->package = NULL;
+    self->priv->parent = NULL;
 }
 
 static GObject *
@@ -136,7 +151,13 @@
 
     self = ZMP_SUBWINDOW(obj);
 
-    self->priv->package = g_strdup("zmp.");
+    if(!self->priv->parent)
+    {
+        g_printf("ERROR: Tried to instantiate ZmpSubwindow without passing parent MudTelnetZMP\n");
+        g_error("ERROR: Tried to instantiate ZmpSubwindow without passing parent MudTelnetZMP");
+    }
+
+    self->priv->package = g_strdup("subwindow");
 
     return obj;
 }
@@ -167,6 +188,10 @@
 
     switch(prop_id)
     {
+        case PROP_PARENT:
+            self->priv->parent = MUD_TELNET_ZMP(g_value_get_object(value));
+            break;
+
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
             break;
@@ -185,6 +210,10 @@
 
     switch(prop_id)
     {
+        case PROP_PARENT:
+            g_value_take_object(value, self->priv->parent);
+            break;
+
         case PROP_PACKAGE:
             g_value_set_string(value, self->priv->package);
             break;
@@ -208,39 +237,155 @@
                                               "subwindow.close",
                                               zmp_subwindow_close));
     mud_zmp_register(zmp, mud_zmp_new_command("subwindow.",
+                                              "subwindow.select",
+                                              zmp_subwindow_select));
+
+    /* If the server sends us these, its a broken server.
+     * We send these commands to the server. */
+    mud_zmp_register(zmp, mud_zmp_new_command("subwindow.",
                                               "subwindow.size",
-                                              zmp_subwindow_size));
+                                              NULL));
     mud_zmp_register(zmp, mud_zmp_new_command("subwindow.",
                                               "subwindow.set-input",
-                                              zmp_subwindow_set_input));
-    mud_zmp_register(zmp, mud_zmp_new_command("subwindow.",
-                                              "subwindow.select",
-                                              zmp_subwindow_select));
+                                              NULL));
 }
 
 /* ZmpSubwindow Commands */
 static void
-zmp_subwindow_open(MudTelnetZmp *self, gint argc, gchar **argv)
-{
+zmp_subwindow_open(MudTelnetZmp *self,
+                   gint argc,
+                   gchar **argv)
+{
+    MudConnectionView *view;
+    MudTelnet *telnet;
+    MudSubwindow *sub;
+    ZmpSubwindow *pkg;
+    ZmpMain *zmp_main;
+
+    if(argc != 5)
+        return;
+
+    g_object_get(self,
+                 "telnet", &telnet,
+                 "zmp-main", &zmp_main,
+                 NULL);
+    g_object_get(telnet, "parent-view", &view, NULL);
+    
+    pkg = zmp_main_get_package_by_name(zmp_main, "subwindow");
+
+    if(mud_connection_view_has_subwindow(view, argv[1]))
+    {
+        sub = mud_connection_view_get_subwindow(view, argv[1]);
+
+        g_object_set(sub, "title", argv[2], NULL);
+        mud_subwindow_set_title(sub, argv[2]);
+        mud_subwindow_set_size(sub,
+                               (guint)atol(argv[3]),
+                               (guint)atol(argv[4]));
+
+        mud_connection_view_show_subwindow(view, argv[1]);
+    }
+    else
+    {
+        sub = mud_connection_view_create_subwindow(view,
+                                                   argv[2],
+                                                   argv[1],
+                                                   (guint)atol(argv[3]),
+                                                   (guint)atol(argv[4]));
+
+        g_signal_connect(sub,
+                         "resized",
+                         G_CALLBACK(zmp_subwindow_size),
+                         pkg);
+
+        g_signal_connect(sub,
+                         "input-received",
+                         G_CALLBACK(zmp_subwindow_do_input),
+                         pkg);
+    }
 }
 
 static void
-zmp_subwindow_close(MudTelnetZmp *self, gint argc, gchar **argv)
+zmp_subwindow_close(MudTelnetZmp *self,
+                    gint argc,
+                    gchar **argv)
 {
+    MudConnectionView *view;
+    MudTelnet *telnet;
+
+    if(argc != 2)
+        return;
+
+    g_object_get(self, "telnet", &telnet, NULL);
+    g_object_get(telnet, "parent-view", &view, NULL);
+
+    mud_connection_view_remove_subwindow(view, argv[1]);
 }
 
 static void
-zmp_subwindow_size(MudTelnetZmp *self, gint argc, gchar **argv)
+zmp_subwindow_select(MudTelnetZmp *self,
+                     gint argc,
+                     gchar **argv)
 {
+    MudConnectionView *view;
+    MudTelnet *telnet;
+
+    if(argc != 2)
+        return;
+
+    g_object_get(self, "telnet", &telnet, NULL);
+    g_object_get(telnet, "parent-view", &view, NULL);
+
+    mud_connection_view_set_output(view, argv[1]);
 }
 
 static void
-zmp_subwindow_set_input(MudTelnetZmp *self, gint argc, gchar **argv)
+zmp_subwindow_do_input(MudSubwindow *sub,
+                       const gchar *input,
+                       ZmpSubwindow *self)
 {
+    MudConnectionView *view;
+    gchar *identifier;
+
+    g_object_get(sub,
+                 "identifier", &identifier,
+                 "parent-view", &view,
+                 NULL);
+
+    mud_zmp_send_command(self->priv->parent, 2,
+                         "subwindow.set-input",
+                         identifier);
+
+    mud_connection_view_send(view, input);
+
+    mud_zmp_send_command(self->priv->parent, 2,
+                         "subwindow.set-input",
+                         "main");
+
+    g_free(identifier);
 }
 
 static void
-zmp_subwindow_select(MudTelnetZmp *self, gint argc, gchar **argv)
+zmp_subwindow_size(MudSubwindow *sub,
+                   guint width,
+                   guint height,
+                   ZmpSubwindow *self)
 {
+    gchar *identifier;
+    gchar *w, *h;
+
+    g_object_get(sub, "identifier", &identifier, NULL);
+    w = g_strdup_printf("%d", width);
+    h = g_strdup_printf("%d", height);
+
+    mud_zmp_send_command(self->priv->parent, 4,
+                         "subwindow.size",
+                         identifier,
+                         w,
+                         h);
+
+    g_free(w);
+    g_free(h);
+    g_free(identifier);
 }
 

Modified: trunk/src/zmp/zmp-subwindow.h
==============================================================================
--- trunk/src/zmp/zmp-subwindow.h	(original)
+++ trunk/src/zmp/zmp-subwindow.h	Wed Mar 18 05:57:45 2009
@@ -36,6 +36,8 @@
 typedef struct _ZmpSubwindowClass       ZmpSubwindowClass;
 typedef struct _ZmpSubwindowPrivate     ZmpSubwindowPrivate;
 
+#include "handlers/mud-telnet-handlers.h"
+
 struct _ZmpSubwindowClass
 {
     GObjectClass parent_class;

Modified: trunk/ui/main.glade
==============================================================================
--- trunk/ui/main.glade	(original)
+++ trunk/ui/main.glade	Wed Mar 18 05:57:45 2009
@@ -517,4 +517,10 @@
       </widget>
     </child>
   </widget>
+  <widget class="GtkWindow" id="subwindow">
+    <property name="destroy_with_parent">True</property>
+    <child>
+      <placeholder/>
+    </child>
+  </widget>
 </glade-interface>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]