1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
#include "bonobo-application.h"
4
#include "bonobo-app-client.h"
5
#include <bonobo-exception.h>
6
#include "bonobo-marshal.h"
7
#include "bonobo-arg.h"
8
#include "bonobo-main.h"
9
#include "bonobo-i18n.h"
10
#include "bonobo-types.h"
25
static guint signals [LAST_SIGNAL] = { 0 };
28
BonoboAppHookFunc func;
36
} BonoboAppMessageDesc;
38
static GArray *bonobo_application_hooks = NULL;
41
* A pointer to our parent object class
43
static gpointer parent_class;
46
/* ------------ Forward function declarations ------------ */
47
static void bonobo_application_invoke_hooks (BonoboApplication *app);
50
static void bonobo_app_message_desc_free (BonoboAppMessageDesc *msgdesc)
53
g_closure_unref (msgdesc->closure);
59
_bonobo_application_message_accumulator(GSignalInvocationHint *ihint,
61
const GValue *handler_return,
66
null_gvalue = (G_VALUE_HOLDS (handler_return, G_TYPE_VALUE) &&
67
(g_value_peek_pointer (handler_return) == NULL));
70
g_value_copy (handler_return, return_accu);
71
return FALSE; /* stop emission */
73
return TRUE; /* continue emission */
79
bonobo_application_finalize (GObject *object)
81
BonoboApplication *self = BONOBO_APPLICATION (object);
83
if (self->message_list) {
84
g_slist_foreach (self->message_list, (GFunc) CORBA_free, NULL);
85
g_slist_free (self->message_list);
86
self->message_list = NULL;
94
if (self->closure_hash) {
95
g_hash_table_destroy (self->closure_hash);
96
self->closure_hash = NULL;
99
G_OBJECT_CLASS (parent_class)->finalize (object);
104
impl_Bonobo_Application_message (PortableServer_Servant servant,
105
const CORBA_char *msg,
106
const Bonobo_Application_ArgList *args,
107
CORBA_Environment *ev)
109
BonoboApplication *app = BONOBO_APPLICATION (bonobo_object (servant));
110
GValue *signal_return = NULL;
111
GValueArray *signal_args;
116
signal_args = g_value_array_new (args->_length);
117
memset (&value, 0, sizeof (value));
118
for (i = 0; i < args->_length; ++i) {
119
if (bonobo_arg_to_gvalue_alloc (&args->_buffer [i], &value)) {
120
g_value_array_append (signal_args, &value);
121
g_value_unset (&value);
123
g_warning ("Failed to convert type '%s' to GValue",
124
args->_buffer[i]._type->name);
128
g_signal_emit (app, signals [MESSAGE],
129
g_quark_from_string (msg),
130
msg, signal_args, &signal_return);
132
g_value_array_free (signal_args);
133
rv = CORBA_any__alloc ();
135
if (!bonobo_arg_from_gvalue_alloc (rv, signal_return)) {
136
g_warning ("Failed to convert type '%s' to CORBA::any",
137
g_type_name (G_VALUE_TYPE (signal_return)));
140
g_value_unset (signal_return);
141
g_free (signal_return);
149
* bonobo_application_new_instance:
150
* @app: a #BonoboApplication
151
* @argc: number of elements in @argv
152
* @argv: array of strings (command-line arguments)
154
* Emit the "new-instance" signal of the #BonoboApplication with the
157
* Return value: signal return value
159
gint bonobo_application_new_instance (BonoboApplication *app,
164
gchar **new_argv = g_new (gchar *, argc + 1);
166
memcpy (new_argv, argv, argc * sizeof(gchar *));
167
new_argv[argc] = NULL;
168
g_signal_emit (app, signals [NEW_INSTANCE], 0,
169
argc, new_argv, &rv);
175
bonobo_application_run_closures (BonoboApplication *self,
179
BonoboAppMessageDesc *desc;
181
desc = g_hash_table_lookup (self->closure_hash, name);
184
GValue *retval = g_new0 (GValue, 1);
185
GValue *params = g_newa (GValue, args->n_values + 1);
187
memset (params + 0, 0, sizeof (GValue));
188
g_value_init (params + 0, G_TYPE_OBJECT);
189
g_value_set_object (params + 0, self);
190
memcpy (params + 1, args->values, args->n_values * sizeof (GValue));
191
g_value_init (retval, desc->return_type);
192
g_closure_invoke (desc->closure, retval, args->n_values + 1,
193
params, NULL /* invocation_hint */);
194
g_value_unset (params + 0);
201
/* Handle the "new-instance" standard message */
203
bonobo_application_real_message (BonoboApplication *app,
207
return bonobo_application_run_closures (app, name, args);
212
impl_Bonobo_Application_newInstance (PortableServer_Servant servant,
213
Bonobo_Application_argv_t const *argv,
214
CORBA_Environment *ev)
216
BonoboApplication *app = BONOBO_APPLICATION (bonobo_object (servant));
219
retval = bonobo_application_new_instance
220
(app, argv->_length, argv->_buffer);
225
message_desc_copy (Bonobo_Application_MessageDesc *dest,
226
Bonobo_Application_MessageDesc *src)
228
dest->name = CORBA_string_dup (src->name);
229
dest->return_type = src->return_type;
230
dest->types._buffer = src->types._buffer;
231
dest->types._length = src->types._length;
232
dest->types._maximum = src->types._maximum;
233
dest->types._release = CORBA_FALSE;
234
dest->description = CORBA_string_dup (src->description);
238
static Bonobo_Application_MessageList *
239
impl_Bonobo_Application_listMessages (PortableServer_Servant servant,
240
CORBA_Environment *ev)
242
BonoboApplication *app = BONOBO_APPLICATION (bonobo_object (servant));
246
Bonobo_Application_MessageList *msglist;
248
nmessages = g_slist_length (app->message_list);
249
msglist = Bonobo_Application_MessageList__alloc ();
250
msglist->_length = msglist->_maximum = nmessages;
251
msglist->_buffer = Bonobo_Application_MessageList_allocbuf (nmessages);
252
for (l = app->message_list, i = 0; l; l = l->next, ++i)
253
message_desc_copy (&msglist->_buffer [i],
254
(Bonobo_Application_MessageDesc *) l->data);
255
CORBA_sequence_set_release (msglist, CORBA_TRUE);
260
impl_Bonobo_Application_getName (PortableServer_Servant servant,
261
CORBA_Environment *ev)
263
BonoboApplication *app = BONOBO_APPLICATION (bonobo_object (servant));
264
return CORBA_string_dup (app->name);
268
set_property (GObject *g_object,
273
BonoboApplication *self = (BonoboApplication *) g_object;
277
if (self->name) g_free (self->name);
278
self->name = g_strdup (g_value_get_string (value));
286
get_property (GObject *object,
291
BonoboApplication *self = (BonoboApplication *) object;
295
g_value_set_string (value, self->name);
298
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
304
bonobo_application_constructor (GType type,
305
guint n_construct_properties,
306
GObjectConstructParam *construct_properties)
309
BonoboApplication *self;
311
object = G_OBJECT_CLASS (parent_class)->constructor
312
(type, n_construct_properties, construct_properties);
313
self = BONOBO_APPLICATION (object);
314
bonobo_application_invoke_hooks (self);
319
bonobo_application_class_init (BonoboApplicationClass *klass)
321
GObjectClass *object_class = (GObjectClass *) klass;
322
POA_Bonobo_Application__epv *epv = &klass->epv;
324
parent_class = g_type_class_peek_parent (klass);
326
object_class->finalize = bonobo_application_finalize;
327
object_class->constructor = bonobo_application_constructor;
328
object_class->set_property = set_property;
329
object_class->get_property = get_property;
331
signals [MESSAGE] = g_signal_new (
332
"message", BONOBO_TYPE_APPLICATION,
333
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
334
G_STRUCT_OFFSET (BonoboApplicationClass, message),
335
_bonobo_application_message_accumulator, NULL,
336
bonobo_marshal_BOXED__STRING_BOXED,
337
G_TYPE_VALUE, 2, /* return_type, nparams */
338
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
341
signals [NEW_INSTANCE] = g_signal_new (
342
"new-instance", BONOBO_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
343
G_STRUCT_OFFSET (BonoboApplicationClass, new_instance),
344
NULL, NULL, /* accumulator and accumulator data */
345
bonobo_marshal_INT__INT_BOXED,
346
G_TYPE_INT, 2, /* return_type, nparams */
347
G_TYPE_INT, G_TYPE_STRV);
349
g_object_class_install_property
350
(object_class, PROP_NAME,
352
("name", _("Name"), _("Application unique name"), NULL,
353
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
355
klass->message = bonobo_application_real_message;
357
epv->message = impl_Bonobo_Application_message;
358
epv->listMessages = impl_Bonobo_Application_listMessages;
359
epv->newInstance = impl_Bonobo_Application_newInstance;
360
epv->getName = impl_Bonobo_Application_getName;
364
bonobo_application_init (BonoboApplication *self)
366
self->closure_hash = g_hash_table_new_full
367
(g_str_hash, g_str_equal,
368
g_free,(GDestroyNotify) bonobo_app_message_desc_free);
371
BONOBO_TYPE_FUNC_FULL (BonoboApplication,
378
* bonobo_application_new:
379
* @name: application name
381
* Creates a new #BonoboApplication object.
383
* Return value: a new #BonoboApplication
386
bonobo_application_new (const char *name)
389
BonoboApplication *app;
391
obj = g_object_new (BONOBO_TYPE_APPLICATION,
392
"poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_ALL_AT_IDLE),
395
app = (BonoboApplication *) obj;
399
static inline CORBA_TypeCode
400
_gtype_to_typecode (GType gtype)
402
static GHashTable *hash = NULL;
405
hash = g_hash_table_new (g_direct_hash, g_direct_equal);
406
#define mapping(gtype_, corba_type)\
407
g_hash_table_insert (hash, GUINT_TO_POINTER (gtype_), corba_type);
409
mapping (G_TYPE_NONE, TC_void);
410
mapping (G_TYPE_BOOLEAN, TC_CORBA_boolean);
411
mapping (G_TYPE_INT, TC_CORBA_long);
412
mapping (G_TYPE_UINT, TC_CORBA_unsigned_long);
413
mapping (G_TYPE_LONG, TC_CORBA_long);
414
mapping (G_TYPE_ULONG, TC_CORBA_unsigned_long);
415
mapping (G_TYPE_FLOAT, TC_CORBA_float);
416
mapping (G_TYPE_DOUBLE, TC_CORBA_double);
417
mapping (G_TYPE_STRING, TC_CORBA_string);
419
mapping (BONOBO_TYPE_CORBA_ANY, TC_CORBA_any);
422
return (CORBA_TypeCode) g_hash_table_lookup (hash, GUINT_TO_POINTER (G_TYPE_INT));
426
* bonobo_application_register_message_v:
427
* @app: a #BonoboApplication
428
* @name: message string identifier
429
* @description: a string containing a human readable description of the message
430
* @opt_closure: a #GClosure that will be called for this message, or %NULL;
431
* Function takes ownership of this closure.
432
* @return_type: Message return #GType.
433
* @arg_types: %G_TYPE_NONE -terminated vector of argument #GType's
435
* See bonobo_application_register_message().
438
bonobo_application_register_message_v (BonoboApplication *app,
440
const gchar *description,
441
GClosure *opt_closure,
443
GType const arg_types[])
445
Bonobo_Application_MessageDesc *msgdesc;
446
int i, arg_types_len;
448
for (arg_types_len = -1; arg_types[++arg_types_len] != G_TYPE_NONE;);
450
msgdesc = Bonobo_Application_MessageDesc__alloc ();
452
msgdesc->return_type = _gtype_to_typecode (return_type);
453
msgdesc->name = CORBA_string_dup (name);
454
msgdesc->description = CORBA_string_dup (description);
456
msgdesc->types._length = msgdesc->types._maximum = arg_types_len;
457
msgdesc->types._buffer =
458
CORBA_sequence_CORBA_TypeCode_allocbuf (arg_types_len);
460
for (i = 0; arg_types[i] != G_TYPE_NONE; ++i)
461
msgdesc->types._buffer[i] = _gtype_to_typecode (arg_types[i]);
463
app->message_list = g_slist_prepend (app->message_list, msgdesc);
466
BonoboAppMessageDesc *desc = g_new0 (BonoboAppMessageDesc, 1);
467
g_closure_ref (opt_closure);
468
g_closure_sink (opt_closure);
469
desc->closure = opt_closure;
470
desc->return_type = return_type;
471
g_hash_table_insert (app->closure_hash, g_strdup (name), desc);
477
* bonobo_application_register_message_va:
478
* @app: a #BonoboApplication
479
* @name: message string identifier
480
* @description: a string containing a human readable description of the message
481
* @opt_closure: a #GClosure that will be called for this message, or
482
* %NULL; Function takes ownership of this closure.
483
* @return_type: Message return #GType.
484
* @first_arg_type: #GType of first argument of message, or %G_TYPE_NONE
485
* @var_args: %G_TYPE_NONE -terminated valist of argument #GType's
487
* See bonobo_application_register_message().
490
bonobo_application_register_message_va (BonoboApplication *app,
492
const gchar *description,
493
GClosure *opt_closure,
495
GType first_arg_type,
501
arg_types = g_array_new (FALSE, FALSE, sizeof(GType));
502
if (first_arg_type != G_TYPE_NONE) {
503
g_array_append_val (arg_types, first_arg_type);
504
while ((gtype = va_arg (var_args, GType)) != G_TYPE_NONE)
505
g_array_append_val (arg_types, gtype);
507
gtype = G_TYPE_NONE; g_array_append_val (arg_types, gtype);
509
bonobo_application_register_message_v (app, name, description,
510
opt_closure, return_type,
511
(const GType *) arg_types->data);
513
g_array_free (arg_types, TRUE);
517
* bonobo_application_register_message:
518
* @app: a #BonoboApplication
519
* @name: message string identifier
520
* @description: a string containing a human readable description of the message
521
* @opt_closure: a #GClosure that will be called for this message, or
522
* %NULL; Function takes ownership of this closure.
523
* @return_type: Message return #GType.
524
* @first_arg_type: #GType of first argument of message, or %G_TYPE_NONE.
525
* @...: %G_TYPE_NONE -terminated list of argument #GType's
527
* Registers a new message type that the application supports.
530
bonobo_application_register_message (BonoboApplication *app,
532
const gchar *description,
533
GClosure *opt_closure,
535
GType first_arg_type,
540
va_start (var_args, first_arg_type);
541
bonobo_application_register_message_va (app, name, description,
542
opt_closure, return_type,
543
first_arg_type, var_args);
549
* bonobo_application_create_serverinfo:
550
* @app: a #BonoboApplication
551
* @envp: %NULL-terminated string vector, containing the enviroment
552
* variables we wish to include in the server description.
554
* This utility function provides a simple way to contruct a valid
555
* serverinfo XML string.
557
* Return value: a newly allocated string; caller must g_free() it.
560
bonobo_application_create_serverinfo (BonoboApplication *app,
563
GString *description;
567
description = g_string_new ("<oaf_info>\n");
568
g_string_append_printf (description,
569
" <oaf_server iid=\"OAFIID:%s\" location=\"unknown\" type=\"runtime\">\n"
570
" <oaf_attribute name=\"repo_ids\" type=\"stringv\">\n"
571
" <item value=\"IDL:Bonobo/Unknown:1.0\"/>\n"
572
" <item value=\"IDL:Bonobo/Application:1.0\"/>\n"
573
" </oaf_attribute>\n"
574
" <oaf_attribute name=\"name\" type=\"string\" value=\"%s\"/>\n"
575
" <oaf_attribute name=\"description\" type=\"string\" "
576
" value=\"%s application instance\"/>\n",
577
app->name, app->name, app->name);
579
if (envp && envp[0]) {
580
g_string_append (description, " <oaf_attribute name="
581
"\"bonobo:environment\" type=\"stringv\">\n");
582
for (i = 0; envp[i]; ++i)
583
g_string_append_printf (description,
584
" <item value=\"%s\"/>\n",
586
g_string_append (description, " </oaf_attribute>");
588
g_string_append (description,
591
rv = description->str;
592
g_string_free (description, FALSE);
597
* bonobo_application_register_unique:
598
* @app: a #BonoboApplication instance
599
* @serverinfo: the XML server
600
* description. bonobo_application_create_server_description() may be
601
* used to easily create such description.
602
* @client: output parameter that will contain a client object, in
603
* case another instance has already running, or %NULL if we are the
606
* Try to register the running application, or check for an existing
607
* application already registered and get a reference to it.
608
* Applications already running but on different environments (as
609
* defined by the bonobo:environenment server property) than this one
610
* are ignored and do not interfere.
612
* If the registration attempt indicates that another instance of this
613
* application is already running, then the output variable
614
* @client will receive a newly created #BonoboAppClient
615
* associated with the running application. Otherwise, *@client is
618
* Return value: the registration result.
619
* %Bonobo_ACTIVATION_REG_SUCCESS means the application was registered,
620
* since no other running instance was detected. If, however, a
621
* running application is detected,
622
* %Bonobo_ACTIVATION_REG_ALREADY_ACTIVE is returned.
624
Bonobo_RegistrationResult
625
bonobo_application_register_unique (BonoboApplication *app,
626
gchar const *serverinfo,
627
BonoboAppClient **client)
629
Bonobo_RegistrationResult reg_res;
631
CORBA_Object remote_obj = CORBA_OBJECT_NIL;
632
CORBA_Environment ev;
635
g_return_val_if_fail (app, Bonobo_ACTIVATION_REG_ERROR);
636
g_return_val_if_fail (BONOBO_IS_APPLICATION (app), Bonobo_ACTIVATION_REG_ERROR);
637
g_return_val_if_fail (serverinfo, Bonobo_ACTIVATION_REG_ERROR);
638
g_return_val_if_fail (client, Bonobo_ACTIVATION_REG_ERROR);
640
iid = g_strdup_printf ("OAFIID:%s", app->name);
644
reg_res = bonobo_activation_register_active_server_ext
645
(iid, bonobo_object_corba_objref (BONOBO_OBJECT (app)), NULL,
646
Bonobo_REGISTRATION_FLAG_NO_SERVERINFO, &remote_obj,
648
if (reg_res == Bonobo_ACTIVATION_REG_SUCCESS)
650
else if (reg_res == Bonobo_ACTIVATION_REG_ALREADY_ACTIVE) {
651
CORBA_exception_init (&ev);
652
Bonobo_Unknown_ref (remote_obj, &ev);
653
if (ev._major != CORBA_NO_EXCEPTION) {
654
/* Likely cause: server has quit, leaving a
655
* stale reference. Solution: keep trying
656
* to register as application server. */
657
CORBA_exception_free (&ev);
660
*client = bonobo_app_client_new ((Bonobo_Application) remote_obj);
670
* bonobo_application_add_hook:
671
* @func: hook function
674
* Add a hook function to be called whenever a new #BonoboApplication
675
* instance is created.
677
void bonobo_application_add_hook (BonoboAppHookFunc func, gpointer data)
681
if (bonobo_application_hooks == NULL)
682
bonobo_application_hooks = g_array_new (FALSE, FALSE, sizeof (BonoboAppHook));
686
g_array_append_val (bonobo_application_hooks, hook);
691
* bonobo_application_remove_hook:
692
* @func: hook function
695
* Removes a hook function previously set with bonobo_application_add_hook().
697
void bonobo_application_remove_hook (BonoboAppHookFunc func, gpointer data)
702
g_return_if_fail (bonobo_application_hooks);
704
for (i = 0; i < bonobo_application_hooks->len; ++i) {
705
hook = &g_array_index (bonobo_application_hooks, BonoboAppHook, i);
706
if (hook->func == func && hook->data == data) {
707
g_array_remove_index (bonobo_application_hooks, i);
712
g_warning ("bonobo_application_remove_hook: "
713
"(func, data) == (%p, %p) not found.", func, data);
718
bonobo_application_invoke_hooks (BonoboApplication *app)
723
if (!bonobo_application_hooks)
726
for (i = 0; i < bonobo_application_hooks->len; ++i) {
727
hook = &g_array_index (bonobo_application_hooks, BonoboAppHook, i);
728
hook->func (app, hook->data);