1 | /* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
---|
2 | /* |
---|
3 | * Bonobo control object |
---|
4 | * |
---|
5 | * Author: |
---|
6 | * Nat Friedman (nat@helixcode.com) |
---|
7 | * Miguel de Icaza (miguel@helixcode.com) |
---|
8 | * Maciej Stachowiak (mjs@eazel.com) |
---|
9 | * |
---|
10 | * Copyright 1999, 2000 Helix Code, Inc. |
---|
11 | * 2000 Eazel, Inc. |
---|
12 | */ |
---|
13 | #include <config.h> |
---|
14 | #include <stdlib.h> |
---|
15 | #include <gtk/gtksignal.h> |
---|
16 | #include <gtk/gtkmarshal.h> |
---|
17 | #include <bonobo/bonobo-main.h> |
---|
18 | #include <bonobo/bonobo-plug.h> |
---|
19 | #include <bonobo/bonobo-control.h> |
---|
20 | #include <bonobo/bonobo-exception.h> |
---|
21 | #include <gdk/gdkprivate.h> |
---|
22 | #include <gtk/gtkbox.h> |
---|
23 | #include <gtk/gtkmain.h> |
---|
24 | |
---|
25 | #define PARENT_TYPE BONOBO_X_OBJECT_TYPE |
---|
26 | |
---|
27 | enum { |
---|
28 | SET_FRAME, |
---|
29 | ACTIVATE, |
---|
30 | LAST_SIGNAL |
---|
31 | }; |
---|
32 | |
---|
33 | static guint control_signals [LAST_SIGNAL]; |
---|
34 | |
---|
35 | /* Parent object class in GTK hierarchy */ |
---|
36 | static BonoboObjectClass *bonobo_control_parent_class; |
---|
37 | |
---|
38 | struct _BonoboControlPrivate { |
---|
39 | GtkWidget *widget; |
---|
40 | Bonobo_ControlFrame control_frame; |
---|
41 | gboolean active; |
---|
42 | |
---|
43 | GtkWidget *plug; |
---|
44 | GtkWidget *socket; |
---|
45 | gboolean is_local; |
---|
46 | gboolean xid_received; |
---|
47 | guint destroy_idle_id; |
---|
48 | |
---|
49 | BonoboUIComponent *ui_component; |
---|
50 | gboolean automerge; |
---|
51 | |
---|
52 | BonoboPropertyBag *propbag; |
---|
53 | }; |
---|
54 | |
---|
55 | /** |
---|
56 | * window_id_demangle: |
---|
57 | * @id: CORBA_char * |
---|
58 | * |
---|
59 | * De-mangle a window id string, |
---|
60 | * fields are separated by ':' character, |
---|
61 | * currently only the first field is used. |
---|
62 | * |
---|
63 | * Return value: the X11 window id. |
---|
64 | **/ |
---|
65 | inline static guint32 |
---|
66 | window_id_demangle (Bonobo_Control_windowId id) |
---|
67 | { |
---|
68 | guint32 x11_id; |
---|
69 | char **elements; |
---|
70 | |
---|
71 | /* printf ("ID string '%s'\n", id);*/ |
---|
72 | |
---|
73 | elements = g_strsplit (id, ":", -1); |
---|
74 | if (elements && elements [0]) |
---|
75 | x11_id = strtol (elements [0], NULL, 10); |
---|
76 | else { |
---|
77 | g_warning ("Serious X id mangling error"); |
---|
78 | x11_id = 0; |
---|
79 | } |
---|
80 | g_strfreev (elements); |
---|
81 | |
---|
82 | /* printf ("x11 : %d\n", x11_id);*/ |
---|
83 | |
---|
84 | return x11_id; |
---|
85 | } |
---|
86 | |
---|
87 | /** |
---|
88 | * bonobo_control_windowid_from_x11: |
---|
89 | * @x11_id: the x11 window id. |
---|
90 | * |
---|
91 | * This mangles the X11 name into the ':' delimited |
---|
92 | * string format "X-id: ..." |
---|
93 | * |
---|
94 | * Return value: the string; free after use. |
---|
95 | **/ |
---|
96 | Bonobo_Control_windowId |
---|
97 | bonobo_control_windowid_from_x11 (guint32 x11_id) |
---|
98 | { |
---|
99 | CORBA_char *str; |
---|
100 | |
---|
101 | str = g_strdup_printf ("%d", x11_id); |
---|
102 | |
---|
103 | /* printf ("Mangled %d to '%s'\n", x11_id, str);*/ |
---|
104 | return str; |
---|
105 | } |
---|
106 | |
---|
107 | /* |
---|
108 | * This callback is invoked when the plug is unexpectedly destroyed by |
---|
109 | * way of its associated X window dying. This usually indicates that |
---|
110 | * the container application has died. This callback is _not_ invoked |
---|
111 | * if the BonoboControl is destroyed normally, i.e. the user unrefs |
---|
112 | * the BonoboControl away. |
---|
113 | */ |
---|
114 | static gboolean |
---|
115 | bonobo_control_plug_destroy_event_cb (GtkWidget *plug, |
---|
116 | GdkEventAny *event, |
---|
117 | gpointer closure) |
---|
118 | { |
---|
119 | BonoboControl *control = BONOBO_CONTROL (closure); |
---|
120 | |
---|
121 | if (control->priv->plug == NULL) |
---|
122 | return FALSE; |
---|
123 | |
---|
124 | if (control->priv->plug != plug) |
---|
125 | g_warning ("Destroying incorrect plug!"); |
---|
126 | |
---|
127 | /* |
---|
128 | * Set the plug to NULL here so that we don't try to |
---|
129 | * destroy it later. It will get destroyed on its |
---|
130 | * own. |
---|
131 | */ |
---|
132 | control->priv->plug = NULL; |
---|
133 | |
---|
134 | /* |
---|
135 | * Destroy this plug's BonoboControl. |
---|
136 | */ |
---|
137 | bonobo_object_unref (BONOBO_OBJECT (control)); |
---|
138 | |
---|
139 | return FALSE; |
---|
140 | } |
---|
141 | |
---|
142 | /* |
---|
143 | * This callback is invoked when the plug is unexpectedly destroyed |
---|
144 | * through normal Gtk channels. FIXME FIXME FIXME |
---|
145 | * |
---|
146 | */ |
---|
147 | static void |
---|
148 | bonobo_control_plug_destroy_cb (GtkWidget *plug, |
---|
149 | gpointer closure) |
---|
150 | { |
---|
151 | BonoboControl *control = BONOBO_CONTROL (closure); |
---|
152 | |
---|
153 | if (control->priv->plug == NULL) |
---|
154 | return; |
---|
155 | |
---|
156 | if (control->priv->plug != plug) |
---|
157 | g_warning ("Destroying incorrect plug!"); |
---|
158 | |
---|
159 | /* |
---|
160 | * Set the plug to NULL here so that we don't try to |
---|
161 | * destroy it later. It will get destroyed on its |
---|
162 | * own. |
---|
163 | */ |
---|
164 | control->priv->plug = NULL; |
---|
165 | } |
---|
166 | |
---|
167 | |
---|
168 | static void |
---|
169 | bonobo_control_auto_merge (BonoboControl *control) |
---|
170 | { |
---|
171 | Bonobo_UIContainer remote_container; |
---|
172 | |
---|
173 | if (control->priv->ui_component == NULL) |
---|
174 | return; |
---|
175 | |
---|
176 | remote_container = bonobo_control_get_remote_ui_container (control); |
---|
177 | if (remote_container == CORBA_OBJECT_NIL) |
---|
178 | return; |
---|
179 | |
---|
180 | bonobo_ui_component_set_container ( |
---|
181 | control->priv->ui_component, remote_container); |
---|
182 | |
---|
183 | bonobo_object_release_unref (remote_container, NULL); |
---|
184 | } |
---|
185 | |
---|
186 | |
---|
187 | static void |
---|
188 | bonobo_control_auto_unmerge (BonoboControl *control) |
---|
189 | { |
---|
190 | if (control->priv->ui_component == NULL) |
---|
191 | return; |
---|
192 | |
---|
193 | bonobo_ui_component_unset_container (control->priv->ui_component); |
---|
194 | } |
---|
195 | |
---|
196 | static void |
---|
197 | impl_Bonobo_Control_activate (PortableServer_Servant servant, |
---|
198 | CORBA_boolean activated, |
---|
199 | CORBA_Environment *ev) |
---|
200 | { |
---|
201 | BonoboControl *control = BONOBO_CONTROL (bonobo_object_from_servant (servant)); |
---|
202 | |
---|
203 | if (control->priv->automerge && control->priv->active != activated) { |
---|
204 | if (activated) |
---|
205 | bonobo_control_auto_merge (control); |
---|
206 | else |
---|
207 | bonobo_control_auto_unmerge (control); |
---|
208 | } |
---|
209 | |
---|
210 | if (control->priv->active != activated) |
---|
211 | gtk_signal_emit (GTK_OBJECT (control), control_signals [ACTIVATE], (gboolean) activated); |
---|
212 | |
---|
213 | control->priv->active = activated; |
---|
214 | } |
---|
215 | |
---|
216 | |
---|
217 | static void |
---|
218 | impl_Bonobo_Control_setFrame (PortableServer_Servant servant, |
---|
219 | Bonobo_ControlFrame frame, |
---|
220 | CORBA_Environment *ev) |
---|
221 | { |
---|
222 | BonoboControl *control = BONOBO_CONTROL (bonobo_object_from_servant (servant)); |
---|
223 | |
---|
224 | bonobo_control_set_control_frame (control, frame); |
---|
225 | } |
---|
226 | |
---|
227 | |
---|
228 | static GtkWidget * |
---|
229 | bonobo_gtk_widget_from_x11_id (guint32 xid) |
---|
230 | { |
---|
231 | GdkWindow *window; |
---|
232 | gpointer data; |
---|
233 | |
---|
234 | window = gdk_window_lookup (xid); |
---|
235 | |
---|
236 | if (!window) |
---|
237 | return NULL; |
---|
238 | |
---|
239 | gdk_window_get_user_data(window, &data); |
---|
240 | |
---|
241 | if (!GTK_IS_WIDGET (data)) |
---|
242 | return NULL; |
---|
243 | else |
---|
244 | return GTK_WIDGET (data); |
---|
245 | } |
---|
246 | |
---|
247 | static gint |
---|
248 | idle_destroy_socket (gpointer data) |
---|
249 | { |
---|
250 | BonoboControl *control = BONOBO_CONTROL (data); |
---|
251 | |
---|
252 | g_return_val_if_fail (control != NULL, FALSE); |
---|
253 | |
---|
254 | control->priv->destroy_idle_id = 0; |
---|
255 | |
---|
256 | gtk_widget_destroy (control->priv->socket); |
---|
257 | |
---|
258 | return FALSE; |
---|
259 | } |
---|
260 | |
---|
261 | |
---|
262 | static void |
---|
263 | remove_destroy_idle (GtkWidget *socket, |
---|
264 | BonoboControl *control) |
---|
265 | { |
---|
266 | if (control->priv->destroy_idle_id != 0) |
---|
267 | gtk_idle_remove (control->priv->destroy_idle_id); |
---|
268 | |
---|
269 | control->priv->destroy_idle_id = 0; |
---|
270 | } |
---|
271 | |
---|
272 | static void |
---|
273 | impl_Bonobo_Control_setWindowId (PortableServer_Servant servant, |
---|
274 | Bonobo_Control_windowId id, |
---|
275 | CORBA_Environment *ev) |
---|
276 | { |
---|
277 | BonoboControl *control = BONOBO_CONTROL (bonobo_object_from_servant (servant)); |
---|
278 | GtkWidget *local_socket; |
---|
279 | guint32 x11_id; |
---|
280 | |
---|
281 | g_return_if_fail (control->priv->widget != NULL); |
---|
282 | |
---|
283 | x11_id = window_id_demangle (id); |
---|
284 | |
---|
285 | /* |
---|
286 | * Check to see if this XID is local to the application. In |
---|
287 | * that case, we bypass the GtkPlug/GtkSocket mechanism and |
---|
288 | * embed the control directly into the widget hierarchy. This |
---|
289 | * avoids a lot of the problems that Plug/Socket give us. |
---|
290 | */ |
---|
291 | local_socket = bonobo_gtk_widget_from_x11_id (x11_id); |
---|
292 | |
---|
293 | if (! local_socket) { |
---|
294 | GtkWidget *old_plug; |
---|
295 | |
---|
296 | old_plug = control->priv->plug; |
---|
297 | |
---|
298 | /* Create the new plug */ |
---|
299 | control->priv->plug = bonobo_plug_new (x11_id); |
---|
300 | |
---|
301 | gtk_signal_connect_while_alive (GTK_OBJECT (control->priv->plug), "destroy_event", |
---|
302 | GTK_SIGNAL_FUNC (bonobo_control_plug_destroy_event_cb), |
---|
303 | control, GTK_OBJECT (control)); |
---|
304 | gtk_signal_connect_while_alive (GTK_OBJECT (control->priv->plug), "destroy", |
---|
305 | GTK_SIGNAL_FUNC (bonobo_control_plug_destroy_cb), |
---|
306 | control, GTK_OBJECT (control)); |
---|
307 | |
---|
308 | /* |
---|
309 | * Put the control widget inside the plug. If we |
---|
310 | * already have a plug, then reparent the control into |
---|
311 | * the new plug. |
---|
312 | */ |
---|
313 | if (control->priv->xid_received) { |
---|
314 | |
---|
315 | if (old_plug != NULL) { |
---|
316 | gtk_object_unref (GTK_OBJECT (old_plug)); |
---|
317 | } |
---|
318 | |
---|
319 | gtk_widget_reparent (control->priv->widget, control->priv->plug); |
---|
320 | } else { |
---|
321 | gtk_container_add (GTK_CONTAINER (control->priv->plug), control->priv->widget); |
---|
322 | } |
---|
323 | |
---|
324 | gtk_widget_show (control->priv->plug); |
---|
325 | |
---|
326 | control->priv->is_local = FALSE; |
---|
327 | |
---|
328 | } else { |
---|
329 | GtkWidget *socket_parent; |
---|
330 | |
---|
331 | if (control->priv->xid_received) |
---|
332 | return; |
---|
333 | |
---|
334 | control->priv->is_local = TRUE; |
---|
335 | |
---|
336 | socket_parent = local_socket->parent; |
---|
337 | gtk_widget_hide (local_socket); |
---|
338 | |
---|
339 | control->priv->socket = local_socket; |
---|
340 | control->priv->destroy_idle_id = gtk_idle_add ( |
---|
341 | idle_destroy_socket, control); |
---|
342 | |
---|
343 | gtk_signal_connect_while_alive (GTK_OBJECT (local_socket), |
---|
344 | "destroy", |
---|
345 | remove_destroy_idle, |
---|
346 | control, GTK_OBJECT (control)); |
---|
347 | |
---|
348 | |
---|
349 | gtk_box_pack_end (GTK_BOX (socket_parent), |
---|
350 | control->priv->widget, |
---|
351 | TRUE, TRUE, 0); |
---|
352 | } |
---|
353 | |
---|
354 | control->priv->xid_received = TRUE; |
---|
355 | } |
---|
356 | |
---|
357 | static void |
---|
358 | impl_Bonobo_Control_setSize (PortableServer_Servant servant, |
---|
359 | const CORBA_short width, |
---|
360 | const CORBA_short height, |
---|
361 | CORBA_Environment *ev) |
---|
362 | { |
---|
363 | /* |
---|
364 | * Nothing. |
---|
365 | * |
---|
366 | * In the Gnome implementation of Bonobo, all size negotiation |
---|
367 | * is handled by GtkPlug/GtkSocket for us, or GtkFrame in the |
---|
368 | * local case. |
---|
369 | */ |
---|
370 | } |
---|
371 | |
---|
372 | static void |
---|
373 | impl_Bonobo_Control_getDesiredSize (PortableServer_Servant servant, |
---|
374 | CORBA_short *desired_width, |
---|
375 | CORBA_short *desired_height, |
---|
376 | CORBA_Environment *ev) |
---|
377 | { |
---|
378 | BonoboControl *control = BONOBO_CONTROL (bonobo_object_from_servant (servant)); |
---|
379 | GtkRequisition requisition; |
---|
380 | |
---|
381 | gtk_widget_size_request (control->priv->widget, &requisition); |
---|
382 | |
---|
383 | *desired_width = requisition.width; |
---|
384 | *desired_height = requisition.height; |
---|
385 | } |
---|
386 | |
---|
387 | static GtkStateType |
---|
388 | bonobo_control_gtk_state_from_corba (const Bonobo_Control_State state) |
---|
389 | { |
---|
390 | switch (state) { |
---|
391 | case Bonobo_Control_StateNormal: |
---|
392 | return GTK_STATE_NORMAL; |
---|
393 | |
---|
394 | case Bonobo_Control_StateActive: |
---|
395 | return GTK_STATE_ACTIVE; |
---|
396 | |
---|
397 | case Bonobo_Control_StatePrelight: |
---|
398 | return GTK_STATE_PRELIGHT; |
---|
399 | |
---|
400 | case Bonobo_Control_StateSelected: |
---|
401 | return GTK_STATE_SELECTED; |
---|
402 | |
---|
403 | case Bonobo_Control_StateInsensitive: |
---|
404 | return GTK_STATE_INSENSITIVE; |
---|
405 | |
---|
406 | default: |
---|
407 | g_warning ("bonobo_control_gtk_state_from_corba: Unknown state: %d", (gint) state); |
---|
408 | return GTK_STATE_NORMAL; |
---|
409 | } |
---|
410 | } |
---|
411 | |
---|
412 | static void |
---|
413 | impl_Bonobo_Control_setState (PortableServer_Servant servant, |
---|
414 | const Bonobo_Control_State state, |
---|
415 | CORBA_Environment *ev) |
---|
416 | { |
---|
417 | BonoboControl *control = BONOBO_CONTROL (bonobo_object_from_servant (servant)); |
---|
418 | GtkStateType gtk_state = bonobo_control_gtk_state_from_corba (state); |
---|
419 | |
---|
420 | g_return_if_fail (control->priv->widget != NULL); |
---|
421 | |
---|
422 | if (gtk_state == GTK_STATE_INSENSITIVE) |
---|
423 | gtk_widget_set_sensitive (control->priv->widget, FALSE); |
---|
424 | else { |
---|
425 | if (! GTK_WIDGET_SENSITIVE (control->priv->widget)) |
---|
426 | gtk_widget_set_sensitive (control->priv->widget, TRUE); |
---|
427 | |
---|
428 | gtk_widget_set_state (control->priv->widget, |
---|
429 | gtk_state); |
---|
430 | } |
---|
431 | } |
---|
432 | |
---|
433 | static Bonobo_PropertyBag |
---|
434 | impl_Bonobo_Control_getProperties (PortableServer_Servant servant, |
---|
435 | CORBA_Environment *ev) |
---|
436 | { |
---|
437 | BonoboControl *control = BONOBO_CONTROL (bonobo_object_from_servant (servant)); |
---|
438 | Bonobo_PropertyBag corba_propbag; |
---|
439 | |
---|
440 | if (control->priv->propbag == NULL) |
---|
441 | return CORBA_OBJECT_NIL; |
---|
442 | |
---|
443 | corba_propbag = BONOBO_OBJREF (control->priv->propbag); |
---|
444 | |
---|
445 | return bonobo_object_dup_ref (corba_propbag, ev); |
---|
446 | } |
---|
447 | |
---|
448 | static void |
---|
449 | process_events (PortableServer_Servant servant) |
---|
450 | { |
---|
451 | BonoboControl *control = |
---|
452 | BONOBO_CONTROL (bonobo_object_from_servant (servant)); |
---|
453 | |
---|
454 | g_return_if_fail (control != NULL); |
---|
455 | g_return_if_fail (control->priv != NULL); |
---|
456 | |
---|
457 | if (!control->priv->is_local) { |
---|
458 | while (gtk_events_pending ()) |
---|
459 | gtk_main_iteration (); |
---|
460 | gdk_flush (); |
---|
461 | } |
---|
462 | } |
---|
463 | |
---|
464 | static void |
---|
465 | impl_Bonobo_Control_realize (PortableServer_Servant servant, |
---|
466 | CORBA_Environment *ev) |
---|
467 | { |
---|
468 | process_events (servant); |
---|
469 | } |
---|
470 | |
---|
471 | static void |
---|
472 | impl_Bonobo_Control_unrealize (PortableServer_Servant servant, |
---|
473 | CORBA_Environment *ev) |
---|
474 | { |
---|
475 | process_events (servant); |
---|
476 | } |
---|
477 | |
---|
478 | static CORBA_boolean |
---|
479 | impl_Bonobo_Control_focusChild (PortableServer_Servant servant, |
---|
480 | Bonobo_Control_FocusDirection corba_direction, |
---|
481 | CORBA_Environment *ev) |
---|
482 | { |
---|
483 | BonoboControl *control; |
---|
484 | BonoboControlPrivate *priv; |
---|
485 | GtkDirectionType direction; |
---|
486 | |
---|
487 | control = BONOBO_CONTROL (bonobo_object_from_servant (servant)); |
---|
488 | priv = control->priv; |
---|
489 | |
---|
490 | if (!priv->plug) |
---|
491 | return FALSE; |
---|
492 | |
---|
493 | switch (corba_direction) { |
---|
494 | case Bonobo_Control_TAB_FORWARD: |
---|
495 | direction = GTK_DIR_TAB_FORWARD; |
---|
496 | break; |
---|
497 | |
---|
498 | case Bonobo_Control_TAB_BACKWARD: |
---|
499 | direction = GTK_DIR_TAB_BACKWARD; |
---|
500 | break; |
---|
501 | |
---|
502 | case Bonobo_Control_UP: |
---|
503 | direction = GTK_DIR_UP; |
---|
504 | break; |
---|
505 | |
---|
506 | case Bonobo_Control_DOWN: |
---|
507 | direction = GTK_DIR_DOWN; |
---|
508 | break; |
---|
509 | |
---|
510 | case Bonobo_Control_LEFT: |
---|
511 | direction = GTK_DIR_LEFT; |
---|
512 | break; |
---|
513 | |
---|
514 | case Bonobo_Control_RIGHT: |
---|
515 | direction = GTK_DIR_RIGHT; |
---|
516 | break; |
---|
517 | |
---|
518 | default: |
---|
519 | /* Hmmm, we should throw an exception. */ |
---|
520 | return FALSE; |
---|
521 | } |
---|
522 | |
---|
523 | bonobo_plug_clear_focus_chain (BONOBO_PLUG (priv->plug)); |
---|
524 | return gtk_container_focus (GTK_CONTAINER (priv->plug), direction); |
---|
525 | } |
---|
526 | |
---|
527 | BonoboControl * |
---|
528 | bonobo_control_construct (BonoboControl *control, |
---|
529 | GtkWidget *widget) |
---|
530 | { |
---|
531 | g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); |
---|
532 | g_return_val_if_fail (BONOBO_IS_CONTROL (control), NULL); |
---|
533 | |
---|
534 | /* |
---|
535 | * This sets up the X handler for Bonobo objects. We basically will |
---|
536 | * ignore X errors if our container dies (because X will kill the |
---|
537 | * windows of the container and our container without telling us). |
---|
538 | */ |
---|
539 | bonobo_setup_x_error_handler (); |
---|
540 | |
---|
541 | control->priv->widget = GTK_WIDGET (widget); |
---|
542 | gtk_object_ref (GTK_OBJECT (widget)); |
---|
543 | gtk_object_sink (GTK_OBJECT (widget)); |
---|
544 | |
---|
545 | control->priv->ui_component = NULL; |
---|
546 | control->priv->propbag = NULL; |
---|
547 | |
---|
548 | return control; |
---|
549 | } |
---|
550 | |
---|
551 | /** |
---|
552 | * bonobo_control_new: |
---|
553 | * @widget: a GTK widget that contains the control and will be passed to the |
---|
554 | * container process. |
---|
555 | * |
---|
556 | * This function creates a new BonoboControl object for @widget. |
---|
557 | * |
---|
558 | * Returns: a BonoboControl object that implements the Bonobo::Control CORBA |
---|
559 | * service that will transfer the @widget to the container process. |
---|
560 | */ |
---|
561 | BonoboControl * |
---|
562 | bonobo_control_new (GtkWidget *widget) |
---|
563 | { |
---|
564 | BonoboControl *control; |
---|
565 | |
---|
566 | g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); |
---|
567 | |
---|
568 | control = gtk_type_new (bonobo_control_get_type ()); |
---|
569 | |
---|
570 | return bonobo_control_construct (control, widget); |
---|
571 | } |
---|
572 | |
---|
573 | /** |
---|
574 | * bonobo_control_get_widget: |
---|
575 | * @control: a BonoboControl |
---|
576 | * |
---|
577 | * Returns the GtkWidget associated with a BonoboControl. |
---|
578 | * |
---|
579 | * Return value: the BonoboControl's widget |
---|
580 | **/ |
---|
581 | GtkWidget * |
---|
582 | bonobo_control_get_widget (BonoboControl *control) |
---|
583 | { |
---|
584 | g_return_val_if_fail (BONOBO_IS_CONTROL (control), NULL); |
---|
585 | |
---|
586 | return control->priv->widget; |
---|
587 | } |
---|
588 | |
---|
589 | /** |
---|
590 | * bonobo_control_set_automerge: |
---|
591 | * @control: A #BonoboControl. |
---|
592 | * @automerge: Whether or not menus and toolbars should be |
---|
593 | * automatically merged when the control is activated. |
---|
594 | * |
---|
595 | * Sets whether or not the control handles menu/toolbar merging |
---|
596 | * automatically. If automerge is on, the control will automatically |
---|
597 | * register its BonoboUIComponent with the remote BonoboUIContainer |
---|
598 | * when it is activated. |
---|
599 | */ |
---|
600 | void |
---|
601 | bonobo_control_set_automerge (BonoboControl *control, |
---|
602 | gboolean automerge) |
---|
603 | { |
---|
604 | g_return_if_fail (BONOBO_IS_CONTROL (control)); |
---|
605 | |
---|
606 | control->priv->automerge = automerge; |
---|
607 | |
---|
608 | if (automerge && !control->priv->ui_component) |
---|
609 | control->priv->ui_component = bonobo_ui_component_new_default (); |
---|
610 | } |
---|
611 | |
---|
612 | /** |
---|
613 | * bonobo_control_get_automerge: |
---|
614 | * @control: A #BonoboControl. |
---|
615 | * |
---|
616 | * Returns: Whether or not the control is set to automerge its |
---|
617 | * menus/toolbars. See bonobo_control_set_automerge(). |
---|
618 | */ |
---|
619 | gboolean |
---|
620 | bonobo_control_get_automerge (BonoboControl *control) |
---|
621 | { |
---|
622 | g_return_val_if_fail (BONOBO_IS_CONTROL (control), FALSE); |
---|
623 | |
---|
624 | return control->priv->automerge; |
---|
625 | } |
---|
626 | |
---|
627 | static void |
---|
628 | bonobo_control_destroy (GtkObject *object) |
---|
629 | { |
---|
630 | BonoboControl *control = BONOBO_CONTROL (object); |
---|
631 | CORBA_Environment ev; |
---|
632 | |
---|
633 | CORBA_exception_init (&ev); |
---|
634 | |
---|
635 | if (control->priv->destroy_idle_id != 0) { |
---|
636 | gtk_idle_remove (control->priv->destroy_idle_id); |
---|
637 | } |
---|
638 | control->priv->destroy_idle_id = 0; |
---|
639 | |
---|
640 | if (control->priv->propbag) |
---|
641 | bonobo_object_unref (BONOBO_OBJECT (control->priv->propbag)); |
---|
642 | control->priv->propbag = NULL; |
---|
643 | |
---|
644 | if (control->priv->control_frame != CORBA_OBJECT_NIL) { |
---|
645 | if (control->priv->active) |
---|
646 | Bonobo_ControlFrame_activated (control->priv->control_frame, |
---|
647 | FALSE, &ev); |
---|
648 | |
---|
649 | CORBA_Object_release (control->priv->control_frame, &ev); |
---|
650 | } |
---|
651 | |
---|
652 | CORBA_exception_free (&ev); |
---|
653 | |
---|
654 | /* |
---|
655 | * If we have a UIComponent, destroy it. |
---|
656 | */ |
---|
657 | if (control->priv->ui_component != NULL) { |
---|
658 | bonobo_ui_component_unset_container (control->priv->ui_component); |
---|
659 | bonobo_object_unref (BONOBO_OBJECT (control->priv->ui_component)); |
---|
660 | } |
---|
661 | |
---|
662 | GTK_OBJECT_CLASS (bonobo_control_parent_class)->destroy (object); |
---|
663 | } |
---|
664 | |
---|
665 | static void |
---|
666 | bonobo_control_finalize (GtkObject *object) |
---|
667 | { |
---|
668 | BonoboControl *control = BONOBO_CONTROL (object); |
---|
669 | |
---|
670 | /* |
---|
671 | * Destroy the control's top-level widget. |
---|
672 | */ |
---|
673 | if (control->priv->widget) |
---|
674 | gtk_object_unref (GTK_OBJECT (control->priv->widget)); |
---|
675 | |
---|
676 | /* |
---|
677 | * If the plug still exists, destroy it. The plug might not |
---|
678 | * exist in the case where the container application died, |
---|
679 | * taking the plug out with it, or the optimized local case |
---|
680 | * where the plug/socket mechanism was bypassed. In the |
---|
681 | * formaer case, plug_destroy_cb() would have been invoked, |
---|
682 | * and it would have triggered the destruction of the Control, |
---|
683 | * which is why we're here now. In the latter case, it's not |
---|
684 | * needed because there is no plug. |
---|
685 | */ |
---|
686 | if (control->priv->plug) { |
---|
687 | gtk_object_destroy (GTK_OBJECT (control->priv->plug)); |
---|
688 | control->priv->plug = NULL; |
---|
689 | } |
---|
690 | |
---|
691 | g_free (control->priv); |
---|
692 | |
---|
693 | GTK_OBJECT_CLASS (bonobo_control_parent_class)->finalize (object); |
---|
694 | } |
---|
695 | |
---|
696 | /** |
---|
697 | * bonobo_control_set_control_frame: |
---|
698 | * @control: A BonoboControl object. |
---|
699 | * @control_frame: A CORBA interface for the ControlFrame which contains this Controo. |
---|
700 | * |
---|
701 | * Sets the ControlFrame for @control to @control_frame. |
---|
702 | */ |
---|
703 | void |
---|
704 | bonobo_control_set_control_frame (BonoboControl *control, Bonobo_ControlFrame control_frame) |
---|
705 | { |
---|
706 | CORBA_Environment ev; |
---|
707 | |
---|
708 | g_return_if_fail (BONOBO_IS_CONTROL (control)); |
---|
709 | |
---|
710 | CORBA_exception_init (&ev); |
---|
711 | |
---|
712 | if (control->priv->control_frame != CORBA_OBJECT_NIL) |
---|
713 | CORBA_Object_release (control->priv->control_frame, &ev); |
---|
714 | |
---|
715 | if (control_frame == CORBA_OBJECT_NIL) |
---|
716 | control->priv->control_frame = CORBA_OBJECT_NIL; |
---|
717 | else |
---|
718 | control->priv->control_frame = CORBA_Object_duplicate (control_frame, &ev); |
---|
719 | |
---|
720 | CORBA_exception_free (&ev); |
---|
721 | |
---|
722 | gtk_signal_emit (GTK_OBJECT (control), control_signals [SET_FRAME]); |
---|
723 | } |
---|
724 | |
---|
725 | /** |
---|
726 | * bonobo_control_get_control_frame: |
---|
727 | * @control: A BonoboControl object whose Bonobo_ControlFrame CORBA interface is |
---|
728 | * being retrieved. |
---|
729 | * |
---|
730 | * Returns: The Bonobo_ControlFrame CORBA object associated with @control, this is |
---|
731 | * a CORBA_Object_duplicated object. You need to CORBA_Object_release it when you are |
---|
732 | * done with it. |
---|
733 | */ |
---|
734 | Bonobo_ControlFrame |
---|
735 | bonobo_control_get_control_frame (BonoboControl *control) |
---|
736 | { |
---|
737 | Bonobo_ControlFrame control_frame; |
---|
738 | CORBA_Environment ev; |
---|
739 | |
---|
740 | g_return_val_if_fail (BONOBO_IS_CONTROL (control), CORBA_OBJECT_NIL); |
---|
741 | |
---|
742 | CORBA_exception_init (&ev); |
---|
743 | control_frame = CORBA_Object_duplicate (control->priv->control_frame, &ev); |
---|
744 | CORBA_exception_free (&ev); |
---|
745 | |
---|
746 | return control_frame; |
---|
747 | } |
---|
748 | |
---|
749 | /** |
---|
750 | * bonobo_control_get_ui_component: |
---|
751 | * @control: The control |
---|
752 | * |
---|
753 | * Return value: the associated UI component |
---|
754 | **/ |
---|
755 | BonoboUIComponent * |
---|
756 | bonobo_control_get_ui_component (BonoboControl *control) |
---|
757 | { |
---|
758 | g_return_val_if_fail (BONOBO_IS_CONTROL (control), NULL); |
---|
759 | |
---|
760 | if (!control->priv->ui_component) |
---|
761 | control->priv->ui_component = bonobo_ui_component_new_default (); |
---|
762 | |
---|
763 | return control->priv->ui_component; |
---|
764 | } |
---|
765 | |
---|
766 | void |
---|
767 | bonobo_control_set_ui_component (BonoboControl *control, |
---|
768 | BonoboUIComponent *component) |
---|
769 | { |
---|
770 | g_return_if_fail (BONOBO_IS_CONTROL (control)); |
---|
771 | g_return_if_fail (BONOBO_IS_UI_COMPONENT (component)); |
---|
772 | |
---|
773 | if (control->priv->ui_component) |
---|
774 | bonobo_object_unref (BONOBO_OBJECT (control->priv->ui_component)); |
---|
775 | |
---|
776 | control->priv->ui_component = component; |
---|
777 | } |
---|
778 | |
---|
779 | /** |
---|
780 | * bonobo_control_set_properties: |
---|
781 | * @control: A #BonoboControl object. |
---|
782 | * @pb: A #BonoboPropertyBag. |
---|
783 | * |
---|
784 | * Binds @pb to @control. When a remote object queries @control |
---|
785 | * for its property bag, @pb will be used in the responses. |
---|
786 | */ |
---|
787 | void |
---|
788 | bonobo_control_set_properties (BonoboControl *control, BonoboPropertyBag *pb) |
---|
789 | { |
---|
790 | BonoboPropertyBag *old_bag; |
---|
791 | |
---|
792 | g_return_if_fail (BONOBO_IS_CONTROL (control)); |
---|
793 | g_return_if_fail (BONOBO_IS_PROPERTY_BAG (pb)); |
---|
794 | |
---|
795 | old_bag = control->priv->propbag; |
---|
796 | control->priv->propbag = pb; |
---|
797 | |
---|
798 | if (pb) |
---|
799 | bonobo_object_ref (BONOBO_OBJECT (pb)); |
---|
800 | |
---|
801 | if (old_bag) |
---|
802 | bonobo_object_unref (BONOBO_OBJECT (old_bag)); |
---|
803 | } |
---|
804 | |
---|
805 | /** |
---|
806 | * bonobo_control_get_properties: |
---|
807 | * @control: A #BonoboControl whose PropertyBag has already been set. |
---|
808 | * |
---|
809 | * Returns: The #BonoboPropertyBag bound to @control. |
---|
810 | */ |
---|
811 | BonoboPropertyBag * |
---|
812 | bonobo_control_get_properties (BonoboControl *control) |
---|
813 | { |
---|
814 | g_return_val_if_fail (BONOBO_IS_CONTROL (control), NULL); |
---|
815 | |
---|
816 | return control->priv->propbag; |
---|
817 | } |
---|
818 | |
---|
819 | /** |
---|
820 | * bonobo_control_get_ambient_properties: |
---|
821 | * @control: A #BonoboControl which is bound to a remote |
---|
822 | * #BonoboControlFrame. |
---|
823 | * @ev: CORBA exception environment. |
---|
824 | * |
---|
825 | * Returns: A #Bonobo_PropertyBag bound to the bag of ambient |
---|
826 | * properties associated with this #Control's #ControlFrame. |
---|
827 | */ |
---|
828 | Bonobo_PropertyBag |
---|
829 | bonobo_control_get_ambient_properties (BonoboControl *control, |
---|
830 | CORBA_Environment *ev) |
---|
831 | { |
---|
832 | Bonobo_ControlFrame control_frame; |
---|
833 | Bonobo_PropertyBag pbag; |
---|
834 | CORBA_Environment *real_ev, tmp_ev; |
---|
835 | |
---|
836 | g_return_val_if_fail (BONOBO_IS_CONTROL (control), NULL); |
---|
837 | |
---|
838 | control_frame = control->priv->control_frame; |
---|
839 | |
---|
840 | if (control_frame == CORBA_OBJECT_NIL) |
---|
841 | return NULL; |
---|
842 | |
---|
843 | if (ev) |
---|
844 | real_ev = ev; |
---|
845 | else { |
---|
846 | CORBA_exception_init (&tmp_ev); |
---|
847 | real_ev = &tmp_ev; |
---|
848 | } |
---|
849 | |
---|
850 | pbag = Bonobo_ControlFrame_getAmbientProperties ( |
---|
851 | control_frame, real_ev); |
---|
852 | |
---|
853 | if (BONOBO_EX (real_ev)) { |
---|
854 | if (!ev) |
---|
855 | CORBA_exception_free (&tmp_ev); |
---|
856 | pbag = CORBA_OBJECT_NIL; |
---|
857 | } |
---|
858 | |
---|
859 | return pbag; |
---|
860 | } |
---|
861 | |
---|
862 | /** |
---|
863 | * bonobo_control_get_remote_ui_container: |
---|
864 | * @control: A BonoboControl object which is associated with a remote |
---|
865 | * ControlFrame. |
---|
866 | * |
---|
867 | * Returns: The Bonobo_UIContainer CORBA server for the remote BonoboControlFrame. |
---|
868 | */ |
---|
869 | Bonobo_UIContainer |
---|
870 | bonobo_control_get_remote_ui_container (BonoboControl *control) |
---|
871 | { |
---|
872 | CORBA_Environment ev; |
---|
873 | Bonobo_UIContainer ui_container; |
---|
874 | |
---|
875 | g_return_val_if_fail (BONOBO_IS_CONTROL (control), CORBA_OBJECT_NIL); |
---|
876 | |
---|
877 | g_return_val_if_fail (control->priv->control_frame != CORBA_OBJECT_NIL, |
---|
878 | CORBA_OBJECT_NIL); |
---|
879 | |
---|
880 | CORBA_exception_init (&ev); |
---|
881 | |
---|
882 | ui_container = Bonobo_ControlFrame_getUIHandler (control->priv->control_frame, &ev); |
---|
883 | |
---|
884 | bonobo_object_check_env (BONOBO_OBJECT (control), control->priv->control_frame, &ev); |
---|
885 | |
---|
886 | CORBA_exception_free (&ev); |
---|
887 | |
---|
888 | return ui_container; |
---|
889 | } |
---|
890 | |
---|
891 | /** |
---|
892 | * bonobo_control_activate_notify: |
---|
893 | * @control: A #BonoboControl object which is bound |
---|
894 | * to a remote ControlFrame. |
---|
895 | * @activated: Whether or not @control has been activated. |
---|
896 | * |
---|
897 | * Notifies the remote ControlFrame which is associated with |
---|
898 | * @control that @control has been activated/deactivated. |
---|
899 | */ |
---|
900 | void |
---|
901 | bonobo_control_activate_notify (BonoboControl *control, |
---|
902 | gboolean activated) |
---|
903 | { |
---|
904 | CORBA_Environment ev; |
---|
905 | |
---|
906 | g_return_if_fail (BONOBO_IS_CONTROL (control)); |
---|
907 | g_return_if_fail (control->priv->control_frame != CORBA_OBJECT_NIL); |
---|
908 | |
---|
909 | CORBA_exception_init (&ev); |
---|
910 | |
---|
911 | Bonobo_ControlFrame_activated (control->priv->control_frame, activated, &ev); |
---|
912 | |
---|
913 | bonobo_object_check_env (BONOBO_OBJECT (control), control->priv->control_frame, &ev); |
---|
914 | |
---|
915 | CORBA_exception_free (&ev); |
---|
916 | } |
---|
917 | |
---|
918 | static void |
---|
919 | bonobo_control_class_init (BonoboControlClass *klass) |
---|
920 | { |
---|
921 | GtkObjectClass *object_class = (GtkObjectClass *)klass; |
---|
922 | POA_Bonobo_Control__epv *epv; |
---|
923 | |
---|
924 | bonobo_control_parent_class = gtk_type_class (PARENT_TYPE); |
---|
925 | |
---|
926 | control_signals [SET_FRAME] = |
---|
927 | gtk_signal_new ("set_frame", |
---|
928 | GTK_RUN_LAST, |
---|
929 | object_class->type, |
---|
930 | GTK_SIGNAL_OFFSET (BonoboControlClass, set_frame), |
---|
931 | gtk_marshal_NONE__NONE, |
---|
932 | GTK_TYPE_NONE, 0); |
---|
933 | |
---|
934 | control_signals [ACTIVATE] = |
---|
935 | gtk_signal_new ("activate", |
---|
936 | GTK_RUN_LAST, |
---|
937 | object_class->type, |
---|
938 | GTK_SIGNAL_OFFSET (BonoboControlClass, activate), |
---|
939 | gtk_marshal_NONE__BOOL, |
---|
940 | GTK_TYPE_NONE, 1, |
---|
941 | GTK_TYPE_BOOL); |
---|
942 | |
---|
943 | gtk_object_class_add_signals (object_class, control_signals, LAST_SIGNAL); |
---|
944 | |
---|
945 | object_class->destroy = bonobo_control_destroy; |
---|
946 | object_class->finalize = bonobo_control_finalize; |
---|
947 | |
---|
948 | epv = &klass->epv; |
---|
949 | |
---|
950 | epv->activate = impl_Bonobo_Control_activate; |
---|
951 | epv->setSize = impl_Bonobo_Control_setSize; |
---|
952 | epv->setWindowId = impl_Bonobo_Control_setWindowId; |
---|
953 | epv->setState = impl_Bonobo_Control_setState; |
---|
954 | epv->setFrame = impl_Bonobo_Control_setFrame; |
---|
955 | epv->getDesiredSize = impl_Bonobo_Control_getDesiredSize; |
---|
956 | epv->getProperties = impl_Bonobo_Control_getProperties; |
---|
957 | epv->realize = impl_Bonobo_Control_realize; |
---|
958 | epv->unrealize = impl_Bonobo_Control_unrealize; |
---|
959 | epv->focusChild = impl_Bonobo_Control_focusChild; |
---|
960 | } |
---|
961 | |
---|
962 | static void |
---|
963 | bonobo_control_init (BonoboControl *control) |
---|
964 | { |
---|
965 | control->priv = g_new0 (BonoboControlPrivate, 1); |
---|
966 | |
---|
967 | control->priv->control_frame = CORBA_OBJECT_NIL; |
---|
968 | } |
---|
969 | |
---|
970 | BONOBO_X_TYPE_FUNC_FULL (BonoboControl, |
---|
971 | Bonobo_Control, |
---|
972 | PARENT_TYPE, |
---|
973 | bonobo_control); |
---|
974 | |
---|
975 | void |
---|
976 | bonobo_control_set_property (BonoboControl *control, |
---|
977 | const char *first_prop, |
---|
978 | ...) |
---|
979 | { |
---|
980 | Bonobo_PropertyBag bag; |
---|
981 | char *err; |
---|
982 | CORBA_Environment ev; |
---|
983 | va_list args; |
---|
984 | |
---|
985 | g_return_if_fail (first_prop != NULL); |
---|
986 | g_return_if_fail (BONOBO_IS_CONTROL (control)); |
---|
987 | |
---|
988 | va_start (args, first_prop); |
---|
989 | |
---|
990 | CORBA_exception_init (&ev); |
---|
991 | |
---|
992 | bag = BONOBO_OBJREF (control->priv->propbag); |
---|
993 | |
---|
994 | if ((err = bonobo_property_bag_client_setv (bag, &ev, first_prop, args))) |
---|
995 | g_warning ("Error '%s'", err); |
---|
996 | |
---|
997 | CORBA_exception_free (&ev); |
---|
998 | |
---|
999 | va_end (args); |
---|
1000 | } |
---|
1001 | |
---|
1002 | void |
---|
1003 | bonobo_control_get_property (BonoboControl *control, |
---|
1004 | const char *first_prop, |
---|
1005 | ...) |
---|
1006 | { |
---|
1007 | Bonobo_PropertyBag bag; |
---|
1008 | char *err; |
---|
1009 | CORBA_Environment ev; |
---|
1010 | va_list args; |
---|
1011 | |
---|
1012 | g_return_if_fail (first_prop != NULL); |
---|
1013 | g_return_if_fail (BONOBO_IS_CONTROL (control)); |
---|
1014 | |
---|
1015 | va_start (args, first_prop); |
---|
1016 | |
---|
1017 | CORBA_exception_init (&ev); |
---|
1018 | |
---|
1019 | bag = BONOBO_OBJREF (control->priv->propbag); |
---|
1020 | |
---|
1021 | if ((err = bonobo_property_bag_client_getv (bag, &ev, first_prop, args))) |
---|
1022 | g_warning ("Error '%s'", err); |
---|
1023 | |
---|
1024 | CORBA_exception_free (&ev); |
---|
1025 | |
---|
1026 | va_end (args); |
---|
1027 | } |
---|