X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fdispatcher.cc;h=915e1eff0aa2db05e40b77499dafeaad2d5737b8;hb=9e781b7dc83b60a543ce218aa1a5f139f74c760f;hp=c2e777a131de776b42eda946f84d4ac7018da217;hpb=233fb6a8b3b6e31de1841641dbbd4c4f43423151;p=lilypond.git diff --git a/lily/dispatcher.cc b/lily/dispatcher.cc index c2e777a131..915e1eff0a 100644 --- a/lily/dispatcher.cc +++ b/lily/dispatcher.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 2005--2012 Erik Sandberg + Copyright (C) 2005--2014 Erik Sandberg LilyPond is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -71,6 +71,12 @@ Event dispatching: This is done by keeping a priority queue of listener lists, and iteratively send the event to the lowest-priority listener. - An event is never sent twice to listeners with equal priority. + The only case where listeners with equal priority may exist is when + two dispatchers are connected for more than one event type. In that + case, the respective listeners all have the same priority, making + sure that any event is only dispatched at most once for that + combination of dispatchers, even if it matches more than one event + type. */ IMPLEMENT_LISTENER (Dispatcher, dispatch); void @@ -96,7 +102,7 @@ Dispatcher::dispatch (SCM sev) listener list, and the lowest priority element is repeatedly extracted and called. - The priority queue is implemented as a bubble-sorted C + The priority queue is implemented as an insertion-sorted C array. Using the stack instead of native Scheme datastructures avoids overheads for memory allocation. The queue is usually small (around 2 elements), so the quadratic sorting time is not a @@ -115,7 +121,7 @@ Dispatcher::dispatch (SCM sev) num_classes--; else { - // bubblesort. + // insertion sort. int prio = scm_to_int (scm_caar (list)); int j; for (j = i; j > 0 && lists[j - 1].prio > prio; j--) @@ -181,9 +187,9 @@ Dispatcher::is_listened_class (SCM cl) static SCM accumulate_types (void * /* closure */, - SCM key, - SCM val, - SCM result) + SCM key, + SCM val, + SCM result) { if (scm_is_pair (val)) return scm_cons (key, result); @@ -203,6 +209,7 @@ Dispatcher::broadcast (Stream_event *ev) dispatch (ev->self_scm ()); } +// add_listener will always assign a new priority for each call void Dispatcher::add_listener (Listener l, SCM ev_class) { @@ -213,6 +220,14 @@ inline void Dispatcher::internal_add_listener (Listener l, SCM ev_class, int priority) { SCM list = scm_hashq_ref (listeners_, ev_class, SCM_EOL); + // if ev_class is not yet listened to, we go through our list of + // source dispatchers and register ourselves there with the priority + // we have reserved for this dispatcher. The priority system + // usually distributes events in the order events are registered. + // The reuse of a previous priority when registering another event + // for a dispatcher/dispatcher connection bypasses the normal + // ordering, but it is the mechanism by which duplicate broadcasts + // of the same event from one dispatcher to another are avoided. if (!scm_is_pair (list)) { /* Tell all dispatchers that we listen to, that we want to hear ev_class @@ -259,7 +274,7 @@ Dispatcher::remove_listener (Listener l, SCM ev_class) scm_hashq_set_x (listeners_, ev_class, list); if (first) - warning ("Attempting to remove nonexisting listener."); + warning (_ ("Attempting to remove nonexisting listener.")); else if (!scm_is_pair (list)) { /* Unregister with all dispatchers. */ @@ -276,12 +291,16 @@ Dispatcher::remove_listener (Listener l, SCM ev_class) void Dispatcher::register_as_listener (Dispatcher *disp) { + // We are creating and remembering the priority _we_ have with the + // foreign dispatcher. All events are dispatched with the same + // priority. The result is that, for example, a single event class + // will only trigger an event listener once. int priority = ++disp->priority_count_; // Don't register twice to the same dispatcher. if (scm_assq (disp->self_scm (), dispatchers_) != SCM_BOOL_F) { - warning ("Already listening to dispatcher, ignoring request"); + warning (_ ("Already listening to dispatcher, ignoring request")); return; }