Re: libglade vs glade for dialog generation



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Gus Koppel <gtk spamkiller bytechase cx> writes:

Tim MÃller wrote:

- Doing without libglade typically also saves RAM, from some
hundreds  KB up to MBs, which may be important for certain target
platforms.

If that is a concern, mmap() your .glade file into memory, and use 
glade_xml_new_from_buffer().

It's not only the XML file but also all the additional libraries which
need to be loaded and require their own data objects in RAM. Besides, I
have a Glade XML file that's more than 1 MB in size. All together adds
more than 2 MB of RAM consumption as a minimum, compared to hardcode.
[...]
You suggest writing a number of extensions, i.e. Perl scripts to
generate code, or own convenience functions to better deal with
libglade. None of it is required when just using the Glade generated
code. To me, this sounds like asking many programmers to reinvent the
wheel on their own, just because the original wheel has become
deprecated by its inventor. Someone else recently mentioned, using
libglade would be easier, i.e. simplifying the code. I contradicted
prior to your suggestions, but they make it even more obvious that using
libglade isn't a simplification for writers, compared to Glade code.

I don't agree with these assertions.  While Glade-generated code is
certainly convenient, I don't believe that it is better (I don't
personally like the generated code).  I imagine that the 1 MiB Glade
file describes quite a complex interface, but when I'm writing a
program, I generally find that a single "monolithic" interface is not
sufficiently structured to allow for a good overall design.  I can
usually soon spot particular widgets, or sets of widgets that have
particular responsibilities, which are really objects in their own
right.  For these cases, it makes sense to derive new first-class
widgets to really take advantage of the framework GTK/GLib offers.

This does not preclude the use of Glade: the derived widgets can make
use of Glade internally.  I've pasted a sample template object derived
from GtkWindow as an example (at the end).  This is simple to change
for different Glade interfaces, or to derive from a different object.
It just needs some methods adding.  In this case, I do believe
libglade offers significant improvements in the clarity of the code,
and it allows me to add proper GObject properties, signals etc., which
means the application can be structured very nicely (e.g. Model/View
(or Presenter)), since each object can reference a [shared] model,
and interact with the other components via signals.

If you take your Glade file and callbacks, all you need to do is paste
in your signal handlers as class methods, and you've replaced the
Glade-generated code.

This isn't something I would have written a year ago--it's taken
several months of using Gtkmm last year to really appreciate the
beauty of this approach in C as well.  I'm not sure how typical it is,
though.

Let me briefly sum up, again. Using libglade + XML file instead of Glade
generated code means, you
- have more external library dependancies, therefore
- have higher disk space consumption

Agreed, but it's only two libraries, which are standard on all Linux
distributions, and on a typical desktop are probably already in use.

- have greater installation package if it's to be self-contained

This isn't an issue for a mainstream Linux distribution, and the
Windows GTK+ installer at gladewin32.sf.net includes libglade, AFAICT.

- have higher RAM conumption at application execution time
- have lower application execution speed (dialog open delays)

This is very true, but I guess this is one of the places where you
trade speed for convenience, and you can always unref the GladeXML
object once the UI has been constructed.

- should write extra conviencience funtions to compensate libglade's
  deficencies.

If you write your code making full use of GObject/GType, this is not a
problem.  I'm assuming here you are referring to lookup_widget(); the
solution there is to use glade_xml_get_widget to find the widgets you
need during object initialisation/realisation and store them in the
object structure.  This way, all your object methods have easy access
to them, as if you had constructed the UI by hand.


Regards,
Roger


This is a generic template I use (cleaned up a little bit, but it
might require a C99 compiler):

/* example-mainwindow - Generic mainwindow for a Glade UI
 *
 * Copyright (C) 2004-2005  Roger Leigh <rleigh debian 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 EXAMPLE_MAINWINDOW_H
#define EXAMPLE_MAINWINDOW_H

#include <gtk/gtk.h>
#include <glade/glade.h>

#define EXAMPLE_TYPE_MAINWINDOW           (example_mainwindow_get_type ())
#define EXAMPLE_MAINWINDOW(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_MAINWINDOW, 
ExampleMainwindow))
#define EXAMPLE_MAINWINDOW_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_MAINWINDOW, 
ExampleMainwindowClass))
#define EXAMPLE_IS_MAINWINDOW(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_MAINWINDOW))
#define EXAMPLE_IS_MAINWINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_MAINWINDOW))
#define EXAMPLE_MAINWINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_MAINWINDOW, 
ExampleMainwindowClass))

typedef struct _ExampleMainwindow ExampleMainwindow;
typedef struct _ExampleMainwindowClass ExampleMainwindowClass;

struct _ExampleMainwindow
{
  GtkWindow    parent;          /* The object derives from GtkWindow. */
  GladeXML    *xml;             /* The XML interface. */
  /* Widgets contained within the window. */
/*   GtkButton   *quit_button;  /\* Quit button. *\/ */
};

struct _ExampleMainwindowClass
{
  /* The class derives from GtkWindowClass. */
  GtkWindowClass parent;
  /* No other class properties are required (e.g. virtual
     functions). */
};

GType example_mainwindow_get_type (void);

ExampleMainwindow *
example_mainwindow_new (void);

gboolean
example_mainwindow_on_delete_event( ExampleMainwindow *example_mainwindow,
                                    GdkEvent          *event,
                                    gpointer           data );

#endif /* EXAMPLE_MAINWINDOW_H */

