gsignal.c revision 300e3bb247216fee40254822c2fb60a78a8ef21c
1/* GObject - GLib Type, Object, Parameter and Signal Library 2 * Copyright (C) 2000 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 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, write to the 16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 17 * Boston, MA 02111-1307, USA. 18 * 19 * this code is based on the original GtkSignal implementation 20 * for the Gtk+ library by Peter Mattis <petm@xcf.berkeley.edu> 21 */ 22#include "gsignal.h" 23 24#include "gbsearcharray.h" 25 26 27/* pre allocation configurations 28 */ 29#define BSA_PRE_ALLOC (20) 30#define HANDLER_PRE_ALLOC (48) 31#define EMISSION_PRE_ALLOC (16) 32 33#define TIGHT_MEMORY (1) 34 35#define REPORT_BUG "please report occourance circumstances to gtk-devel-list@gnome.org" 36 37 38/* --- generic allocation --- */ 39/* we can special case allocations generically by replacing 40 * these functions with more speed/memory aware variants 41 */ 42static inline gpointer 43g_generic_node_alloc (GTrashStack **trash_stack_p, 44 guint sizeof_node, 45 guint nodes_pre_alloc) 46{ 47 gpointer node = g_trash_stack_pop (trash_stack_p); 48 49 if (!node) 50 { 51 guint8 *block; 52 53 nodes_pre_alloc = MAX (nodes_pre_alloc, 1); 54 block = g_malloc (sizeof_node * nodes_pre_alloc); 55 while (--nodes_pre_alloc) 56 { 57 g_trash_stack_push (trash_stack_p, block); 58 block += sizeof_node; 59 } 60 node = block; 61 } 62 63 return node; 64} 65static inline void 66g_generic_node_free (GTrashStack **trash_stack_p, 67 gpointer node) 68{ 69 g_trash_stack_push (trash_stack_p, node); 70} 71 72 73/* --- typedefs --- */ 74typedef struct _SignalNode SignalNode; 75typedef struct _SignalKey SignalKey; 76typedef struct _Emission Emission; 77typedef struct _Handler Handler; 78typedef struct _HandlerList HandlerList; 79typedef enum 80{ 81 EMISSION_STOP, 82 EMISSION_RUN, 83 EMISSION_HOOK, 84 EMISSION_RESTART 85} EmissionState; 86 87 88/* --- prototypes --- */ 89static inline guint signal_id_lookup (GQuark quark, 90 GType itype); 91static void signal_destroy_R (SignalNode *signal_node); 92static inline HandlerList* handler_list_ensure (guint signal_id, 93 gpointer instance); 94static inline HandlerList* handler_list_lookup (guint signal_id, 95 gpointer instance); 96static inline Handler* handler_new (gboolean after); 97static void handler_insert (guint signal_id, 98 gpointer instance, 99 Handler *handler); 100static Handler* handler_lookup (gpointer instance, 101 guint handler_id, 102 guint *signal_id_p); 103static Handler* handler_find (gpointer instance, 104 GSignalMatchType mask, 105 guint signal_id, 106 GQuark detail, 107 GClosure *closure, 108 gpointer func, 109 gpointer data); 110static inline void handler_ref (Handler *handler); 111static inline void handler_unref_R (guint signal_id, 112 gpointer instance, 113 Handler *handler); 114static inline void emission_push (Emission **emission_list_p, 115 guint signal_id, 116 GQuark detail, 117 gpointer instance, 118 EmissionState *state_p); 119static inline void emission_pop (Emission **emission_list_p, 120 EmissionState *state_p); 121static inline Emission* emission_find (Emission *emission_list, 122 guint signal_id, 123 GQuark detail, 124 gpointer instance); 125static void signal_emit_R (SignalNode *node, 126 GQuark detail, 127 gpointer instance, 128 GValue *return_value, 129 const GValue *instance_and_params); 130 131 132/* --- structures --- */ 133struct _SignalNode 134{ 135 /* permanent portion */ 136 guint signal_id; 137 GType itype; 138 gchar *name; 139 guint destroyed : 1; 140 141 /* reinitializable portion */ 142 guint flags : 8; 143 guint n_params : 8; 144 GType *param_types; 145 GType return_type; 146 GClosure *class_closure; 147 GSignalAccumulator accumulator; 148 GSignalCMarshaller c_marshaller; 149 GHookList *emission_hooks; 150}; 151 152struct _SignalKey 153{ 154 GType itype; 155 GQuark quark; 156 guint signal_id; 157}; 158 159struct _Emission 160{ 161 Emission *next; 162 guint signal_id; 163 GQuark detail; 164 gpointer instance; 165 EmissionState *state_p; 166}; 167 168struct _HandlerList 169{ 170 guint signal_id; 171 Handler *handlers; 172}; 173 174struct _Handler 175{ 176 guint id; 177 Handler *next; 178 Handler *prev; 179 GQuark detail; 180 guint ref_count : 16; 181#define HANDLER_MAX_REF_COUNT (1 << 16) 182 guint block_count : 12; 183#define HANDLER_MAX_BLOCK_COUNT (1 << 12) 184 guint after : 1; 185 GClosure *closure; 186}; 187 188 189/* --- variables --- */ 190static GBSearchArray g_signal_key_bsa = { NULL, 0, 0, 0, NULL }; 191static GHashTable *g_handler_list_bsa_ht = NULL; 192static Emission *g_recursive_emissions = NULL; 193static Emission *g_restart_emissions = NULL; 194static GTrashStack *g_bsa_ts = NULL; 195static GTrashStack *g_handler_ts = NULL; 196static GTrashStack *g_emission_ts = NULL; 197G_LOCK_DEFINE_STATIC (g_signal_mutex); 198 199 200/* --- signal nodes --- */ 201static guint g_n_signal_nodes = 0; 202static SignalNode **g_signal_nodes = NULL; 203 204static inline SignalNode* 205LOOKUP_SIGNAL_NODE (register guint signal_id) 206{ 207 if (signal_id < g_n_signal_nodes) 208 return g_signal_nodes[signal_id]; 209 else 210 return NULL; 211} 212 213 214/* --- functions --- */ 215static inline guint 216signal_id_lookup (GQuark quark, 217 GType itype) 218{ 219 do 220 { 221 SignalKey key, *signal_key; 222 223 key.itype = itype; 224 key.quark = quark; 225 226 signal_key = g_bsearch_array_lookup (&g_signal_key_bsa, &key); 227 228 if (signal_key) 229 return signal_key->signal_id; 230 231 itype = g_type_parent (itype); 232 } 233 while (itype); 234 235 return 0; 236} 237 238static gint 239handler_lists_cmp (gconstpointer node1, 240 gconstpointer node2) 241{ 242 const HandlerList *hlist1 = node1, *hlist2 = node2; 243 244 return G_BSEARCH_ARRAY_CMP (hlist1->signal_id, hlist2->signal_id); 245} 246 247static inline HandlerList* 248handler_list_ensure (guint signal_id, 249 gpointer instance) 250{ 251 GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance); 252 HandlerList key; 253 254 if (!hlbsa) 255 { 256 hlbsa = g_generic_node_alloc (&g_bsa_ts, 257 sizeof (GBSearchArray), 258 BSA_PRE_ALLOC); 259 hlbsa->cmp_func = handler_lists_cmp; 260 hlbsa->sizeof_node = sizeof (HandlerList); 261 hlbsa->flags = G_BSEARCH_DEFER_SHRINK; 262 hlbsa->n_nodes = 0; 263 hlbsa->nodes = NULL; 264 g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa); 265 } 266 key.signal_id = signal_id; 267 key.handlers = NULL; 268 269 return g_bsearch_array_insert (hlbsa, &key, FALSE); 270} 271 272static inline HandlerList* 273handler_list_lookup (guint signal_id, 274 gpointer instance) 275{ 276 GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance); 277 HandlerList key; 278 279 key.signal_id = signal_id; 280 281 return hlbsa ? g_bsearch_array_lookup (hlbsa, &key) : NULL; 282} 283 284static Handler* 285handler_lookup (gpointer instance, 286 guint handler_id, 287 guint *signal_id_p) 288{ 289 GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance); 290 291 if (hlbsa) 292 { 293 guint i; 294 295 for (i = 0; i < hlbsa->n_nodes; i++) 296 { 297 HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i); 298 Handler *handler; 299 300 for (handler = hlist->handlers; handler; handler = handler->next) 301 if (handler->id == handler_id) 302 { 303 if (signal_id_p) 304 *signal_id_p = hlist->signal_id; 305 306 return handler; 307 } 308 } 309 } 310 311 return NULL; 312} 313 314static Handler* 315handler_find (gpointer instance, 316 GSignalMatchType mask, 317 guint signal_id, 318 GQuark detail, 319 GClosure *closure, 320 gpointer func, 321 gpointer data) 322{ 323 if (mask & G_SIGNAL_MATCH_ID) 324 { 325 HandlerList *hlist = handler_list_lookup (signal_id, instance); 326 Handler *handler; 327 SignalNode *node; 328 329 if (mask & G_SIGNAL_MATCH_FUNC) 330 { 331 node = LOOKUP_SIGNAL_NODE (signal_id); 332 if (!node || !node->c_marshaller) 333 return NULL; 334 } 335 336 mask = ~mask; 337 for (handler = hlist ? hlist->handlers : NULL; handler; handler = handler->next) 338 if (((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) && 339 ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) && 340 ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) && 341 ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) && 342 ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller && 343 handler->closure->meta_marshal == 0 && 344 ((GCClosure*) handler->closure)->callback == func))) 345 return handler; 346 } 347 else 348 { 349 GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance); 350 351 mask = ~mask; 352 if (hlbsa) 353 { 354 guint i; 355 356 for (i = 0; i < hlbsa->n_nodes; i++) 357 { 358 HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i); 359 SignalNode *node; 360 Handler *handler; 361 362 if (!(mask & G_SIGNAL_MATCH_FUNC)) 363 { 364 node = LOOKUP_SIGNAL_NODE (hlist->signal_id); 365 if (!node->c_marshaller) 366 continue; 367 } 368 369 for (handler = hlist->handlers; handler; handler = handler->next) 370 if (((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) && 371 ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) && 372 ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) && 373 ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) && 374 ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller && 375 handler->closure->meta_marshal == 0 && 376 ((GCClosure*) handler->closure)->callback == func))) 377 return handler; 378 } 379 } 380 } 381 382 return NULL; 383} 384 385static inline Handler* 386handler_new (gboolean after) 387{ 388 static guint handler_id = 1; 389 Handler *handler = g_generic_node_alloc (&g_handler_ts, 390 sizeof (Handler), 391 HANDLER_PRE_ALLOC); 392#ifndef G_DISABLE_CHECKS 393 if (handler_id == 0) 394 g_error (G_STRLOC ": handler id overflow, %s", REPORT_BUG); 395#endif 396 397 handler->id = handler_id++; 398 handler->prev = NULL; 399 handler->next = NULL; 400 handler->detail = 0; 401 handler->ref_count = 1; 402 handler->block_count = 0; 403 handler->after = after != FALSE; 404 handler->closure = NULL; 405 406 return handler; 407} 408 409static inline void 410handler_ref (Handler *handler) 411{ 412 g_return_if_fail (handler->ref_count > 0); 413 414#ifndef G_DISABLE_CHECKS 415 if (handler->ref_count >= HANDLER_MAX_REF_COUNT - 1) 416 g_error (G_STRLOC ": handler ref_count overflow, %s", REPORT_BUG); 417#endif 418 419 handler->ref_count += 1; 420} 421 422static inline void 423handler_unref_R (guint signal_id, 424 gpointer instance, 425 Handler *handler) 426{ 427 g_return_if_fail (handler->ref_count > 0); 428 429 handler->ref_count -= 1; 430 if (!handler->ref_count) 431 { 432 if (handler->next) 433 handler->next->prev = handler->prev; 434 if (handler->prev) /* watch out for g_signal_handlers_destroy()! */ 435 handler->prev->next = handler->next; 436 else 437 { 438 HandlerList *hlist = handler_list_lookup (signal_id, instance); 439 440 hlist->handlers = handler->next; 441 } 442 G_UNLOCK (g_signal_mutex); 443 g_closure_unref (handler->closure); 444 G_LOCK (g_signal_mutex); 445 g_generic_node_free (&g_handler_ts, handler); 446 } 447} 448 449static void 450handler_insert (guint signal_id, 451 gpointer instance, 452 Handler *handler) 453{ 454 HandlerList *hlist; 455 456 g_assert (handler->prev == NULL && handler->next == NULL); // FIXME: paranoid 457 458 hlist = handler_list_ensure (signal_id, instance); 459 if (!hlist->handlers) 460 hlist->handlers = handler; 461 else if (hlist->handlers->after && !handler->after) 462 { 463 handler->next = hlist->handlers; 464 hlist->handlers->prev = handler; 465 hlist->handlers = handler; 466 } 467 else 468 { 469 Handler *tmp = hlist->handlers; 470 471 if (handler->after) 472 while (tmp->next) 473 tmp = tmp->next; 474 else 475 while (tmp->next && !tmp->next->after) 476 tmp = tmp->next; 477 if (tmp->next) 478 tmp->next->prev = handler; 479 handler->next = tmp->next; 480 handler->prev = tmp; 481 tmp->next = handler; 482 } 483} 484 485static inline void 486emission_push (Emission **emission_list_p, 487 guint signal_id, 488 GQuark detail, 489 gpointer instance, 490 EmissionState *state_p) 491{ 492 Emission *emission = g_generic_node_alloc (&g_emission_ts, 493 sizeof (Emission), 494 EMISSION_PRE_ALLOC); 495 emission->next = *emission_list_p; 496 emission->signal_id = signal_id; 497 emission->detail = detail; 498 emission->instance = instance; 499 emission->state_p = state_p; 500 *emission_list_p = emission; 501} 502 503static inline void 504emission_pop (Emission **emission_list_p, 505 EmissionState *state_p) 506{ 507 Emission **loc = emission_list_p, *emission = *loc; 508 509 while (emission->state_p != state_p) 510 { 511 loc = &emission->next; 512 emission = *loc; 513 } 514 *loc = emission->next; 515 g_generic_node_free (&g_emission_ts, emission); 516} 517 518static inline Emission* 519emission_find (Emission *emission_list, 520 guint signal_id, 521 GQuark detail, 522 gpointer instance) 523{ 524 Emission *emission; 525 526 for (emission = emission_list; emission; emission = emission->next) 527 if (emission->instance == instance && 528 emission->signal_id == signal_id && 529 emission->detail == detail) 530 return emission; 531 return NULL; 532} 533 534static gint 535signal_key_cmp (gconstpointer node1, 536 gconstpointer node2) 537{ 538 const SignalKey *key1 = node1, *key2 = node2; 539 540 if (key1->itype == key2->itype) 541 return G_BSEARCH_ARRAY_CMP (key1->quark, key2->quark); 542 else 543 return G_BSEARCH_ARRAY_CMP (key1->itype, key2->itype); 544} 545 546void 547g_signal_init (void) /* sync with gtype.c */ 548{ 549 G_LOCK (g_signal_mutex); 550 if (!g_n_signal_nodes) 551 { 552 /* setup signal key array */ 553 g_signal_key_bsa.cmp_func = signal_key_cmp; 554 g_signal_key_bsa.sizeof_node = sizeof (SignalKey); 555 g_signal_key_bsa.flags = 0; /* alloc-only */ 556 557 /* setup handler list binary searchable array hash table (in german, that'd be one word ;) */ 558 g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL); 559 560 /* invalid (0) signal_id */ 561 g_n_signal_nodes = 1; 562 g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes); 563 g_signal_nodes[0] = NULL; 564 } 565 G_UNLOCK (g_signal_mutex); 566} 567 568void 569g_signals_destroy (GType itype) 570{ 571 guint i; 572 gboolean found_one = FALSE; 573 574 G_LOCK (g_signal_mutex); 575 for (i = 0; i < g_n_signal_nodes; i++) 576 { 577 SignalNode *node = g_signal_nodes[i]; 578 579 if (node->itype == itype) 580 { 581 if (node->destroyed) 582 g_warning (G_STRLOC ": signal \"%s\" of type `%s' already destroyed", 583 node->name, 584 g_type_name (node->itype)); 585 else 586 { 587 found_one = TRUE; 588 signal_destroy_R (node); 589 } 590 } 591 } 592 if (!found_one) 593 g_warning (G_STRLOC ": type `%s' has no signals that could be destroyed", 594 g_type_name (itype)); 595 G_UNLOCK (g_signal_mutex); 596} 597 598void 599g_signal_stop_emission (gpointer instance, 600 guint signal_id, 601 GQuark detail) 602{ 603 SignalNode *node; 604 605 g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); 606 g_return_if_fail (signal_id > 0); 607 608 G_LOCK (g_signal_mutex); 609 node = LOOKUP_SIGNAL_NODE (signal_id); 610 if (node && detail && !(node->flags & G_SIGNAL_DETAILED)) 611 { 612 g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); 613 G_UNLOCK (g_signal_mutex); 614 return; 615 } 616 if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype)) 617 { 618 Emission *emission_list = node->flags & G_SIGNAL_NO_RECURSE ? g_restart_emissions : g_recursive_emissions; 619 Emission *emission = emission_find (emission_list, signal_id, detail, instance); 620 621 if (emission) 622 { 623 if (*emission->state_p == EMISSION_HOOK) 624 g_warning (G_STRLOC ": emission of signal \"%s\" for instance `%p' cannot be stopped from emission hook", 625 node->name, instance); 626 else if (*emission->state_p == EMISSION_RUN) 627 *emission->state_p = EMISSION_STOP; 628 } 629 else 630 g_warning (G_STRLOC ": no emission of signal \"%s\" to stop for instance `%p'", 631 node->name, instance); 632 } 633 else 634 g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance); 635 G_UNLOCK (g_signal_mutex); 636} 637 638guint 639g_signal_lookup (const gchar *name, 640 GType itype) 641{ 642 guint signal_id; 643 644 g_return_val_if_fail (name != NULL, 0); 645 g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0); 646 647 G_LOCK (g_signal_mutex); 648 signal_id = signal_id_lookup (g_quark_try_string (name), itype); 649 G_UNLOCK (g_signal_mutex); 650 651 return signal_id; 652} 653 654gchar* 655g_signal_name (guint signal_id) 656{ 657 SignalNode *node; 658 gchar *name; 659 660 G_LOCK (g_signal_mutex); 661 node = LOOKUP_SIGNAL_NODE (signal_id); 662 name = node ? node->name : NULL; 663 G_UNLOCK (g_signal_mutex); 664 665 return name; 666} 667 668void 669g_signal_query (guint signal_id, 670 GSignalQuery *query) 671{ 672 SignalNode *node; 673 674 g_return_if_fail (query != NULL); 675 676 G_LOCK (g_signal_mutex); 677 node = LOOKUP_SIGNAL_NODE (signal_id); 678 if (!node || node->destroyed) 679 query->signal_id = 0; 680 else 681 { 682 query->signal_id = node->signal_id; 683 query->signal_name = node->name; 684 query->itype = node->itype; 685 query->signal_flags = node->flags; 686 query->return_type = node->return_type; 687 query->n_params = node->n_params; 688 query->param_types = node->param_types; 689 } 690 G_UNLOCK (g_signal_mutex); 691} 692 693/** 694 * gtk_signals_list: 695 * @itype: an 696 * @n_ids: location to store number of ids in @itype 697 * 698 * List all signals for a given type. 699 * 700 * Return value: Array 701 **/ 702guint * 703g_type_signals (GType itype, 704 guint *n_ids) 705{ 706 guint i; 707 SignalKey *keys; 708 guint n_nodes; 709 GArray *result; 710 711 g_return_val_if_fail (n_ids != NULL, NULL); 712 g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), NULL); 713 714 keys = g_signal_key_bsa.nodes; 715 n_nodes = g_signal_key_bsa.n_nodes; 716 result = g_array_new (FALSE, FALSE, sizeof (guint)); 717 718 for (i = 0; i < n_nodes; i++) 719 { 720 if (keys[i].itype == itype) 721 g_array_append_val (result, keys[i].signal_id); 722 } 723 724 *n_ids = result->len; 725 726 return (guint *) g_array_free (result, FALSE); 727} 728 729guint 730g_signal_newv (const gchar *signal_name, 731 GType itype, 732 GSignalFlags signal_flags, 733 GClosure *class_closure, 734 GSignalAccumulator accumulator, 735 GSignalCMarshaller c_marshaller, 736 GType return_type, 737 guint n_params, 738 GType *param_types) 739{ 740 gchar *name; 741 guint signal_id, i; 742 SignalNode *node; 743 744 g_return_val_if_fail (signal_name != NULL, 0); 745 g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0); 746 if (n_params) 747 g_return_val_if_fail (param_types != NULL, 0); 748 if (return_type != G_TYPE_NONE) 749 g_return_val_if_fail (accumulator == NULL, 0); 750 751 name = g_strdup (signal_name); 752 g_strdelimit (name, G_STR_DELIMITERS ":^", '_'); // FIXME do character checks like for types 753 754 G_LOCK (g_signal_mutex); 755 756 signal_id = signal_id_lookup (g_quark_try_string (name), itype); 757 node = LOOKUP_SIGNAL_NODE (signal_id); 758 if (node && !node->destroyed) 759 { 760 g_warning (G_STRLOC ": signal \"%s\" already exists in the `%s' %s", 761 name, 762 g_type_name (node->itype), 763 G_TYPE_IS_INTERFACE (node->itype) ? "interface" : "class ancestry"); 764 g_free (name); 765 G_UNLOCK (g_signal_mutex); 766 return 0; 767 } 768 if (node && node->itype != itype) 769 { 770 g_warning (G_STRLOC ": signal \"%s\" for type `%s' was previously created for type `%s'", 771 name, 772 g_type_name (itype), 773 g_type_name (node->itype)); 774 g_free (name); 775 G_UNLOCK (g_signal_mutex); 776 return 0; 777 } 778 for (i = 0; i < n_params; i++) 779 if (!G_TYPE_IS_VALUE (param_types[i]) || 780 param_types[i] == G_TYPE_ENUM || param_types[i] == G_TYPE_FLAGS) /* FIXME: kludge */ 781 { 782 g_warning (G_STRLOC ": parameter %d of type `%s' for signal \"%s::%s\" is not a value type", 783 i + 1, g_type_name (param_types[i]), g_type_name (itype), name); 784 g_free (name); 785 G_UNLOCK (g_signal_mutex); 786 return 0; 787 } 788 if (return_type != G_TYPE_NONE && !G_TYPE_IS_VALUE (return_type)) 789 { 790 g_warning (G_STRLOC ": return value of type `%s' for signal \"%s::%s\" is not a value type", 791 g_type_name (param_types[i]), g_type_name (itype), name); 792 g_free (name); 793 G_UNLOCK (g_signal_mutex); 794 return 0; 795 } 796 797 /* setup permanent portion of signal node */ 798 if (!node) 799 { 800 SignalKey key; 801 802 signal_id = g_n_signal_nodes++; 803 node = g_new (SignalNode, 1); 804 node->signal_id = signal_id; 805 g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes); 806 g_signal_nodes[signal_id] = node; 807 node->itype = itype; 808 node->name = name; 809 key.itype = itype; 810 key.quark = g_quark_from_string (node->name); 811 key.signal_id = signal_id; 812 g_bsearch_array_insert (&g_signal_key_bsa, &key, FALSE); 813 g_strdelimit (node->name, "_", '-'); 814 key.quark = g_quark_from_static_string (node->name); 815 g_bsearch_array_insert (&g_signal_key_bsa, &key, FALSE); 816 } 817 node->destroyed = FALSE; 818 819 /* setup reinitializable portion */ 820 node->flags = signal_flags & G_SIGNAL_FLAGS_MASK; 821 node->n_params = n_params; 822 node->param_types = g_memdup (param_types, sizeof (GType) * n_params); 823 node->return_type = return_type; 824 node->class_closure = class_closure ? g_closure_ref (class_closure) : NULL; 825 node->accumulator = accumulator; 826 node->c_marshaller = c_marshaller; 827 node->emission_hooks = NULL; 828 if (node->c_marshaller && class_closure && G_CLOSURE_NEEDS_MARSHAL (class_closure)) 829 g_closure_set_marshal (class_closure, node->c_marshaller); 830 831 G_UNLOCK (g_signal_mutex); 832 return signal_id; 833} 834 835static void 836signal_destroy_R (SignalNode *signal_node) 837{ 838 SignalNode node = *signal_node; 839 840 signal_node->destroyed = TRUE; 841 842 /* reentrancy caution, zero out real contents first */ 843 signal_node->n_params = 0; 844 signal_node->param_types = NULL; 845 signal_node->return_type = 0; 846 signal_node->class_closure = NULL; 847 signal_node->accumulator = NULL; 848 signal_node->c_marshaller = NULL; 849 signal_node->emission_hooks = NULL; 850 851#ifndef G_DISABLE_CHECKS 852 /* check current emissions */ 853 { 854 Emission *emission; 855 856 for (emission = (node.flags & G_SIGNAL_NO_RECURSE) ? g_restart_emissions : g_recursive_emissions; 857 emission; emission = emission->next) 858 if (emission->signal_id == node.signal_id) 859 g_critical (G_STRLOC ": signal \"%s\" being destroyed is currently in emission (instance `%p')", 860 node.name, emission->instance); 861 } 862#endif 863 864 /* free contents that need to 865 */ 866 G_UNLOCK (g_signal_mutex); 867 g_free (node.param_types); 868 g_closure_unref (node.class_closure); 869 if (node.emission_hooks) 870 { 871 g_hook_list_clear (node.emission_hooks); 872 g_free (node.emission_hooks); 873 } 874 G_LOCK (g_signal_mutex); 875} 876 877guint 878g_signal_connect_closure (gpointer instance, 879 guint signal_id, 880 GQuark detail, 881 GClosure *closure, 882 gboolean after) 883{ 884 SignalNode *node; 885 guint handler_id = 0; 886 887 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0); 888 g_return_val_if_fail (signal_id > 0, 0); 889 g_return_val_if_fail (closure != NULL, 0); 890 891 G_LOCK (g_signal_mutex); 892 node = LOOKUP_SIGNAL_NODE (signal_id); 893 if (node && detail && !(node->flags & G_SIGNAL_DETAILED)) 894 { 895 g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); 896 G_UNLOCK (g_signal_mutex); 897 return 0; 898 } 899 if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype)) 900 { 901 Handler *handler = handler_new (after); 902 903 handler_id = handler->id; 904 handler->detail = detail; 905 handler->closure = g_closure_ref (closure); 906 handler_insert (signal_id, instance, handler); 907 if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure)) 908 g_closure_set_marshal (closure, node->c_marshaller); 909 } 910 else 911 g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance); 912 G_UNLOCK (g_signal_mutex); 913 914 return handler_id; 915} 916 917void 918g_signal_handler_disconnect (gpointer instance, 919 guint handler_id) 920{ 921 Handler *handler; 922 guint signal_id; 923 924 g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); 925 g_return_if_fail (handler_id > 0); 926 927 G_LOCK (g_signal_mutex); 928 handler = handler_lookup (instance, handler_id, &signal_id); 929 if (handler) 930 { 931 handler->id = 0; 932 handler->block_count = 1; 933 handler_unref_R (signal_id, instance, handler); 934 } 935 else 936 g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id); 937 G_UNLOCK (g_signal_mutex); 938} 939 940void 941g_signal_handlers_destroy (gpointer instance) 942{ 943 GBSearchArray *hlbsa; 944 945 g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); 946 947 G_LOCK (g_signal_mutex); 948 hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance); 949 if (hlbsa) 950 { 951 guint i; 952 953 /* reentrancy caution, delete instance trace first */ 954 g_hash_table_remove (g_handler_list_bsa_ht, instance); 955 956 for (i = 0; i < hlbsa->n_nodes; i++) 957 { 958 HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i); 959 Handler *handler = hlist->handlers; 960 961 while (handler) 962 { 963 Handler *tmp = handler; 964 965 handler = tmp->next; 966 tmp->block_count = 1; 967 /* cruel unlink, this works because _all_ handlers vanish */ 968 tmp->next = NULL; 969 tmp->prev = tmp; 970 if (tmp->id) 971 { 972 tmp->id = 0; 973 handler_unref_R (0, NULL, tmp); 974 } 975 } 976 } 977 g_free (hlbsa->nodes); 978 g_generic_node_free (&g_bsa_ts, hlbsa); 979 } 980 G_UNLOCK (g_signal_mutex); 981} 982 983void 984g_signal_handler_block (gpointer instance, 985 guint handler_id) 986{ 987 Handler *handler; 988 989 g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); 990 g_return_if_fail (handler_id > 0); 991 992 G_LOCK (g_signal_mutex); 993 handler = handler_lookup (instance, handler_id, NULL); 994 if (handler) 995 { 996#ifndef G_DISABLE_CHECKS 997 if (handler->block_count >= HANDLER_MAX_BLOCK_COUNT - 1) 998 g_error (G_STRLOC ": handler block_count overflow, %s", REPORT_BUG); 999#endif 1000 1001 handler->block_count += 1; 1002 } 1003 else 1004 g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id); 1005 G_UNLOCK (g_signal_mutex); 1006} 1007 1008void 1009g_signal_handler_unblock (gpointer instance, 1010 guint handler_id) 1011{ 1012 Handler *handler; 1013 1014 g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); 1015 g_return_if_fail (handler_id > 0); 1016 1017 G_LOCK (g_signal_mutex); 1018 handler = handler_lookup (instance, handler_id, NULL); 1019 if (handler) 1020 { 1021 if (handler->block_count) 1022 handler->block_count -= 1; 1023 else 1024 g_warning (G_STRLOC ": handler `%u' of instance `%p' is not blocked", handler_id, instance); 1025 } 1026 else 1027 g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id); 1028 G_UNLOCK (g_signal_mutex); 1029} 1030 1031guint 1032g_signal_handler_find (gpointer instance, 1033 GSignalMatchType mask, 1034 guint signal_id, 1035 GQuark detail, 1036 GClosure *closure, 1037 gpointer func, 1038 gpointer data) 1039{ 1040 Handler *handler = NULL; 1041 guint handler_id; 1042 1043 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0); 1044 g_return_val_if_fail ((mask & ~G_SIGNAL_MATCH_MASK) == 0, 0); 1045 1046 G_LOCK (g_signal_mutex); 1047 handler = handler_find (instance, mask, signal_id, detail, closure, func, data); 1048 handler_id = handler ? handler->id : 0; 1049 G_UNLOCK (g_signal_mutex); 1050 1051 return handler_id; 1052} 1053 1054gboolean 1055g_signal_handler_pending (gpointer instance, 1056 guint signal_id, 1057 GQuark detail, 1058 gboolean may_be_blocked) 1059{ 1060 Handler *handler = NULL; 1061 1062 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE); 1063 g_return_val_if_fail (signal_id > 0, FALSE); 1064 1065 G_LOCK (g_signal_mutex); 1066 if (detail) 1067 { 1068 SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id); 1069 1070 if (!(node->flags & G_SIGNAL_DETAILED)) 1071 { 1072 g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); 1073 G_UNLOCK (g_signal_mutex); 1074 return FALSE; 1075 } 1076 } 1077 handler = handler_find (instance, 1078 (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | 1079 (may_be_blocked ? 0 : G_SIGNAL_MATCH_UNBLOCKED)), 1080 signal_id, detail, NULL, NULL, NULL); 1081 G_UNLOCK (g_signal_mutex); 1082 1083 return handler != NULL; 1084} 1085 1086void 1087g_signal_emitv (const GValue *instance_and_params, 1088 guint signal_id, 1089 GQuark detail, 1090 GValue *return_value) 1091{ 1092 SignalNode *node; 1093 gpointer instance; 1094 const GValue *param_values; 1095 guint i; 1096 1097 g_return_if_fail (instance_and_params != NULL); 1098 instance = g_value_get_as_pointer (instance_and_params); 1099 g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); 1100 g_return_if_fail (signal_id > 0); 1101 1102 param_values = instance_and_params + 1; 1103 1104 G_LOCK (g_signal_mutex); 1105 node = LOOKUP_SIGNAL_NODE (signal_id); 1106#ifndef G_DISABLE_CHECKS 1107 if (!node || !g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype)) 1108 g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance); 1109 if (detail && !(node->flags & G_SIGNAL_DETAILED)) 1110 { 1111 g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); 1112 G_UNLOCK (g_signal_mutex); 1113 return; 1114 } 1115 for (i = 0; i < node->n_params; i++) 1116 if (!G_VALUE_HOLDS (param_values + i, node->param_types[i])) 1117 { 1118 g_critical (G_STRLOC ": value for `%s' parameter %u for signal \"%s\" is of type `%s'", 1119 g_type_name (node->param_types[i]), 1120 i, 1121 node->name, 1122 G_VALUE_TYPE_NAME (param_values + i)); 1123 G_UNLOCK (g_signal_mutex); 1124 return; 1125 } 1126 if (node->return_type != G_TYPE_NONE) 1127 { 1128 if (!return_value) 1129 { 1130 g_critical (G_STRLOC ": return value `%s' for signal \"%s\" is (NULL)", 1131 g_type_name (node->return_type), 1132 node->name); 1133 G_UNLOCK (g_signal_mutex); 1134 return; 1135 } 1136 else if (!node->accumulator && !G_VALUE_HOLDS (return_value, node->return_type)) 1137 { 1138 g_critical (G_STRLOC ": return value `%s' for signal \"%s\" is of type `%s'", 1139 g_type_name (node->return_type), 1140 node->name, 1141 G_VALUE_TYPE_NAME (return_value)); 1142 G_UNLOCK (g_signal_mutex); 1143 return; 1144 } 1145 } 1146 else 1147 return_value = NULL; 1148#endif /* !G_DISABLE_CHECKS */ 1149 1150 signal_emit_R (node, detail, instance, return_value, instance_and_params); 1151 1152 G_UNLOCK (g_signal_mutex); 1153} 1154 1155static void 1156signal_emit_R (SignalNode *node, 1157 GQuark detail, 1158 gpointer instance, 1159 GValue *return_value, 1160 const GValue *instance_and_params) 1161{ 1162 EmissionState emission_state = 0; 1163 GSignalAccumulator accumulator; 1164 GSignalInvocationHint ihint; 1165 GClosure *class_closure; 1166 HandlerList *hlist; 1167 Handler *handler_list = NULL; 1168 GValue accu; 1169 gboolean accu_used = FALSE; 1170 guint signal_id = node->signal_id; 1171 1172 if (node->flags & G_SIGNAL_NO_RECURSE) 1173 { 1174 Emission *emission = emission_find (g_restart_emissions, signal_id, detail, instance); 1175 1176 if (emission) 1177 { 1178 *emission->state_p = EMISSION_RESTART; 1179 return; 1180 } 1181 } 1182 ihint.signal_id = node->signal_id; 1183 ihint.detail = detail; 1184 accumulator = node->accumulator; 1185 if (accumulator) 1186 { 1187 G_UNLOCK (g_signal_mutex); 1188 g_value_init (&accu, node->return_type); 1189 G_LOCK (g_signal_mutex); 1190 } 1191 emission_push ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions, 1192 signal_id, detail, instance, &emission_state); 1193 class_closure = node->class_closure; 1194 1195 EMIT_RESTART: 1196 1197 if (handler_list) 1198 handler_unref_R (signal_id, instance, handler_list); 1199 hlist = handler_list_lookup (signal_id, instance); 1200 handler_list = hlist ? hlist->handlers : NULL; 1201 if (handler_list) 1202 handler_ref (handler_list); 1203 1204 ihint.run_type = G_SIGNAL_RUN_FIRST; 1205 1206 if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure) 1207 { 1208 emission_state = EMISSION_RUN; 1209 1210 G_UNLOCK (g_signal_mutex); 1211 if (accumulator) 1212 { 1213 if (accu_used) 1214 g_value_reset (&accu); 1215 g_closure_invoke (class_closure, 1216 &accu, 1217 node->n_params + 1, 1218 instance_and_params, 1219 &ihint); 1220 if (!accumulator (&ihint, return_value, &accu) && 1221 emission_state == EMISSION_RUN) 1222 emission_state = EMISSION_STOP; 1223 accu_used = TRUE; 1224 } 1225 else 1226 g_closure_invoke (class_closure, 1227 return_value, 1228 node->n_params + 1, 1229 instance_and_params, 1230 &ihint); 1231 G_LOCK (g_signal_mutex); 1232 1233 if (emission_state == EMISSION_STOP) 1234 goto EMIT_CLEANUP; 1235 else if (emission_state == EMISSION_RESTART) 1236 goto EMIT_RESTART; 1237 } 1238 1239 if (node->emission_hooks) 1240 { 1241 emission_state = EMISSION_HOOK; 1242 1243 G_UNLOCK (g_signal_mutex); 1244 g_print ("emission_hooks()\n"); 1245 G_LOCK (g_signal_mutex); 1246 1247 if (emission_state == EMISSION_RESTART) 1248 goto EMIT_RESTART; 1249 } 1250 1251 if (handler_list) 1252 { 1253 Handler *handler = handler_list; 1254 1255 emission_state = EMISSION_RUN; 1256 handler_ref (handler); 1257 do 1258 { 1259 Handler *tmp; 1260 1261 if (handler->after) 1262 { 1263 handler_unref_R (signal_id, instance, handler_list); 1264 handler_list = handler; 1265 break; 1266 } 1267 else if (!handler->block_count && (!handler->detail || handler->detail == detail)) 1268 { 1269 G_UNLOCK (g_signal_mutex); 1270 if (accumulator) 1271 { 1272 if (accu_used) 1273 g_value_reset (&accu); 1274 g_closure_invoke (handler->closure, 1275 &accu, 1276 node->n_params + 1, 1277 instance_and_params, 1278 &ihint); 1279 if (!accumulator (&ihint, return_value, &accu) && 1280 emission_state == EMISSION_RUN) 1281 emission_state = EMISSION_STOP; 1282 accu_used = TRUE; 1283 } 1284 else 1285 g_closure_invoke (handler->closure, 1286 return_value, 1287 node->n_params + 1, 1288 instance_and_params, 1289 &ihint); 1290 G_LOCK (g_signal_mutex); 1291 1292 tmp = emission_state == EMISSION_RUN ? handler->next : NULL; 1293 } 1294 else 1295 tmp = handler->next; 1296 1297 if (tmp) 1298 handler_ref (tmp); 1299 handler_unref_R (signal_id, instance, handler_list); 1300 handler_list = handler; 1301 handler = tmp; 1302 } 1303 while (handler); 1304 1305 if (emission_state == EMISSION_STOP) 1306 goto EMIT_CLEANUP; 1307 else if (emission_state == EMISSION_RESTART) 1308 goto EMIT_RESTART; 1309 } 1310 1311 ihint.run_type = G_SIGNAL_RUN_LAST; 1312 1313 if ((node->flags & G_SIGNAL_RUN_LAST) && class_closure) 1314 { 1315 emission_state = EMISSION_RUN; 1316 1317 G_UNLOCK (g_signal_mutex); 1318 if (accumulator) 1319 { 1320 if (accu_used) 1321 g_value_reset (&accu); 1322 g_closure_invoke (class_closure, 1323 &accu, 1324 node->n_params + 1, 1325 instance_and_params, 1326 &ihint); 1327 if (!accumulator (&ihint, return_value, &accu) && 1328 emission_state == EMISSION_RUN) 1329 emission_state = EMISSION_STOP; 1330 accu_used = TRUE; 1331 } 1332 else 1333 g_closure_invoke (class_closure, 1334 return_value, 1335 node->n_params + 1, 1336 instance_and_params, 1337 &ihint); 1338 G_LOCK (g_signal_mutex); 1339 1340 if (emission_state == EMISSION_STOP) 1341 goto EMIT_CLEANUP; 1342 else if (emission_state == EMISSION_RESTART) 1343 goto EMIT_RESTART; 1344 } 1345 1346 if (handler_list) 1347 { 1348 Handler *handler = handler_list; 1349 1350 emission_state = EMISSION_RUN; 1351 handler_ref (handler); 1352 do 1353 { 1354 Handler *tmp; 1355 1356 if (handler->after && !handler->block_count && (!handler->detail || handler->detail == detail)) 1357 { 1358 G_UNLOCK (g_signal_mutex); 1359 if (accumulator) 1360 { 1361 if (accu_used) 1362 g_value_reset (&accu); 1363 g_closure_invoke (handler->closure, 1364 &accu, 1365 node->n_params + 1, 1366 instance_and_params, 1367 &ihint); 1368 if (!accumulator (&ihint, return_value, &accu) && 1369 emission_state == EMISSION_RUN) 1370 emission_state = EMISSION_STOP; 1371 accu_used = TRUE; 1372 } 1373 else 1374 g_closure_invoke (handler->closure, 1375 return_value, 1376 node->n_params + 1, 1377 instance_and_params, 1378 &ihint); 1379 G_LOCK (g_signal_mutex); 1380 1381 tmp = emission_state == EMISSION_RUN ? handler->next : NULL; 1382 } 1383 else 1384 tmp = handler->next; 1385 1386 if (tmp) 1387 handler_ref (tmp); 1388 handler_unref_R (signal_id, instance, handler); 1389 handler = tmp; 1390 } 1391 while (handler); 1392 1393 if (emission_state == EMISSION_STOP) 1394 goto EMIT_CLEANUP; 1395 else if (emission_state == EMISSION_RESTART) 1396 goto EMIT_RESTART; 1397 } 1398 1399 EMIT_CLEANUP: 1400 1401 ihint.run_type = G_SIGNAL_RUN_CLEANUP; 1402 1403 if ((node->flags & G_SIGNAL_RUN_CLEANUP) && class_closure) 1404 { 1405 gboolean need_unset = FALSE; 1406 1407 emission_state = EMISSION_STOP; 1408 1409 G_UNLOCK (g_signal_mutex); 1410 if (node->return_type != G_TYPE_NONE) 1411 { 1412 if (!accumulator) 1413 { 1414 g_value_init (&accu, node->return_type); 1415 need_unset = TRUE; 1416 } 1417 else if (accu_used) 1418 g_value_reset (&accu); 1419 } 1420 g_closure_invoke (class_closure, 1421 node->return_type != G_TYPE_NONE ? &accu : NULL, 1422 node->n_params + 1, 1423 instance_and_params, 1424 &ihint); 1425 if (need_unset) 1426 g_value_unset (&accu); 1427 G_LOCK (g_signal_mutex); 1428 1429 if (emission_state == EMISSION_RESTART) 1430 goto EMIT_RESTART; 1431 } 1432 1433 if (handler_list) 1434 handler_unref_R (signal_id, instance, handler_list); 1435 1436 emission_pop ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions, &emission_state); 1437 if (accumulator) 1438 { 1439 G_UNLOCK (g_signal_mutex); 1440 g_value_unset (&accu); 1441 G_LOCK (g_signal_mutex); 1442 } 1443} 1444