grim/guifications3
Clone
Summary
Browse
Changes
Graph
moved guifications-gtk to cmake
cmake
2010-12-13, Gary Kramlich
36e02fafe588
moved guifications-gtk to cmake
/*
* Guifications - The end-all, be-all notification framework
* Copyright (C) 2003-2009 Gary Kramlich <grim@reaperworld.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include
<gflib/gf_type.h>
#include
<gflib/gf_intl.h>
#define GF_TYPE_QUERY_CONTEXT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), GF_TYPE_TYPE_QUERY_CONTEXT, GfTypeQueryContextPrivate))
/******************************************************************************
* structs
*****************************************************************************/
typedef
struct
{
GfTypeQuery
*
query
;
gboolean
recursive
;
gpointer
data
;
GDestroyNotify
destroy_notify
;
}
GfTypeQueryContextPrivate
;
/******************************************************************************
* enums
*****************************************************************************/
enum
{
PROP_ZERO
,
PROP_QUERY
,
PROP_RECURSIVE
,
PROP_DATA
,
PROP_DESTROY_NOTIFY
,
PROP_LAST
,
};
/******************************************************************************
* globals
*****************************************************************************/
static
GObjectClass
*
parent_class
=
NULL
;
/******************************************************************************
* query context stuff
*****************************************************************************/
static
inline
void
gf_type_query_context_real_params
(
GfTypeQueryContext
*
ctx
,
GObjectClass
*
klass
)
{
GfTypeQueryContextPrivate
*
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
GParamSpec
**
pspecs
=
NULL
;
guint
n_pspecs
=
0
,
p
=
0
;
pspecs
=
g_object_class_list_properties
(
klass
,
&
n_pspecs
);
for
(
p
=
0
;
p
<
n_pspecs
;
p
++
)
if
(
priv
->
query
->
param
)
priv
->
query
->
param
(
ctx
,
pspecs
[
p
],
priv
->
data
);
g_free
(
pspecs
);
}
static
inline
void
gf_type_query_context_real_signals
(
GfTypeQueryContext
*
ctx
,
GType
type
)
{
GfTypeQueryContextPrivate
*
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
guint
*
signal_ids
=
NULL
,
n_ids
=
0
,
s
=
0
;
signal_ids
=
g_signal_list_ids
(
type
,
&
n_ids
);
for
(
s
=
0
;
s
<
n_ids
;
s
++
)
{
GSignalQuery
query
;
g_signal_query
(
signal_ids
[
s
],
&
query
);
if
(
priv
->
query
->
signal
)
priv
->
query
->
signal
(
ctx
,
&
query
,
priv
->
data
);
}
g_free
(
signal_ids
);
}
static
inline
void
gf_type_query_context_real_query_object
(
GfTypeQueryContext
*
ctx
,
GType
type
)
{
GfTypeQueryContextPrivate
*
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
GObjectClass
*
klass
=
NULL
;
GTypePlugin
*
plugin
=
NULL
;
GTypeQuery
*
query
=
NULL
;
guint
t
=
0
;
/* handle the passed in type */
klass
=
g_type_class_ref
(
type
);
/* work around for glib bug 600505, refer to that at some point to see if
* this can be cleaned up.
*
* https://bugzilla.gnome.org/show_bug.cgi?id=600505
*/
query
=
g_new0
(
GTypeQuery
,
1
);
plugin
=
g_type_get_plugin
(
type
);
if
(
plugin
)
{
GTypeInfo
info
;
GTypeValueTable
table
;
/* we don't use table, but it needs to be there to shutup a runtime
* warning.
*/
g_type_plugin_complete_type_info
(
plugin
,
type
,
&
info
,
&
table
);
query
->
type
=
type
;
query
->
type_name
=
g_type_name
(
type
);
query
->
class_size
=
info
.
class_size
;
query
->
instance_size
=
info
.
instance_size
;
}
else
{
g_type_query
(
type
,
query
);
}
if
(
priv
->
query
->
start_object
)
priv
->
query
->
start_object
(
ctx
,
query
,
priv
->
data
);
/* if the query doesn't have a function for params signals don't bother
* with digging through them.
*/
if
(
priv
->
query
->
param
)
gf_type_query_context_real_params
(
ctx
,
klass
);
/* ditto for signals */
if
(
priv
->
query
->
signal
)
gf_type_query_context_real_signals
(
ctx
,
type
);
/* we're done with this object. finish it up before moving to it's
* children.
*/
if
(
priv
->
query
->
end_object
)
priv
->
query
->
end_object
(
ctx
,
query
,
priv
->
data
);
/* now dig through the children if we're recursive */
if
(
priv
->
recursive
)
{
GType
*
types
=
g_type_children
(
type
,
NULL
);
for
(
t
=
0
;
types
[
t
];
t
++
)
{
GObjectClass
*
child
=
NULL
;
child
=
g_type_class_ref
(
types
[
t
]);
gf_type_query_context_real_query_object
(
ctx
,
types
[
t
]);
g_type_class_unref
(
child
);
}
g_free
(
types
);
}
g_free
(
query
);
g_type_class_unref
(
klass
);
}
static
void
gf_type_query_context_real_query
(
GfTypeQueryContext
*
ctx
,
GType
type
)
{
gf_type_query_context_real_query_object
(
ctx
,
type
);
}
/******************************************************************************
* helpers
*****************************************************************************/
static
void
gf_type_query_context_set_query
(
GfTypeQueryContext
*
ctx
,
GfTypeQuery
*
query
)
{
GfTypeQueryContextPrivate
*
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
priv
->
query
=
query
;
}
static
void
gf_type_query_context_set_data
(
GfTypeQueryContext
*
ctx
,
gpointer
data
)
{
GfTypeQueryContextPrivate
*
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
priv
->
data
=
data
;
}
static
void
gf_type_query_context_set_destroy_notify
(
GfTypeQueryContext
*
ctx
,
GDestroyNotify
destroy_notify
)
{
GfTypeQueryContextPrivate
*
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
priv
->
destroy_notify
=
destroy_notify
;
}
/******************************************************************************
* object stuff
*****************************************************************************/
static
void
gf_type_query_context_get_property
(
GObject
*
obj
,
guint
param_id
,
GValue
*
value
,
GParamSpec
*
pspec
)
{
GfTypeQueryContext
*
ctx
=
GF_TYPE_QUERY_CONTEXT
(
obj
);
switch
(
param_id
)
{
case
PROP_QUERY
:
g_value_set_pointer
(
value
,
gf_type_query_context_get_query
(
ctx
));
break
;
case
PROP_RECURSIVE
:
g_value_set_boolean
(
value
,
gf_type_query_context_is_recursive
(
ctx
));
break
;
case
PROP_DATA
:
g_value_set_pointer
(
value
,
gf_type_query_context_get_user_data
(
ctx
));
break
;
case
PROP_DESTROY_NOTIFY
:
g_value_set_pointer
(
value
,
gf_type_query_context_get_destroy_notify
(
ctx
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
param_id
,
pspec
);
break
;
}
}
static
void
gf_type_query_context_set_property
(
GObject
*
obj
,
guint
param_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
)
{
GfTypeQueryContext
*
ctx
=
GF_TYPE_QUERY_CONTEXT
(
obj
);
switch
(
param_id
)
{
case
PROP_QUERY
:
gf_type_query_context_set_query
(
ctx
,
g_value_get_pointer
(
value
));
break
;
case
PROP_RECURSIVE
:
gf_type_query_context_set_recursive
(
ctx
,
g_value_get_boolean
(
value
));
break
;
case
PROP_DATA
:
gf_type_query_context_set_data
(
ctx
,
g_value_get_pointer
(
value
));
break
;
case
PROP_DESTROY_NOTIFY
:
gf_type_query_context_set_destroy_notify
(
ctx
,
(
GDestroyNotify
)
g_value_get_pointer
(
value
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
param_id
,
pspec
);
break
;
}
}
static
void
gf_type_query_context_finalize
(
GObject
*
obj
)
{
GfTypeQueryContextPrivate
*
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
obj
);
if
(
priv
->
destroy_notify
)
priv
->
destroy_notify
(
priv
->
data
);
G_OBJECT_CLASS
(
parent_class
)
->
finalize
(
obj
);
}
static
void
gf_type_query_context_class_init
(
GfTypeQueryContextClass
*
klass
)
{
GObjectClass
*
obj_class
=
G_OBJECT_CLASS
(
klass
);
parent_class
=
g_type_class_peek_parent
(
klass
);
g_type_class_add_private
(
klass
,
sizeof
(
GfTypeQueryContextPrivate
));
obj_class
->
get_property
=
gf_type_query_context_get_property
;
obj_class
->
set_property
=
gf_type_query_context_set_property
;
obj_class
->
finalize
=
gf_type_query_context_finalize
;
klass
->
query
=
gf_type_query_context_real_query
;
g_object_class_install_property
(
obj_class
,
PROP_QUERY
,
g_param_spec_pointer
(
"query"
,
P_
(
"query"
),
P_
(
"The GfTypeQuery to use."
),
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
));
g_object_class_install_property
(
obj_class
,
PROP_RECURSIVE
,
g_param_spec_boolean
(
"recursive"
,
P_
(
"recursive"
),
P_
(
"Whether or not to recurse into children"
),
TRUE
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT
));
g_object_class_install_property
(
obj_class
,
PROP_DATA
,
g_param_spec_pointer
(
"data"
,
P_
(
"data"
),
P_
(
"The user data to use while parsing."
),
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
));
g_object_class_install_property
(
obj_class
,
PROP_DESTROY_NOTIFY
,
g_param_spec_pointer
(
"destroy-notify"
,
P_
(
"destroy-notify"
),
P_
(
"The function to free the user data when the "
"context is freed."
),
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
));
}
/******************************************************************************
* API
*****************************************************************************/
GType
gf_type_query_context_get_type
(
void
)
{
static
GType
type
=
0
;
if
(
G_UNLIKELY
(
type
==
0
))
{
static
const
GTypeInfo
info
=
{
sizeof
(
GfTypeQueryContextClass
),
NULL
,
NULL
,
(
GClassInitFunc
)
gf_type_query_context_class_init
,
NULL
,
NULL
,
sizeof
(
GfTypeQueryContext
),
0
,
NULL
,
};
type
=
g_type_register_static
(
G_TYPE_OBJECT
,
"GfTypeQueryContext"
,
&
info
,
0
);
}
return
type
;
}
/**
* gf_type_query_context_new:
* @query: A #GfTypeQuery.
* @recursive: Whether or not to recurse into children.
* @data: user data to pass to the #GfTypeQuery functions.
* @destroy_notify: A function to free @data.
*
* Creates a new #GfTypeQueryContext using @query.
*
* Return Value: The new #GfTypeQueryContext.
*/
GfTypeQueryContext
*
gf_type_query_context_new
(
GfTypeQuery
*
query
,
gboolean
recursive
,
gpointer
data
,
GDestroyNotify
destroy_notify
)
{
g_return_val_if_fail
(
query
,
NULL
);
return
g_object_new
(
GF_TYPE_TYPE_QUERY_CONTEXT
,
"query"
,
query
,
"recursive"
,
recursive
,
"data"
,
data
,
"destroy-notify"
,
destroy_notify
,
NULL
);
}
/**
* gf_type_query_context_run:
* @ctx: The #GfTypeQueryContext instance.
* @type: The #GType to start the parsing at.
*
* Querys through all types descending from @type as well as @type itself.
*/
void
gf_type_query_context_run
(
GfTypeQueryContext
*
ctx
,
GType
type
)
{
GfTypeQueryContextClass
*
klass
=
NULL
;
g_return_if_fail
(
GF_IS_TYPE_QUERY_CONTEXT
(
ctx
));
g_return_if_fail
(
type
!=
G_TYPE_INVALID
);
klass
=
GF_TYPE_QUERY_CONTEXT_GET_CLASS
(
ctx
);
if
(
klass
&&
klass
->
query
)
klass
->
query
(
ctx
,
type
);
}
/**
* gf_type_query_context_get_query:
* @ctx: The #GfTypeQueryContext instance.
*
* Gets the #GfTypeQuery used in @ctx.
*
* Return Value: The #GfTypeQuery used in @ctx.
*/
GfTypeQuery
*
gf_type_query_context_get_query
(
const
GfTypeQueryContext
*
ctx
)
{
GfTypeQueryContextPrivate
*
priv
=
NULL
;
g_return_val_if_fail
(
GF_IS_TYPE_QUERY_CONTEXT
(
ctx
),
NULL
);
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
return
priv
->
query
;
}
/**
* gf_type_query_context_get_user_data:
* @ctx: The #GfTypeQueryContext instance.
*
* Gets the user data from @ctx.
*
* Return Value: The user data used from @ctx.
*/
gpointer
gf_type_query_context_get_user_data
(
const
GfTypeQueryContext
*
ctx
)
{
GfTypeQueryContextPrivate
*
priv
=
NULL
;
g_return_val_if_fail
(
GF_IS_TYPE_QUERY_CONTEXT
(
ctx
),
NULL
);
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
return
priv
->
data
;
}
/**
* gf_type_query_context_get_destroy_notify:
* @ctx: The #GfTypeQueryContext instance.
*
* Gets the destroy notify function from @ctx.
*
* Return Value: The destroy notify function from @ctx.
*/
GDestroyNotify
gf_type_query_context_get_destroy_notify
(
const
GfTypeQueryContext
*
ctx
)
{
GfTypeQueryContextPrivate
*
priv
=
NULL
;
g_return_val_if_fail
(
GF_IS_TYPE_QUERY_CONTEXT
(
ctx
),
NULL
);
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
return
priv
->
destroy_notify
;
}
/**
* gf_type_query_context_is_recursive:
* @ctx: The #GfTypeQueryContext instance.
*
* Gets whether or not @ctx will recurse into children.
*
* Return Value: TRUE if recursive, FALSE otherwise.
*/
gboolean
gf_type_query_context_is_recursive
(
const
GfTypeQueryContext
*
ctx
)
{
GfTypeQueryContextPrivate
*
priv
=
NULL
;
g_return_val_if_fail
(
GF_IS_TYPE_QUERY_CONTEXT
(
ctx
),
FALSE
);
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
return
priv
->
recursive
;
}
/**
* gf_type_query_context_set_recursive:
* @ctx: The #GfTypeQueryContext instance.
* @recursive: Whether or not to recurse into children.
*
* Set's whether or not @ctx will recurse into children.
*/
void
gf_type_query_context_set_recursive
(
GfTypeQueryContext
*
ctx
,
gboolean
recursive
)
{
GfTypeQueryContextPrivate
*
priv
=
NULL
;
g_return_if_fail
(
GF_IS_TYPE_QUERY_CONTEXT
(
ctx
));
priv
=
GF_TYPE_QUERY_CONTEXT_GET_PRIVATE
(
ctx
);
if
(
priv
->
recursive
!=
recursive
)
{
priv
->
recursive
=
recursive
;
g_object_notify
(
G_OBJECT
(
ctx
),
"recursive"
);
}
}
/******************************************************************************
* Builtin Queries
*****************************************************************************/
typedef
gboolean
(
*
GfTypeQueryBuiltInTest
)(
GType
type
,
gpointer
data
);
typedef
struct
{
GQueue
*
queue
;
GfTypeQueryBuiltInTest
test
;
gpointer
data
;
}
GfTypeQueryBuiltInData
;
static
void
gf_type_query_built_in_object_start
(
GfTypeQueryContext
*
ctx
,
const
GTypeQuery
*
query
,
gpointer
data
)
{
GfTypeQueryBuiltInData
*
built_in_data
=
(
GfTypeQueryBuiltInData
*
)
data
;
if
(
built_in_data
->
test
)
{
if
(
built_in_data
->
test
(
query
->
type
,
built_in_data
->
data
))
{
g_queue_push_tail
(
built_in_data
->
queue
,
GSIZE_TO_POINTER
(
query
->
type
));
}
}
else
{
g_queue_push_tail
(
built_in_data
->
queue
,
GSIZE_TO_POINTER
(
query
->
type
));
}
}
static
GfTypeQuery
built_in_query
=
{
gf_type_query_built_in_object_start
,
NULL
,
NULL
,
NULL
};
static
GType
*
gf_type_query_built_in_helper
(
GType
type
,
GfTypeQueryBuiltInTest
test
,
guint
*
n_children
,
gpointer
data
)
{
GfTypeQueryContext
*
ctx
=
NULL
;
GfTypeQueryBuiltInData
*
built_in_data
=
NULL
;
GQueue
*
queue
=
NULL
;
GType
*
types
=
NULL
;
GList
*
l
=
NULL
;
guint
i
=
0
;
queue
=
g_queue_new
();
built_in_data
=
g_new0
(
GfTypeQueryBuiltInData
,
1
);
built_in_data
->
queue
=
queue
;
built_in_data
->
test
=
test
;
built_in_data
->
data
=
data
;
ctx
=
gf_type_query_context_new
(
&
built_in_query
,
TRUE
,
built_in_data
,
g_free
);
gf_type_query_context_run
(
ctx
,
type
);
types
=
g_new0
(
GType
,
queue
->
length
+
1
);
for
(
i
=
0
,
l
=
queue
->
head
;
i
<
queue
->
length
;
i
++
,
l
=
l
->
next
)
types
[
i
]
=
GPOINTER_TO_SIZE
(
l
->
data
);
if
(
n_children
)
*
n_children
=
queue
->
length
;
/* clean up the queue and the query context. The queue context will kill
* the data when it is unrefed.
*/
g_queue_free
(
queue
);
g_object_unref
(
G_OBJECT
(
ctx
));
return
types
;
}
/******************************************************************************
* Built in tests
*****************************************************************************/
static
gboolean
gf_type_children_test_concrete
(
GType
type
,
gpointer
data
)
{
return
(
!
g_type_test_flags
(
type
,
G_TYPE_FLAG_ABSTRACT
));
}
static
gboolean
gf_type_interface_implementor
(
GType
type
,
gpointer
data
)
{
GType
interface
=
GPOINTER_TO_INT
(
data
);
return
g_type_is_a
(
type
,
interface
);
}
/******************************************************************************
* Introspection API
*****************************************************************************/
/**
* gf_type_children:
* @type : The #GType of the base class who's children we want.
* @n_children : Return address for the number of children or NULL.
*
* Returns a newly allocated array of #GType's for each child of @type.
*
* Note: Unlike #g_type_children, gf_type_children returns all subclasses,
* not just direct subclasses.
*
* Return Value: A newly allocated array of #GType's for each subclass which
* must be freed with #g_free().
*/
GType
*
gf_type_children
(
GType
type
,
guint
*
n_children
)
{
return
gf_type_query_built_in_helper
(
type
,
NULL
,
n_children
,
NULL
);
}
/**
* gf_type_concrete_children:
* @type : The #GType of the base class who's children we want.
* @n_children : Return address for the number of children, or NULL.
*
* This function is identical to #gf_type_children() except that it only
* returns concrete classes, that is non-abstract classes.
*
* Return Value: A newly allocated array of #GType's for each non-abstract
* subclass, which must be freed with #g_free().
*/
GType
*
gf_type_concrete_children
(
GType
type
,
guint
*
n_children
)
{
return
gf_type_query_built_in_helper
(
type
,
gf_type_children_test_concrete
,
n_children
,
NULL
);
}
/**
* gf_type_interface_implementors:
* @type : The #GType of the Interface.
* @n_children : Return address for the number of children, or @NULL.
*
* This function is identical to #gf_type_children() except that it only
* returns types that implement @type.
*
* Return Value: A newly allocated array of #GType's for each implementor
* of @type.
*/
GType
*
gf_type_interface_implementors
(
GType
type
,
guint
*
n_children
)
{
return
gf_type_query_built_in_helper
(
G_TYPE_OBJECT
,
gf_type_interface_implementor
,
n_children
,
GINT_TO_POINTER
(
type
));
}