src/events/SDL_events.c
changeset 7304 9598cbf46957
parent 7201 c6b3d3c32507
child 7305 d918643aee17
     1.1 --- a/src/events/SDL_events.c	Sun Jun 09 11:58:31 2013 +0200
     1.2 +++ b/src/events/SDL_events.c	Mon Jun 10 23:24:02 2013 -0700
     1.3 @@ -53,17 +53,30 @@
     1.4  static Uint32 SDL_userevents = SDL_USEREVENT;
     1.5  
     1.6  /* Private data -- event queue */
     1.7 -#define MAXEVENTS   128
     1.8 +typedef struct _SDL_EventEntry
     1.9 +{
    1.10 +    SDL_Event event;
    1.11 +    SDL_SysWMmsg msg;
    1.12 +    struct _SDL_EventEntry *prev;
    1.13 +    struct _SDL_EventEntry *next;
    1.14 +} SDL_EventEntry;
    1.15 +
    1.16 +typedef struct _SDL_SysWMEntry
    1.17 +{
    1.18 +    SDL_SysWMmsg msg;
    1.19 +    struct _SDL_SysWMEntry *next;
    1.20 +} SDL_SysWMEntry;
    1.21 +
    1.22  static struct
    1.23  {
    1.24      SDL_mutex *lock;
    1.25 -    int active;
    1.26 -    int head;
    1.27 -    int tail;
    1.28 -    SDL_Event event[MAXEVENTS];
    1.29 -    int wmmsg_next;
    1.30 -    struct SDL_SysWMmsg wmmsg[MAXEVENTS];
    1.31 -} SDL_EventQ = { NULL, 1 };
    1.32 +    volatile SDL_bool active;
    1.33 +    SDL_EventEntry *head;
    1.34 +    SDL_EventEntry *tail;
    1.35 +    SDL_EventEntry *free;
    1.36 +    SDL_SysWMEntry *wmmsg_used;
    1.37 +    SDL_SysWMEntry *wmmsg_free;
    1.38 +} SDL_EventQ = { NULL, SDL_TRUE };
    1.39  
    1.40  
    1.41  static __inline__ SDL_bool
    1.42 @@ -85,18 +98,41 @@
    1.43  SDL_StopEventLoop(void)
    1.44  {
    1.45      int i;
    1.46 -
    1.47 -    SDL_EventQ.active = 0;
    1.48 +    SDL_EventEntry *entry;
    1.49 +    SDL_SysWMEntry *wmmsg;
    1.50  
    1.51      if (SDL_EventQ.lock) {
    1.52 -        SDL_DestroyMutex(SDL_EventQ.lock);
    1.53 -        SDL_EventQ.lock = NULL;
    1.54 +        SDL_LockMutex(SDL_EventQ.lock);
    1.55      }
    1.56  
    1.57 +    SDL_EventQ.active = SDL_FALSE;
    1.58 +
    1.59      /* Clean out EventQ */
    1.60 -    SDL_EventQ.head = 0;
    1.61 -    SDL_EventQ.tail = 0;
    1.62 -    SDL_EventQ.wmmsg_next = 0;
    1.63 +    for (entry = SDL_EventQ.head; entry; ) {
    1.64 +        SDL_EventEntry *next = entry->next;
    1.65 +        SDL_free(entry);
    1.66 +        entry = next;
    1.67 +    }
    1.68 +    for (entry = SDL_EventQ.free; entry; ) {
    1.69 +        SDL_EventEntry *next = entry->next;
    1.70 +        SDL_free(entry);
    1.71 +        entry = next;
    1.72 +    }
    1.73 +    for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
    1.74 +        SDL_SysWMEntry *next = wmmsg->next;
    1.75 +        SDL_free(wmmsg);
    1.76 +        wmmsg = next;
    1.77 +    }
    1.78 +    for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
    1.79 +        SDL_SysWMEntry *next = wmmsg->next;
    1.80 +        SDL_free(wmmsg);
    1.81 +        wmmsg = next;
    1.82 +    }
    1.83 +    SDL_EventQ.head = NULL;
    1.84 +    SDL_EventQ.tail = NULL;
    1.85 +    SDL_EventQ.free = NULL;
    1.86 +    SDL_EventQ.wmmsg_used = NULL;
    1.87 +    SDL_EventQ.wmmsg_free = NULL;
    1.88  
    1.89      /* Clear disabled event state */
    1.90      for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
    1.91 @@ -112,6 +148,12 @@
    1.92          SDL_free(tmp);
    1.93      }
    1.94      SDL_EventOK = NULL;
    1.95 +
    1.96 +    if (SDL_EventQ.lock) {
    1.97 +        SDL_UnlockMutex(SDL_EventQ.lock);
    1.98 +        SDL_DestroyMutex(SDL_EventQ.lock);
    1.99 +        SDL_EventQ.lock = NULL;
   1.100 +    }
   1.101  }
   1.102  
   1.103  /* This function (and associated calls) may be called more than once */
   1.104 @@ -139,7 +181,7 @@
   1.105      SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
   1.106      SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
   1.107  
   1.108 -    SDL_EventQ.active = 1;
   1.109 +    SDL_EventQ.active = SDL_TRUE;
   1.110  
   1.111      return (0);
   1.112  }
   1.113 @@ -149,55 +191,61 @@
   1.114  static int
   1.115  SDL_AddEvent(SDL_Event * event)
   1.116  {
   1.117 -    int tail, added;
   1.118 +    SDL_EventEntry *entry;
   1.119  
   1.120 -    tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
   1.121 -    if (tail == SDL_EventQ.head) {
   1.122 -        /* Overflow, drop event */
   1.123 -        added = 0;
   1.124 +    if (SDL_EventQ.free == NULL) {
   1.125 +        entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
   1.126 +        if (!entry) {
   1.127 +            return 0;
   1.128 +        }
   1.129      } else {
   1.130 -        SDL_EventQ.event[SDL_EventQ.tail] = *event;
   1.131 -        if (event->type == SDL_SYSWMEVENT) {
   1.132 -            /* Note that it's possible to lose an event */
   1.133 -            int next = SDL_EventQ.wmmsg_next;
   1.134 -            SDL_EventQ.wmmsg[next] = *event->syswm.msg;
   1.135 -            SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
   1.136 -                &SDL_EventQ.wmmsg[next];
   1.137 -            SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
   1.138 -        }
   1.139 -        SDL_EventQ.tail = tail;
   1.140 -        added = 1;
   1.141 +        entry = SDL_EventQ.free;
   1.142 +        SDL_EventQ.free = entry->next;
   1.143 +    }
   1.144 +
   1.145 +    entry->event = *event;
   1.146 +    if (event->type == SDL_SYSWMEVENT) {
   1.147 +        entry->msg = *event->syswm.msg;
   1.148      }
   1.149 -    return (added);
   1.150 +
   1.151 +    if (SDL_EventQ.tail) {
   1.152 +        SDL_EventQ.tail->next = entry;
   1.153 +        entry->prev = SDL_EventQ.tail;
   1.154 +        SDL_EventQ.tail = entry;
   1.155 +        entry->next = NULL;
   1.156 +    } else {
   1.157 +        SDL_assert(!SDL_EventQ.head);
   1.158 +        SDL_EventQ.head = entry;
   1.159 +        SDL_EventQ.tail = entry;
   1.160 +        entry->prev = NULL;
   1.161 +        entry->next = NULL;
   1.162 +    }
   1.163 +
   1.164 +    return 1;
   1.165  }
   1.166  
   1.167 -/* Cut an event, and return the next valid spot, or the tail */
   1.168 -/*                           -- called with the queue locked */
   1.169 -static int
   1.170 -SDL_CutEvent(int spot)
   1.171 +/* Remove an event from the queue -- called with the queue locked */
   1.172 +static void
   1.173 +SDL_CutEvent(SDL_EventEntry *entry)
   1.174  {
   1.175 -    if (spot == SDL_EventQ.head) {
   1.176 -        SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
   1.177 -        return (SDL_EventQ.head);
   1.178 -    } else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
   1.179 -        SDL_EventQ.tail = spot;
   1.180 -        return (SDL_EventQ.tail);
   1.181 -    } else
   1.182 -        /* We cut the middle -- shift everything over */
   1.183 -    {
   1.184 -        int here, next;
   1.185 +    if (entry->prev) {
   1.186 +        entry->prev->next = entry->next;
   1.187 +    }
   1.188 +    if (entry->next) {
   1.189 +        entry->next->prev = entry->prev;
   1.190 +    }
   1.191  
   1.192 -        /* This can probably be optimized with SDL_memcpy() -- careful! */
   1.193 -        if (--SDL_EventQ.tail < 0) {
   1.194 -            SDL_EventQ.tail = MAXEVENTS - 1;
   1.195 -        }
   1.196 -        for (here = spot; here != SDL_EventQ.tail; here = next) {
   1.197 -            next = (here + 1) % MAXEVENTS;
   1.198 -            SDL_EventQ.event[here] = SDL_EventQ.event[next];
   1.199 -        }
   1.200 -        return (spot);
   1.201 +    if (entry == SDL_EventQ.head) {
   1.202 +        SDL_assert(entry->prev == NULL);
   1.203 +        SDL_EventQ.head = entry->next;
   1.204      }
   1.205 -    /* NOTREACHED */
   1.206 +    if (entry == SDL_EventQ.tail) {
   1.207 +        SDL_assert(entry->next == NULL);
   1.208 +        SDL_EventQ.tail = entry->prev;
   1.209 +    }
   1.210 +
   1.211 +    entry->next = SDL_EventQ.free;
   1.212 +    SDL_EventQ.free = entry;
   1.213  }
   1.214  
   1.215  /* Lock the event queue, take a peep at it, and unlock it */
   1.216 @@ -209,6 +257,10 @@
   1.217  
   1.218      /* Don't look after we've quit */
   1.219      if (!SDL_EventQ.active) {
   1.220 +        /* We get a few spurious events at shutdown, so don't warn then */
   1.221 +        if (action != SDL_ADDEVENT) {
   1.222 +            SDL_SetError("The event system has been shut down");
   1.223 +        }
   1.224          return (-1);
   1.225      }
   1.226      /* Lock the event queue */
   1.227 @@ -219,8 +271,10 @@
   1.228                  used += SDL_AddEvent(&events[i]);
   1.229              }
   1.230          } else {
   1.231 +            SDL_EventEntry *entry, *next;
   1.232 +            SDL_SysWMEntry *wmmsg, *wmmsg_next;
   1.233              SDL_Event tmpevent;
   1.234 -            int spot;
   1.235 +            Uint32 type;
   1.236  
   1.237              /* If 'events' is NULL, just see if they exist */
   1.238              if (events == NULL) {
   1.239 @@ -228,18 +282,44 @@
   1.240                  numevents = 1;
   1.241                  events = &tmpevent;
   1.242              }
   1.243 -            spot = SDL_EventQ.head;
   1.244 -            while ((used < numevents) && (spot != SDL_EventQ.tail)) {
   1.245 -                Uint32 type = SDL_EventQ.event[spot].type;
   1.246 +
   1.247 +            /* Clean out any used wmmsg data
   1.248 +               FIXME: Do we want to retain the data for some period of time?
   1.249 +             */
   1.250 +            for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
   1.251 +                wmmsg_next = wmmsg->next;
   1.252 +                wmmsg->next = SDL_EventQ.wmmsg_free;
   1.253 +                SDL_EventQ.wmmsg_free = wmmsg;
   1.254 +            }
   1.255 +            SDL_EventQ.wmmsg_used = NULL;
   1.256 +
   1.257 +            for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) {
   1.258 +                next = entry->next;
   1.259 +                type = entry->event.type;
   1.260                  if (minType <= type && type <= maxType) {
   1.261 -                    events[used++] = SDL_EventQ.event[spot];
   1.262 +                    events[used] = entry->event;
   1.263 +                    if (entry->event.type == SDL_SYSWMEVENT) {
   1.264 +                        /* We need to copy the wmmsg somewhere safe.
   1.265 +                           For now we'll guarantee it's valid at least until
   1.266 +                           the next call to SDL_PeepEvents()
   1.267 +                         */
   1.268 +                        SDL_SysWMEntry *wmmsg;
   1.269 +                        if (SDL_EventQ.wmmsg_free) {
   1.270 +                            wmmsg = SDL_EventQ.wmmsg_free;
   1.271 +                            SDL_EventQ.wmmsg_free = wmmsg->next;
   1.272 +                        } else {
   1.273 +                            wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
   1.274 +                        }
   1.275 +                        wmmsg->msg = *entry->event.syswm.msg;
   1.276 +                        wmmsg->next = SDL_EventQ.wmmsg_used;
   1.277 +                        SDL_EventQ.wmmsg_used = wmmsg;
   1.278 +                        events[used].syswm.msg = &wmmsg->msg;
   1.279 +                    }
   1.280 +                    ++used;
   1.281 +
   1.282                      if (action == SDL_GETEVENT) {
   1.283 -                        spot = SDL_CutEvent(spot);
   1.284 -                    } else {
   1.285 -                        spot = (spot + 1) % MAXEVENTS;
   1.286 +                        SDL_CutEvent(entry);
   1.287                      }
   1.288 -                } else {
   1.289 -                    spot = (spot + 1) % MAXEVENTS;
   1.290                  }
   1.291              }
   1.292          }
   1.293 @@ -286,13 +366,13 @@
   1.294  
   1.295      /* Lock the event queue */
   1.296      if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
   1.297 -        int spot = SDL_EventQ.head;
   1.298 -        while (spot != SDL_EventQ.tail) {
   1.299 -            Uint32 type = SDL_EventQ.event[spot].type;
   1.300 +        SDL_EventEntry *entry, *next;
   1.301 +        Uint32 type;
   1.302 +        for (entry = SDL_EventQ.head; entry; entry = next) {
   1.303 +            next = entry->next;
   1.304 +            type = entry->event.type;
   1.305              if (minType <= type && type <= maxType) {
   1.306 -                spot = SDL_CutEvent(spot);
   1.307 -            } else {
   1.308 -                spot = (spot + 1) % MAXEVENTS;
   1.309 +                SDL_CutEvent(entry);
   1.310              }
   1.311          }
   1.312          SDL_UnlockMutex(SDL_EventQ.lock);
   1.313 @@ -448,18 +528,15 @@
   1.314  SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   1.315  {
   1.316      if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
   1.317 -        int spot;
   1.318 -
   1.319 -        spot = SDL_EventQ.head;
   1.320 -        while (spot != SDL_EventQ.tail) {
   1.321 -            if (filter(userdata, &SDL_EventQ.event[spot])) {
   1.322 -                spot = (spot + 1) % MAXEVENTS;
   1.323 -            } else {
   1.324 -                spot = SDL_CutEvent(spot);
   1.325 +        SDL_EventEntry *entry, *next;
   1.326 +        for (entry = SDL_EventQ.head; entry; entry = next) {
   1.327 +            next = entry->next;
   1.328 +            if (!filter(userdata, &entry->event)) {
   1.329 +                SDL_CutEvent(entry);
   1.330              }
   1.331          }
   1.332 +        SDL_UnlockMutex(SDL_EventQ.lock);
   1.333      }
   1.334 -    SDL_UnlockMutex(SDL_EventQ.lock);
   1.335  }
   1.336  
   1.337  Uint8