(root)/
glib-2.79.0/
gobject/
tests/
basics-gobject.c
       1  /* GObject - GLib Type, Object, Parameter and Signal Library
       2   * Copyright (C) 2001 Red Hat, Inc.
       3   *
       4   * This library is free software; you can redistribute it and/or
       5   * modify it under the terms of the GNU Lesser General Public
       6   * License as published by the Free Software Foundation; either
       7   * version 2.1 of the License, or (at your option) any later version.
       8   *
       9   * This library is distributed in the hope that it will be useful,
      10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12   * Lesser General Public License for more details.
      13   *
      14   * You should have received a copy of the GNU Lesser General
      15   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16   */
      17  
      18  #include <glib-object.h>
      19  
      20  #include <string.h>
      21  
      22  #undef  G_LOG_DOMAIN
      23  #define G_LOG_DOMAIN "TestObject"
      24  
      25  /* --- TestIface --- */
      26  #define TEST_TYPE_IFACE           (test_iface_get_type ())
      27  #define TEST_IFACE(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_IFACE, TestIface))
      28  #define TEST_IS_IFACE(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_IFACE))
      29  #define TEST_IFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE, TestIfaceClass))
      30  typedef struct _TestIface      TestIface;
      31  typedef struct _TestIfaceClass TestIfaceClass;
      32  struct _TestIfaceClass
      33  {
      34    GTypeInterface base_iface;
      35    void (*print_string) (TestIface   *tiobj,
      36                          const gchar *string);
      37  };
      38  static void iface_base_init     (TestIfaceClass *iface);
      39  static void iface_base_finalize (TestIfaceClass *iface);
      40  static void print_foo           (TestIface *tiobj,
      41                                   const gchar *string);
      42  static GType
      43  test_iface_get_type (void)
      44  {
      45    static GType test_iface_type = 0;
      46  
      47    if (!test_iface_type)
      48      {
      49        const GTypeInfo test_iface_info =
      50        {
      51          sizeof (TestIfaceClass),
      52          (GBaseInitFunc) iface_base_init,          /* base_init */
      53          (GBaseFinalizeFunc) iface_base_finalize,  /* base_finalize */
      54          NULL,
      55          NULL,
      56          NULL,
      57          0,
      58          0,
      59          NULL,
      60          NULL
      61        };
      62  
      63        test_iface_type = g_type_register_static (G_TYPE_INTERFACE, "TestIface", &test_iface_info, 0);
      64        g_type_interface_add_prerequisite (test_iface_type, G_TYPE_OBJECT);
      65      }
      66  
      67    return test_iface_type;
      68  }
      69  static guint iface_base_init_count = 0;
      70  static void
      71  iface_base_init (TestIfaceClass *iface)
      72  {
      73    iface_base_init_count++;
      74    if (iface_base_init_count == 1)
      75      {
      76        /* add signals here */
      77      }
      78  }
      79  static void
      80  iface_base_finalize (TestIfaceClass *iface)
      81  {
      82    iface_base_init_count--;
      83    if (iface_base_init_count == 0)
      84      {
      85        /* destroy signals here */
      86      }
      87  }
      88  static void
      89  print_foo (TestIface   *tiobj,
      90             const gchar *string)
      91  {
      92    if (!string)
      93      string = "<NULL>";
      94    g_test_message ("Iface-FOO: \"%s\" from %p", string, tiobj);
      95  }
      96  static void
      97  test_object_test_iface_init (gpointer giface,
      98                               gpointer iface_data)
      99  {
     100    TestIfaceClass *iface = giface;
     101  
     102    g_assert (iface_data == GUINT_TO_POINTER (42));
     103    g_assert_cmpint (G_TYPE_FROM_INTERFACE (iface), ==, TEST_TYPE_IFACE);
     104  
     105    /* assert iface_base_init() was already called */
     106    g_assert_cmpuint (iface_base_init_count, >, 0);
     107  
     108    /* initialize stuff */
     109    iface->print_string = print_foo;
     110  }
     111  static void
     112  iface_print_string (TestIface   *tiobj,
     113                      const gchar *string)
     114  {
     115    TestIfaceClass *iface;
     116  
     117    g_return_if_fail (TEST_IS_IFACE (tiobj));
     118    g_return_if_fail (G_IS_OBJECT (tiobj)); /* ensured through prerequisite */
     119  
     120    iface = TEST_IFACE_GET_CLASS (tiobj);
     121    g_object_ref (tiobj);
     122    iface->print_string (tiobj, string);
     123    g_object_unref (tiobj);
     124  }
     125  
     126  
     127  /* --- TestObject --- */
     128  #define TEST_TYPE_OBJECT            (test_object_get_type ())
     129  #define TEST_OBJECT(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_OBJECT, TestObject))
     130  #define TEST_OBJECT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OBJECT, TestObjectClass))
     131  #define TEST_IS_OBJECT(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_OBJECT))
     132  #define TEST_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_OBJECT))
     133  #define TEST_OBJECT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJECT, TestObjectClass))
     134  #define TEST_OBJECT_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), TEST_TYPE_OBJECT, TestObjectPrivate))
     135  typedef struct _TestObject        TestObject;
     136  typedef struct _TestObjectClass   TestObjectClass;
     137  typedef struct _TestObjectPrivate TestObjectPrivate;
     138  struct _TestObject
     139  {
     140    GObject parent_instance;
     141  };
     142  struct _TestObjectClass
     143  {
     144    GObjectClass parent_class;
     145  
     146    gchar* (*test_signal) (TestObject *tobject,
     147                           TestIface  *iface_object,
     148                           gpointer    tdata);
     149  };
     150  struct _TestObjectPrivate
     151  {
     152    int     dummy1;
     153    gdouble dummy2;
     154  };
     155  static void     test_object_class_init  (TestObjectClass        *class);
     156  static void     test_object_init        (TestObject             *tobject);
     157  static gboolean test_signal_accumulator (GSignalInvocationHint  *ihint,
     158                                           GValue                 *return_accu,
     159                                           const GValue           *handler_return,
     160                                           gpointer                data);
     161  static gchar*   test_object_test_signal (TestObject             *tobject,
     162                                           TestIface              *iface_object,
     163                                           gpointer                tdata);
     164  static gint TestObject_private_offset;
     165  static inline gpointer
     166  test_object_get_instance_private (TestObject *self)
     167  {
     168    return (G_STRUCT_MEMBER_P (self, TestObject_private_offset));
     169  }
     170  
     171  static GType
     172  test_object_get_type (void)
     173  {
     174    static GType test_object_type = 0;
     175  
     176    if (!test_object_type)
     177      {
     178        const GTypeInfo test_object_info =
     179        {
     180          sizeof (TestObjectClass),
     181          NULL,           /* base_init */
     182          NULL,           /* base_finalize */
     183          (GClassInitFunc) test_object_class_init,
     184          NULL,           /* class_finalize */
     185          NULL,           /* class_data */
     186          sizeof (TestObject),
     187          5,              /* n_preallocs */
     188          (GInstanceInitFunc) test_object_init,
     189          NULL
     190        };
     191        GInterfaceInfo iface_info = { test_object_test_iface_init, NULL, GUINT_TO_POINTER (42) };
     192  
     193        test_object_type = g_type_register_static (G_TYPE_OBJECT, "TestObject", &test_object_info, 0);
     194        g_type_add_interface_static (test_object_type, TEST_TYPE_IFACE, &iface_info);
     195  
     196        TestObject_private_offset =
     197          g_type_add_instance_private (test_object_type, sizeof (TestObjectPrivate));
     198      }
     199  
     200    return test_object_type;
     201  }
     202  static void
     203  test_object_class_init (TestObjectClass *class)
     204  {
     205    /*  GObjectClass *gobject_class = G_OBJECT_CLASS (class); */
     206    g_type_class_adjust_private_offset (class, &TestObject_private_offset);
     207  
     208    class->test_signal = test_object_test_signal;
     209  
     210    g_signal_new ("test-signal",
     211                  G_OBJECT_CLASS_TYPE (class),
     212                  G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
     213                  G_STRUCT_OFFSET (TestObjectClass, test_signal),
     214                  test_signal_accumulator, NULL,
     215                  g_cclosure_marshal_STRING__OBJECT_POINTER,
     216                  G_TYPE_STRING, 2, TEST_TYPE_IFACE, G_TYPE_POINTER);
     217  }
     218  static void
     219  test_object_init (TestObject *tobject)
     220  {
     221    TestObjectPrivate *priv = test_object_get_instance_private (tobject);
     222    g_assert_nonnull (priv);
     223  
     224    priv->dummy1 = 54321;
     225  }
     226  /* Check to see if private data initialization in the
     227   * instance init function works.
     228   */
     229  static void
     230  test_object_check_private_init (TestObject *tobject)
     231  {
     232    TestObjectPrivate *priv = test_object_get_instance_private (tobject);
     233  
     234    g_test_message ("private data during initialization: %u == %u", priv->dummy1, 54321);
     235    g_assert_cmpint (priv->dummy1, ==, 54321);
     236  }
     237  static gboolean
     238  test_signal_accumulator (GSignalInvocationHint *ihint,
     239                           GValue                *return_accu,
     240                           const GValue          *handler_return,
     241                           gpointer               data)
     242  {
     243    const gchar *accu_string = g_value_get_string (return_accu);
     244    const gchar *new_string = g_value_get_string (handler_return);
     245    gchar *result_string;
     246  
     247    if (accu_string)
     248      result_string = g_strconcat (accu_string, new_string, NULL);
     249    else if (new_string)
     250      result_string = g_strdup (new_string);
     251    else
     252      result_string = NULL;
     253  
     254    g_value_take_string (return_accu, result_string);
     255  
     256    return TRUE;
     257  }
     258  static gchar*
     259  test_object_test_signal (TestObject *tobject,
     260                           TestIface  *iface_object,
     261                           gpointer    tdata)
     262  {
     263    g_test_message ("::test_signal default_handler called");
     264  
     265    g_return_val_if_fail (TEST_IS_IFACE (iface_object), NULL);
     266  
     267    return g_strdup ("<default_handler>");
     268  }
     269  
     270  
     271  /* --- TestIface for DerivedObject --- */
     272  static void
     273  print_bar (TestIface   *tiobj,
     274             const gchar *string)
     275  {
     276    TestIfaceClass *parent_iface;
     277  
     278    g_return_if_fail (TEST_IS_IFACE (tiobj));
     279  
     280    if (!string)
     281      string = "<NULL>";
     282    g_test_message ("Iface-BAR: \"%s\" from %p", string, tiobj);
     283  
     284    g_test_message ("chaining: ");
     285    parent_iface = g_type_interface_peek_parent (TEST_IFACE_GET_CLASS (tiobj));
     286    parent_iface->print_string (tiobj, string);
     287  
     288    g_assert_null (g_type_interface_peek_parent (parent_iface));
     289  }
     290  
     291  static void
     292  derived_object_test_iface_init (gpointer giface,
     293                                  gpointer iface_data)
     294  {
     295    TestIfaceClass *iface = giface;
     296  
     297    g_assert (iface_data == GUINT_TO_POINTER (87));
     298    g_assert (G_TYPE_FROM_INTERFACE (iface) == TEST_TYPE_IFACE);
     299  
     300    /* assert test_object_test_iface_init() was already called */
     301    g_assert (iface->print_string == print_foo);
     302  
     303    /* override stuff */
     304    iface->print_string = print_bar;
     305  }
     306  
     307  
     308  /* --- DerivedObject --- */
     309  #define DERIVED_TYPE_OBJECT            (derived_object_get_type ())
     310  #define DERIVED_OBJECT(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), DERIVED_TYPE_OBJECT, DerivedObject))
     311  #define DERIVED_OBJECT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), DERIVED_TYPE_OBJECT, DerivedObjectClass))
     312  #define DERIVED_IS_OBJECT(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), DERIVED_TYPE_OBJECT))
     313  #define DERIVED_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DERIVED_TYPE_OBJECT))
     314  #define DERIVED_OBJECT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), DERIVED_TYPE_OBJECT, DerivedObjectClass))
     315  #define DERIVED_OBJECT_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), DERIVED_TYPE_OBJECT, DerivedObjectPrivate))
     316  typedef struct _DerivedObject        DerivedObject;
     317  typedef struct _TestObjectClass      DerivedObjectClass;
     318  typedef struct _DerivedObjectPrivate DerivedObjectPrivate;
     319  struct _DerivedObject
     320  {
     321    TestObject parent_instance;
     322    int  dummy1;
     323    int  dummy2;
     324  };
     325  struct _DerivedObjectPrivate
     326  {
     327    char dummy;
     328  };
     329  static void derived_object_class_init (DerivedObjectClass *class);
     330  static void derived_object_init       (DerivedObject      *dobject);
     331  static gint DerivedObject_private_offset;
     332  static inline gpointer
     333  derived_object_get_instance_private (DerivedObject *self)
     334  {
     335    return (G_STRUCT_MEMBER_P (self, DerivedObject_private_offset));
     336  }
     337  static GType
     338  derived_object_get_type (void)
     339  {
     340    static GType derived_object_type = 0;
     341  
     342    if (!derived_object_type)
     343      {
     344        const GTypeInfo derived_object_info =
     345        {
     346          sizeof (DerivedObjectClass),
     347          NULL,           /* base_init */
     348          NULL,           /* base_finalize */
     349          (GClassInitFunc) derived_object_class_init,
     350          NULL,           /* class_finalize */
     351          NULL,           /* class_data */
     352          sizeof (DerivedObject),
     353          5,              /* n_preallocs */
     354          (GInstanceInitFunc) derived_object_init,
     355          NULL
     356        };
     357        GInterfaceInfo iface_info = { derived_object_test_iface_init, NULL, GUINT_TO_POINTER (87) };
     358  
     359        derived_object_type = g_type_register_static (TEST_TYPE_OBJECT, "DerivedObject", &derived_object_info, 0);
     360        g_type_add_interface_static (derived_object_type, TEST_TYPE_IFACE, &iface_info);
     361        DerivedObject_private_offset =
     362          g_type_add_instance_private (derived_object_type, sizeof (DerivedObjectPrivate));
     363      }
     364  
     365    return derived_object_type;
     366  }
     367  static void
     368  derived_object_class_init (DerivedObjectClass *class)
     369  {
     370    g_type_class_adjust_private_offset (class, &DerivedObject_private_offset);
     371  }
     372  static void
     373  derived_object_init (DerivedObject *dobject)
     374  {
     375    TestObjectPrivate *test_priv;
     376    DerivedObjectPrivate *derived_priv;
     377  
     378    derived_priv = derived_object_get_instance_private (dobject);
     379    g_assert_nonnull (derived_priv);
     380  
     381    test_priv = test_object_get_instance_private (TEST_OBJECT (dobject));
     382    g_assert_nonnull (test_priv);
     383  }
     384  
     385  static void
     386  test_gobject_basics (void)
     387  {
     388    GTypeInfo info = { 0, };
     389    GTypeFundamentalInfo finfo = { 0, };
     390    GType type;
     391    TestObject *sigarg;
     392    DerivedObject *dobject;
     393    TestObjectPrivate *priv;
     394    gchar *string = NULL;
     395  
     396    g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
     397                            G_LOG_LEVEL_WARNING |
     398                            G_LOG_LEVEL_CRITICAL);
     399  
     400    /* test new fundamentals */
     401    g_assert (G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST) == g_type_fundamental_next ());
     402    type = g_type_register_fundamental (g_type_fundamental_next (), "FooShadow1", &info, &finfo, 0);
     403    g_assert (type == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST));
     404    g_assert (G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST + 1) == g_type_fundamental_next ());
     405    type = g_type_register_fundamental (g_type_fundamental_next (), "FooShadow2", &info, &finfo, 0);
     406    g_assert (type == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST + 1));
     407    g_assert (G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST + 2) == g_type_fundamental_next ());
     408    g_assert (g_type_from_name ("FooShadow1") == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST));
     409    g_assert (g_type_from_name ("FooShadow2") == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST + 1));
     410  
     411    /* to test past class initialization interface setups, create the class here */
     412    g_type_class_ref (TEST_TYPE_OBJECT);
     413  
     414    dobject = g_object_new (DERIVED_TYPE_OBJECT, NULL);
     415    test_object_check_private_init (TEST_OBJECT (dobject));
     416  
     417    sigarg = g_object_new (TEST_TYPE_OBJECT, NULL);
     418  
     419    g_test_message ("MAIN: emit test-signal:");
     420    g_signal_emit_by_name (dobject, "test-signal", sigarg, NULL, &string);
     421    g_test_message ("signal return: \"%s\"", string);
     422    g_assert_cmpstr (string, ==, "<default_handler><default_handler><default_handler>");
     423    g_free (string);
     424  
     425    g_test_message ("MAIN: call iface print-string on test and derived object:");
     426    iface_print_string (TEST_IFACE (sigarg), "iface-string-from-test-type");
     427    iface_print_string (TEST_IFACE (dobject), "iface-string-from-derived-type");
     428  
     429    priv = test_object_get_instance_private (TEST_OBJECT (dobject));
     430    g_test_message ("private data after initialization: %u == %u", priv->dummy1, 54321);
     431    g_assert_cmpint (priv->dummy1, ==, 54321);
     432  
     433    g_object_unref (sigarg);
     434    g_object_unref (dobject);
     435  }
     436  
     437  int
     438  main (int argc, char *argv[])
     439  {
     440    g_test_init (&argc, &argv, NULL);
     441  
     442    g_test_add_func ("/gobject/basics", test_gobject_basics);
     443  
     444    return g_test_run ();
     445  }