/*
 * Local Variables:
 * mode:C
 * End:
 */


/* example-mainwindow - Generic mainwindow for a Glade UI
 *
 * Copyright (C) 2004-2005  Roger Leigh <rleigh debian 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.
 *
 *********************************************************************/

#include "example-mainwindow.h"

G_DEFINE_TYPE(ExampleMainwindow, example_mainwindow, GTK_TYPE_WINDOW)

ExampleMainwindow *
example_mainwindow_new (void)
{
  return (ExampleMainwindow *) g_object_new (EXAMPLE_TYPE_MAINWINDOW, NULL);
}

static void
example_mainwindow_init( ExampleMainwindow *self )
{
  GtkVBox *main_vbox;

  /* Set the window title */
  gtk_window_set_title(GTK_WINDOW (self),
                       "Glade Window");

  /* Permit resizing */
  gtk_window_set_resizable(GTK_WINDOW (self), TRUE);

  /* Connect the window close button ("destroy-event") to
     a callback. */
  g_signal_connect(G_OBJECT (self), "delete-event",
                   G_CALLBACK (example_mainwindow_on_delete_event),
                   NULL);

  /* Load the interface description. */
  self->xml = glade_xml_new("glade-window.glade",
                            "main_vbox", NULL);

  /* Get the widgets, and put them in the our object structure */
  /*   self->quit_button = GTK_BUTTON */
  /*     (glade_xml_get_widget (self->xml, "quit_button")); */

  /* Set up the signal handlers. */
  glade_xml_signal_autoconnect(self->xml);

/*   g_signal_connect_swapped */
/*     (G_OBJECT (self->quit_button), "clicked", */
/*      G_CALLBACK (gtk_widget_hide), */
/*      (gpointer) self); */

  /* Get the interface root and pack it into our window. */
  gtk_container_add
    (GTK_CONTAINER (self),
     glade_xml_get_widget(self->xml, "main_vbox"));
}

static void
example_mainwindow_finalize (ExampleMainwindow *self)
{
  /* Free the Glade XML interface description. */
  if (self->xml)
    {
      g_object_unref(G_OBJECT(self->xml));
      self->xml = NULL;
    }
}

/*
 * This function is called when the window is about to be
 * destroyed (e.g. if the close button on the window was
 * clicked).  It is not a destructor.
 */
gboolean
example_mainwindow_on_delete_event(ExampleMainwindow *example_mainwindow,
                               GdkEvent      *event,
                               gpointer      user_data)
{
  gtk_widget_hide(GTK_WIDGET (example_mainwindow));
  /* We return true because the object should not be
     automatically destroyed. */
  return TRUE;
}

static void
example_mainwindow_set_property (GObject      *object,
                                 guint         param_id,
                                 const GValue *value,
                                 GParamSpec   *pspec)
{
  ExampleMainwindow *self;

  g_return_if_fail (object != NULL);
  g_return_if_fail (EXAMPLE_IS_MAINWINDOW (object));

  self = EXAMPLE_MAINWINDOW(object);

  switch (param_id)
    {
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
      break;
    }
}

static void
example_mainwindow_get_property (GObject    *object,
                                 guint       param_id,
                                 GValue     *value,
                                 GParamSpec *pspec)
{
  ExampleMainwindow *self;

  g_return_if_fail (object != NULL);
  g_return_if_fail (EXAMPLE_IS_MAINWINDOW (object));

  self = EXAMPLE_MAINWINDOW(object);

  switch (param_id)
    {
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
      break;
    }
}


static void
example_mainwindow_class_init ( ExampleMainwindowClass *klass )
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->finalize = (GObjectFinalizeFunc) example_mainwindow_finalize;
  gobject_class->set_property = (GObjectSetPropertyFunc) example_mainwindow_set_property;
  gobject_class->get_property = (GObjectGetPropertyFunc) example_mainwindow_get_property;

  /* Install properties here */
}

/*
 * Local Variables:
 * mode:C
 * End:
 */


/* example-main - main() to run a window
 *
 * Copyright (C) 2004-2005  Roger Leigh <rleigh debian 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.
 *
 *********************************************************************/

#include <gtk/gtk.h>

#include "example-mainwindow.h"

int
main (int argc, char *argv[])
{
  ExampleMainwindow *win;

  /* Initialise GTK+. */
  gtk_init(&argc, &argv);

  /* Create an ExampleMainwindow object. */
  win = example_mainwindow_new();
  /* When the widget is hidden, quit the GTK+ main loop. */
  g_signal_connect(G_OBJECT (win), "hide",
                   G_CALLBACK (gtk_main_quit), NULL);

  gtk_widget_show(GTK_WIDGET (win));

  gtk_main();

  gtk_widget_destroy(GTK_WIDGET (win));

  return 0;
}

/*
 * Local Variables:
 * mode:C
 * End:
 */


- -- 
Roger Leigh
                Printing on GNU/Linux?  http://gimp-print.sourceforge.net/
                Debian GNU/Linux        http://www.debian.org/
                GPG Public Key: 0x25BFB848.  Please sign and encrypt your mail.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.8 <http://mailcrypt.sourceforge.net/>

iD8DBQFB8CGZVcFcaSW/uEgRAtWAAJ0bt4x6qdS9q0xhV7vqk+HLNB58cACg60W+
GNPIyPWrvMcjvWMgjv36xCY=
=jA6G
-----END PGP SIGNATURE-----



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