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