/* Iterates over all registered timeouts and determine which * will be the first to expire. * @timeout: filled with expiry time of soonest timer, or -1 if * no timeout is pending * returns: 0 on success, -1 on error */ static int virEventPollCalculateTimeout(int *timeout) { unsigned long long then = 0; int i; EVENT_DEBUG("Calculate expiry of %zu timers", eventLoop.timeoutsCount); /* Figure out if we need a timeout */ for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { if (eventLoop.timeouts[i].frequency < 0) continue; EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt); if (then == 0 || eventLoop.timeouts[i].expiresAt < then) then = eventLoop.timeouts[i].expiresAt; } /* Calculate how long we should wait for a timeout if needed */ if (then > 0) { unsigned long long now; if (virTimeMillisNow(&now) < 0) return -1; *timeout = then - now; if (*timeout < 0) *timeout = 0; } else { *timeout = -1; } EVENT_DEBUG("Timeout at %llu due in %d ms", then, *timeout); return 0; }
void ewol::context::InputManager::transfertEvent(ewol::WidgetShared _source, ewol::WidgetShared _destination) { if( _source == nullptr || _destination == nullptr) { // prevent errors ... return; } for(int32_t iii=0; iii<MAX_MANAGE_INPUT; iii++) { ewol::WidgetShared tmpWidget = m_eventInputSaved[iii].curentWidgetEvent.lock(); if (tmpWidget == _source) { // inform the widget that it does not receive the event now EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventInputSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_ABORT] " << m_eventInputSaved[iii].posEvent); localEventInput(gale::key::type::finger, tmpWidget, m_eventInputSaved[iii].destinationInputId, gale::key::status::abort, m_eventInputSaved[iii].posEvent); // set the new widget ... m_eventInputSaved[iii].curentWidgetEvent = _destination; // inform the widget that he receive the event property now... EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventInputSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_TRANSFERT] " << m_eventInputSaved[iii].posEvent); localEventInput(gale::key::type::finger, _destination, m_eventInputSaved[iii].destinationInputId, gale::key::status::transfert, m_eventInputSaved[iii].posEvent); } tmpWidget = m_eventMouseSaved[iii].curentWidgetEvent.lock(); if (tmpWidget == _source) { // inform the widget that it does not receive the event now EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventMouseSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_ABORT] " << m_eventMouseSaved[iii].posEvent); localEventInput(gale::key::type::mouse, tmpWidget, m_eventMouseSaved[iii].destinationInputId, gale::key::status::abort, m_eventMouseSaved[iii].posEvent); // set the new widget ... m_eventMouseSaved[iii].curentWidgetEvent = _destination; // inform the widget that he receive the event property now... EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventMouseSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_TRANSFERT] " << m_eventMouseSaved[iii].posEvent); localEventInput(gale::key::type::mouse, _destination, m_eventMouseSaved[iii].destinationInputId, gale::key::status::transfert, m_eventMouseSaved[iii].posEvent); } } }
/* * Run a single iteration of the event loop, blocking until * at least one file handle has an event, or a timer expires */ int virEventPollRunOnce(void) { struct pollfd *fds = NULL; int ret, timeout, nfds; virMutexLock(&eventLoop.lock); eventLoop.running = 1; virThreadSelf(&eventLoop.leader); virEventPollCleanupTimeouts(); virEventPollCleanupHandles(); if (!(fds = virEventPollMakePollFDs(&nfds)) || virEventPollCalculateTimeout(&timeout) < 0) goto error; virMutexUnlock(&eventLoop.lock); retry: PROBE(EVENT_POLL_RUN, "nhandles=%d timeout=%d", nfds, timeout); ret = poll(fds, nfds, timeout); if (ret < 0) { EVENT_DEBUG("Poll got error event %d", errno); if (errno == EINTR || errno == EAGAIN) { goto retry; } virReportSystemError(errno, "%s", _("Unable to poll on file handles")); goto error_unlocked; } EVENT_DEBUG("Poll got %d event(s)", ret); virMutexLock(&eventLoop.lock); if (virEventPollDispatchTimeouts() < 0) goto error; if (ret > 0 && virEventPollDispatchHandles(nfds, fds) < 0) goto error; virEventPollCleanupTimeouts(); virEventPollCleanupHandles(); eventLoop.running = 0; virMutexUnlock(&eventLoop.lock); VIR_FREE(fds); return 0; error: virMutexUnlock(&eventLoop.lock); error_unlocked: VIR_FREE(fds); return -1; }
/********************************************************************** * %FUNCTION: Event_AddHandler * %ARGUMENTS: * es -- event selector * fd -- file descriptor to watch * flags -- combination of EVENT_FLAG_READABLE and EVENT_FLAG_WRITEABLE * fn -- callback function to call when event is triggered * data -- extra data to pass to callback function * %RETURNS: * A newly-allocated EventHandler, or NULL. ***********************************************************************/ EventHandler * Event_AddHandler(EventSelector *es, int fd, unsigned int flags, EventCallbackFunc fn, void *data) { EventHandler *eh; /* Specifically disable timer and deleted flags */ flags &= (~(EVENT_TIMER_BITS | EVENT_FLAG_DELETED)); /* Bad file descriptor */ if (fd < 0) { errno = EBADF; return NULL; } eh = malloc(sizeof(EventHandler)); if (!eh) return NULL; eh->fd = fd; eh->flags = flags; eh->tmout.tv_usec = 0; eh->tmout.tv_sec = 0; eh->fn = fn; eh->data = data; /* Add immediately. This is safe even if we are in a handler. */ eh->next = es->handlers; es->handlers = eh; EVENT_DEBUG(("Event_AddHandler(es=%p, fd=%d, flags=%u) -> %p\n", es, fd, flags, eh)); return eh; }
/********************************************************************** * %FUNCTION: Event_DelHandler * %ARGUMENTS: * es -- event selector * eh -- event handler * %RETURNS: * 0 if OK, non-zero if there is an error * %DESCRIPTION: * Deletes the event handler eh ***********************************************************************/ int Event_DelHandler(EventSelector *es, EventHandler *eh) { /* Scan the handlers list */ EventHandler *cur, *prev; EVENT_DEBUG(("Event_DelHandler(es=%p, eh=%p)\n", es, eh)); for (cur=es->handlers, prev=NULL; cur; prev=cur, cur=cur->next) { if (cur == eh) { if (es->nestLevel) { eh->flags |= EVENT_FLAG_DELETED; es->opsPending = 1; return 0; } else { if (prev) prev->next = cur->next; else es->handlers = cur->next; DestroyHandler(cur); return 0; } } } /* Handler not found */ return 1; }
/* * Unregister a callback from a file handle * NB, it *must* be safe to call this from within a callback * For this reason we only ever set a flag in the existing list. * Actual deletion will be done out-of-band */ int virEventPollRemoveHandle(int watch) { int i; PROBE(EVENT_POLL_REMOVE_HANDLE, "watch=%d", watch); if (watch <= 0) { VIR_WARN("Ignoring invalid remove watch %d", watch); return -1; } virMutexLock(&eventLoop.lock); for (i = 0 ; i < eventLoop.handlesCount ; i++) { if (eventLoop.handles[i].deleted) continue; if (eventLoop.handles[i].watch == watch) { EVENT_DEBUG("mark delete %d %d", i, eventLoop.handles[i].fd); eventLoop.handles[i].deleted = 1; virEventPollInterruptLocked(); virMutexUnlock(&eventLoop.lock); return 0; } } virMutexUnlock(&eventLoop.lock); return -1; }
/* * Allocate a pollfd array containing data for all registered * file handles. The caller must free the returned data struct * returns: the pollfd array, or NULL on error */ static struct pollfd *virEventPollMakePollFDs(int *nfds) { struct pollfd *fds; int i; *nfds = 0; for (i = 0 ; i < eventLoop.handlesCount ; i++) { if (eventLoop.handles[i].events && !eventLoop.handles[i].deleted) (*nfds)++; } /* Setup the poll file handle data structs */ if (VIR_ALLOC_N(fds, *nfds) < 0) { virReportOOMError(); return NULL; } *nfds = 0; for (i = 0 ; i < eventLoop.handlesCount ; i++) { EVENT_DEBUG("Prepare n=%d w=%d, f=%d e=%d d=%d", i, eventLoop.handles[i].watch, eventLoop.handles[i].fd, eventLoop.handles[i].events, eventLoop.handles[i].deleted); if (!eventLoop.handles[i].events || eventLoop.handles[i].deleted) continue; fds[*nfds].fd = eventLoop.handles[i].fd; fds[*nfds].events = eventLoop.handles[i].events; fds[*nfds].revents = 0; (*nfds)++; //EVENT_DEBUG("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events); } return fds; }
/********************************************************************** * %FUNCTION: Event_AddHandlerWithTimeout * %ARGUMENTS: * es -- event selector * fd -- file descriptor to watch * flags -- combination of EVENT_FLAG_READABLE and EVENT_FLAG_WRITEABLE * t -- Timeout after which to call handler, even if not readable/writable. * If t.tv_sec < 0, calls normal Event_AddHandler with no timeout. * fn -- callback function to call when event is triggered * data -- extra data to pass to callback function * %RETURNS: * A newly-allocated EventHandler, or NULL. ***********************************************************************/ EventHandler * Event_AddHandlerWithTimeout(EventSelector *es, int fd, unsigned int flags, struct timeval t, EventCallbackFunc fn, void *data) { EventHandler *eh; struct timeval now; /* If timeout is negative, just do normal non-timing-out event */ if (t.tv_sec < 0 || t.tv_usec < 0) { return Event_AddHandler(es, fd, flags, fn, data); } /* Specifically disable timer and deleted flags */ flags &= (~(EVENT_FLAG_TIMER | EVENT_FLAG_DELETED)); flags |= EVENT_FLAG_TIMEOUT; /* Bad file descriptor? */ if (fd < 0) { errno = EBADF; return NULL; } /* Bad timeout? */ if (t.tv_usec >= 1000000) { errno = EINVAL; return NULL; } eh = malloc(sizeof(EventHandler)); if (!eh) return NULL; /* Convert time interval to absolute time */ gettimeofday(&now, NULL); t.tv_sec += now.tv_sec; t.tv_usec += now.tv_usec; if (t.tv_usec >= 1000000) { t.tv_usec -= 1000000; t.tv_sec++; } eh->fd = fd; eh->flags = flags; eh->tmout = t; eh->fn = fn; eh->data = data; /* Add immediately. This is safe even if we are in a handler. */ eh->next = es->handlers; es->handlers = eh; EVENT_DEBUG(("Event_AddHandlerWithTimeout(es=%p, fd=%d, flags=%u, t=%d/%d) -> %p\n", es, fd, flags, t.tv_sec, t.tv_usec, eh)); return eh; }
/********************************************************************** * %FUNCTION: free_state * %ARGUMENTS: * state -- EventTcpState to free * %RETURNS: * Nothing * %DESCRIPTION: * Frees all state associated with the TcpEvent. ***********************************************************************/ static void free_state(EventTcpState *state) { if (!state) return; EVENT_DEBUG(("tcp_free_state(state=%p)\n", state)); if (state->buf) free(state->buf); if (state->eh) Event_DelHandler(state->es, state->eh); free(state); }
/********************************************************************** * %FUNCTION: handle_writeable * %ARGUMENTS: * es -- event selector * fd -- the writeable socket * flags -- ignored * data -- the EventTcpState object * %RETURNS: * Nothing * %DESCRIPTION: * Continues to fill buffer. Calls callback when done. ***********************************************************************/ static void handle_writeable(EventSelector *es, int fd, unsigned int flags, void *data) { EventTcpState *state = (EventTcpState *) data; int done = state->cur - state->buf; int togo = state->len - done; int n; /* Timed out? */ if (flags & EVENT_FLAG_TIMEOUT) { errno = ETIMEDOUT; if (state->f) { (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT, state->data); } else { close(fd); } free_state(state); return; } /* togo had better not be zero here! */ n = write(fd, state->cur, togo); EVENT_DEBUG(("tcp_handle_writeable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data)); if (n <= 0) { /* error */ if (state->f) { (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_IOERROR, state->data); } else { close(fd); } free_state(state); return; } state->cur += n; done += n; if (done >= state->len) { /* Written enough! */ if (state->f) { (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_COMPLETE, state->data); } else { close(fd); } free_state(state); return; } }
/********************************************************************** * %FUNCTION: Event_CreateSelector * %ARGUMENTS: * None * %RETURNS: * A newly-allocated EventSelector, or NULL if out of memory. * %DESCRIPTION: * Creates a new EventSelector. ***********************************************************************/ EventSelector * Event_CreateSelector(void) { EventSelector *es = malloc(sizeof(EventSelector)); if (!es) return NULL; es->handlers = NULL; es->nestLevel = 0; es->destroyPending = 0; es->opsPending = 0; EVENT_DEBUG(("CreateSelector() -> %p\n", (void *) es)); return es; }
/********************************************************************** * %FUNCTION: handle_accept * %ARGUMENTS: * es -- event selector * fd -- socket * flags -- ignored * data -- the accept callback function * %RETURNS: * Nothing * %DESCRIPTION: * Calls accept; if a connection arrives, calls the accept callback * function with connected descriptor ***********************************************************************/ static void handle_accept(EventSelector *es, int fd, unsigned int flags, void *data) { int conn; EventTcpAcceptFunc f; EVENT_DEBUG(("tcp_handle_accept(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data)); conn = accept(fd, NULL, NULL); if (conn < 0) return; f = (EventTcpAcceptFunc) data; f(es, conn); }
/* Used post dispatch to actually remove any handles that * were previously marked as deleted. This asynchronous * cleanup is needed to make dispatch re-entrant safe. */ static void virEventPollCleanupHandles(void) { size_t i; size_t gap; VIR_DEBUG("Cleanup %zu", eventLoop.handlesCount); /* Remove deleted entries, shuffling down remaining * entries as needed to form contiguous series */ for (i = 0; i < eventLoop.handlesCount;) { if (!eventLoop.handles[i].deleted) { i++; continue; } PROBE(EVENT_POLL_PURGE_HANDLE, "watch=%d", eventLoop.handles[i].watch); if (eventLoop.handles[i].ff) { virFreeCallback ff = eventLoop.handles[i].ff; void *opaque = eventLoop.handles[i].opaque; virMutexUnlock(&eventLoop.lock); ff(opaque); virMutexLock(&eventLoop.lock); } if ((i+1) < eventLoop.handlesCount) { memmove(eventLoop.handles+i, eventLoop.handles+i+1, sizeof(struct virEventPollHandle)*(eventLoop.handlesCount -(i+1))); } eventLoop.handlesCount--; } /* Release some memory if we've got a big chunk free */ gap = eventLoop.handlesAlloc - eventLoop.handlesCount; if (eventLoop.handlesCount == 0 || (gap > eventLoop.handlesCount && gap > EVENT_ALLOC_EXTENT)) { EVENT_DEBUG("Found %zu out of %zu handles slots used, releasing %zu", eventLoop.handlesCount, eventLoop.handlesAlloc, gap); VIR_SHRINK_N(eventLoop.handles, eventLoop.handlesAlloc, gap); } }
/* * Register a callback for a timer event * NB, it *must* be safe to call this from within a callback * For this reason we only ever append to existing list. */ int virEventPollAddTimeout(int frequency, virEventTimeoutCallback cb, void *opaque, virFreeCallback ff) { unsigned long long now; int ret; if (virTimeMillisNow(&now) < 0) { return -1; } virMutexLock(&eventLoop.lock); if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) { EVENT_DEBUG("Used %zu timeout slots, adding at least %d more", eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT); if (VIR_RESIZE_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, eventLoop.timeoutsCount, EVENT_ALLOC_EXTENT) < 0) { virMutexUnlock(&eventLoop.lock); return -1; } } eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++; eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency; eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb; eventLoop.timeouts[eventLoop.timeoutsCount].ff = ff; eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque; eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0; eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt = frequency >= 0 ? frequency + now : 0; eventLoop.timeoutsCount++; ret = nextTimer-1; virEventPollInterruptLocked(); PROBE(EVENT_POLL_ADD_TIMEOUT, "timer=%d frequency=%d cb=%p opaque=%p ff=%p", ret, frequency, cb, opaque, ff); virMutexUnlock(&eventLoop.lock); return ret; }
/********************************************************************** * %FUNCTION: Event_AddTimerHandler * %ARGUMENTS: * es -- event selector * t -- time interval after which to trigger event * fn -- callback function to call when event is triggered * data -- extra data to pass to callback function * %RETURNS: * A newly-allocated EventHandler, or NULL. ***********************************************************************/ EventHandler * Event_AddTimerHandler(EventSelector *es, struct timeval t, EventCallbackFunc fn, void *data) { EventHandler *eh; struct timeval now; /* Check time interval for validity */ if (t.tv_sec < 0 || t.tv_usec < 0 || t.tv_usec >= 1000000) { errno = EINVAL; return NULL; } eh = malloc(sizeof(EventHandler)); if (!eh) return NULL; /* Convert time interval to absolute time */ gettimeofday(&now, NULL); t.tv_sec += now.tv_sec; t.tv_usec += now.tv_usec; if (t.tv_usec >= 1000000) { t.tv_usec -= 1000000; t.tv_sec++; } eh->fd = -1; eh->flags = EVENT_FLAG_TIMER; eh->tmout = t; eh->fn = fn; eh->data = data; /* Add immediately. This is safe even if we are in a handler. */ eh->next = es->handlers; es->handlers = eh; EVENT_DEBUG(("Event_AddTimerHandler(es=%p, t=%d/%d) -> %p\n", es, t.tv_sec,t.tv_usec, eh)); return eh; }
/********************************************************************** * %FUNCTION: handle_connect * %ARGUMENTS: * es -- event selector * fd -- socket * flags -- ignored * data -- the accept callback function * %RETURNS: * Nothing * %DESCRIPTION: * Calls accept; if a connection arrives, calls the accept callback * function with connected descriptor ***********************************************************************/ static void handle_connect(EventSelector *es, int fd, unsigned int flags, void *data) { int error = 0; socklen_t len = sizeof(error); EventTcpConnectState *state = (EventTcpConnectState *) data; EVENT_DEBUG(("tcp_handle_connect(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data)); /* Cancel writable event */ Event_DelHandler(es, state->conn); state->conn = NULL; /* Timeout? */ if (flags & EVENT_FLAG_TIMEOUT) { errno = ETIMEDOUT; state->f(es, fd, EVENT_TCP_FLAG_TIMEOUT, state->data); free(state); return; } /* Check for pending error */ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data); free(state); return; } if (error) { errno = error; state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data); free(state); return; } /* It looks cool! */ state->f(es, fd, EVENT_TCP_FLAG_COMPLETE, state->data); free(state); }
/********************************************************************** * %FUNCTION: EventTcp_CreateAcceptor * %ARGUMENTS: * es -- event selector * socket -- listening socket * f -- function to call when a connection is accepted * data -- extra data to pass to f. * %RETURNS: * An event handler on success, NULL on failure. * %DESCRIPTION: * Sets up an accepting socket and calls "f" whenever a new * connection arrives. ***********************************************************************/ EventHandler * EventTcp_CreateAcceptor(EventSelector *es, int socket, EventTcpAcceptFunc f) { int flags; EVENT_DEBUG(("EventTcp_CreateAcceptor(es=%p, socket=%d)\n", es, socket)); /* Make sure socket is non-blocking */ flags = fcntl(socket, F_GETFL, 0); if (flags == -1) { return NULL; } if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) { return NULL; } return Event_AddHandler(es, socket, EVENT_FLAG_READABLE, handle_accept, (void *) f); }
/* Iterate over all file handles and dispatch any which * have pending events listed in the poll() data. Invoke * the user supplied callback for each handle which has * pending events * * This method must cope with new handles being registered * by a callback, and must skip any handles marked as deleted. * * Returns 0 upon success, -1 if an error occurred */ static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) { size_t i, n; VIR_DEBUG("Dispatch %d", nfds); /* NB, use nfds not eventLoop.handlesCount, because new * fds might be added on end of list, and they're not * in the fds array we've got */ for (i = 0, n = 0; n < nfds && i < eventLoop.handlesCount; n++) { while (i < eventLoop.handlesCount && (eventLoop.handles[i].fd != fds[n].fd || eventLoop.handles[i].events == 0)) { i++; } if (i == eventLoop.handlesCount) break; VIR_DEBUG("i=%zu w=%d", i, eventLoop.handles[i].watch); if (eventLoop.handles[i].deleted) { EVENT_DEBUG("Skip deleted n=%zu w=%d f=%d", i, eventLoop.handles[i].watch, eventLoop.handles[i].fd); continue; } if (fds[n].revents) { virEventHandleCallback cb = eventLoop.handles[i].cb; int watch = eventLoop.handles[i].watch; void *opaque = eventLoop.handles[i].opaque; int hEvents = virEventPollFromNativeEvents(fds[n].revents); PROBE(EVENT_POLL_DISPATCH_HANDLE, "watch=%d events=%d", watch, hEvents); virMutexUnlock(&eventLoop.lock); (cb)(watch, fds[n].fd, hEvents, opaque); virMutexLock(&eventLoop.lock); } } return 0; }
/* * Register a callback for monitoring file handle events. * NB, it *must* be safe to call this from within a callback * For this reason we only ever append to existing list. */ int virEventPollAddHandle(int fd, int events, virEventHandleCallback cb, void *opaque, virFreeCallback ff) { int watch; virMutexLock(&eventLoop.lock); if (eventLoop.handlesCount == eventLoop.handlesAlloc) { EVENT_DEBUG("Used %zu handle slots, adding at least %d more", eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT); if (VIR_RESIZE_N(eventLoop.handles, eventLoop.handlesAlloc, eventLoop.handlesCount, EVENT_ALLOC_EXTENT) < 0) { virMutexUnlock(&eventLoop.lock); return -1; } } watch = nextWatch++; eventLoop.handles[eventLoop.handlesCount].watch = watch; eventLoop.handles[eventLoop.handlesCount].fd = fd; eventLoop.handles[eventLoop.handlesCount].events = virEventPollToNativeEvents(events); eventLoop.handles[eventLoop.handlesCount].cb = cb; eventLoop.handles[eventLoop.handlesCount].ff = ff; eventLoop.handles[eventLoop.handlesCount].opaque = opaque; eventLoop.handles[eventLoop.handlesCount].deleted = 0; eventLoop.handlesCount++; virEventPollInterruptLocked(); PROBE(EVENT_POLL_ADD_HANDLE, "watch=%d fd=%d events=%d cb=%p opaque=%p ff=%p", watch, fd, events, cb, opaque, ff); virMutexUnlock(&eventLoop.lock); return watch; }
// note if id<0 == > the it was finger event ... void gale::context::InputManager::motion(enum gale::key::type _type, int _pointerID, vec2 _pos) { EVENT_DEBUG("motion event : " << _type << " " << _pointerID << " " << _pos); if (MAX_MANAGE_INPUT <= _pointerID) { // reject pointer == > out of IDs... return; } InputPoperty *eventTable = nullptr; if (_type == gale::key::typeMouse) { eventTable = m_eventMouseSaved; } else if (_type == gale::key::typeFinger) { eventTable = m_eventInputSaved; } else { GALE_ERROR("Unknown type of event"); return; } if( _pointerID > MAX_MANAGE_INPUT || _pointerID < 0) { // not manage input return; } ememory::SharedPtr<gale::Application::Windows> tmpWindows = m_context.getWindows(); // special case for the mouse event 0 that represent the hover event of the system : if (_type == gale::key::typeMouse && _pointerID == 0) { // this event is all time on the good Application ... and manage the enter and leave ... // NOTE : the "layer Application" force us to get the Application at the specific position all the time : ememory::SharedPtr<gale::Application> tmpApplication; if (m_grabApplication.lock() != nullptr) { // grab all events ... tmpApplication = m_grabApplication.lock(); } else { if (nullptr != tmpWindows) { tmpApplication = tmpWindows->getApplicationAtPos(_pos); } } if( tmpApplication != eventTable[_pointerID].curentApplicationEvent.lock() || ( true == eventTable[_pointerID].isInside && ( eventTable[_pointerID].origin.x() > _pos.x() || eventTable[_pointerID].origin.y() > _pos.y() || (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) < _pos.x() || (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) < _pos.y()) ) ) { eventTable[_pointerID].isInside = false; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [LEAVE] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentApplicationEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::statusLeave, _pos); } if (eventTable[_pointerID].isInside == false) { // set the element inside ... eventTable[_pointerID].isInside = true; // get destination Application : eventTable[_pointerID].curentApplicationEvent = tmpApplication; if (tmpApplication == nullptr) { eventTable[_pointerID].isInside = false; } else { eventTable[_pointerID].origin = tmpApplication->getOrigin(); eventTable[_pointerID].size = tmpApplication->getSize(); } eventTable[_pointerID].destinationInputId = 0; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [ENTER] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpApplication, eventTable[_pointerID].destinationInputId, gale::key::statusEnter, _pos); } EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [MOVE] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpApplication, eventTable[_pointerID].destinationInputId, gale::key::statusMove, _pos); } else if (true == eventTable[_pointerID].isUsed) { if (true == eventTable[_pointerID].isInside) { if( eventTable[_pointerID].origin.x() > _pos.x() || eventTable[_pointerID].origin.y() > _pos.y() || (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) < _pos.x() || (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) < _pos.y()) { eventTable[_pointerID].isInside = false; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [LEAVE] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentApplicationEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::statusLeave, _pos); } } else { if( ( eventTable[_pointerID].origin.x() <= _pos.x() && (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) >= _pos.x() ) && ( eventTable[_pointerID].origin.y() <= _pos.y() && (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) >= _pos.y() ) ) { eventTable[_pointerID].isInside = true; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [ENTER] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentApplicationEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::statusEnter, _pos); } } EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [MOVE] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentApplicationEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::statusMove, _pos); } }
/********************************************************************** * %FUNCTION: Event_HandleEvent * %ARGUMENTS: * es -- EventSelector * %RETURNS: * 0 if OK, non-zero on error. errno is set appropriately. * %DESCRIPTION: * Handles a single event (uses select() to wait for an event.) ***********************************************************************/ int Event_HandleEvent(EventSelector *es) { fd_set readfds, writefds; fd_set *rd, *wr; unsigned int flags; struct timeval abs_timeout = {}, now; struct timeval timeout; struct timeval *tm; EventHandler *eh; int r = 0; int errno_save = 0; int foundTimeoutEvent = 0; int foundReadEvent = 0; int foundWriteEvent = 0; int maxfd = -1; int pastDue; EVENT_DEBUG(("Enter Event_HandleEvent(es=%p)\n", (void *) es)); /* Build the select sets */ FD_ZERO(&readfds); FD_ZERO(&writefds); eh = es->handlers; for (eh=es->handlers; eh; eh=eh->next) { if (eh->flags & EVENT_FLAG_DELETED) continue; if (eh->flags & EVENT_FLAG_READABLE) { foundReadEvent = 1; FD_SET(eh->fd, &readfds); if (eh->fd > maxfd) maxfd = eh->fd; } if (eh->flags & EVENT_FLAG_WRITEABLE) { foundWriteEvent = 1; FD_SET(eh->fd, &writefds); if (eh->fd > maxfd) maxfd = eh->fd; } if (eh->flags & EVENT_TIMER_BITS) { if (!foundTimeoutEvent) { abs_timeout = eh->tmout; foundTimeoutEvent = 1; } else { if (eh->tmout.tv_sec < abs_timeout.tv_sec || (eh->tmout.tv_sec == abs_timeout.tv_sec && eh->tmout.tv_usec < abs_timeout.tv_usec)) { abs_timeout = eh->tmout; } } } } if (foundReadEvent) { rd = &readfds; } else { rd = NULL; } if (foundWriteEvent) { wr = &writefds; } else { wr = NULL; } if (foundTimeoutEvent) { gettimeofday(&now, NULL); /* Convert absolute timeout to relative timeout for select */ timeout.tv_usec = abs_timeout.tv_usec - now.tv_usec; timeout.tv_sec = abs_timeout.tv_sec - now.tv_sec; if (timeout.tv_usec < 0) { timeout.tv_usec += 1000000; timeout.tv_sec--; } if (timeout.tv_sec < 0 || (timeout.tv_sec == 0 && timeout.tv_usec < 0)) { timeout.tv_sec = 0; timeout.tv_usec = 0; } tm = &timeout; } else { tm = NULL; } if (foundReadEvent || foundWriteEvent || foundTimeoutEvent) { for(;;) { r = select(maxfd+1, rd, wr, NULL, tm); if (r < 0) { if (errno == EINTR) continue; } break; } } if (foundTimeoutEvent) gettimeofday(&now, NULL); errno_save = errno; es->nestLevel++; if (r >= 0) { /* Call handlers */ for (eh=es->handlers; eh; eh=eh->next) { /* Pending delete for this handler? Ignore it */ if (eh->flags & EVENT_FLAG_DELETED) continue; flags = 0; if ((eh->flags & EVENT_FLAG_READABLE) && FD_ISSET(eh->fd, &readfds)) { flags |= EVENT_FLAG_READABLE; } if ((eh->flags & EVENT_FLAG_WRITEABLE) && FD_ISSET(eh->fd, &writefds)) { flags |= EVENT_FLAG_WRITEABLE; } if (eh->flags & EVENT_TIMER_BITS) { pastDue = (eh->tmout.tv_sec < now.tv_sec || (eh->tmout.tv_sec == now.tv_sec && eh->tmout.tv_usec <= now.tv_usec)); if (pastDue) { flags |= EVENT_TIMER_BITS; if (eh->flags & EVENT_FLAG_TIMER) { /* Timer events are only called once */ es->opsPending = 1; eh->flags |= EVENT_FLAG_DELETED; } } } /* Do callback */ if (flags) { EVENT_DEBUG(("Enter callback: eh=%p flags=%u\n", eh, flags)); eh->fn(es, eh->fd, flags, eh->data); EVENT_DEBUG(("Leave callback: eh=%p flags=%u\n", eh, flags)); } } } es->nestLevel--; if (!es->nestLevel && es->opsPending) { DoPendingChanges(es); } errno = errno_save; return r; }
/********************************************************************** * %FUNCTION: DestroyHandler * %ARGUMENTS: * eh -- an event handler * %RETURNS: * Nothing * %DESCRIPTION: * Destroys handler ***********************************************************************/ void DestroyHandler(EventHandler *eh) { EVENT_DEBUG(("DestroyHandler(eh=%p)\n", eh)); free(eh); }
void gale::context::InputManager::state(enum gale::key::type _type, int _pointerID, bool _isDown, vec2 _pos) { if (MAX_MANAGE_INPUT <= _pointerID) { // reject pointer == > out of IDs... return; } EVENT_DEBUG("event pointerId=" << _pointerID); // convert position in open-GL coordonates ... InputPoperty *eventTable = nullptr; InputLimit localLimit; if (_type == gale::key::typeMouse) { eventTable = m_eventMouseSaved; localLimit = m_eventMouseLimit; } else if (_type == gale::key::typeFinger) { eventTable = m_eventInputSaved; localLimit = m_eventInputLimit; } else { GALE_ERROR("Unknown type of event"); return; } if( _pointerID > MAX_MANAGE_INPUT || _pointerID <= 0) { // not manage input return; } // get the curent time ... int64_t currentTime = gale::getTime(); ememory::SharedPtr<gale::Application::Windows> tmpWindows = m_context.getWindows(); if (true == _isDown) { EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); if(true == eventTable[_pointerID].isUsed) { // we have an event previously ... check delay between click and offset position if (currentTime - eventTable[_pointerID].lastTimeEvent > localLimit.sepatateTime) { cleanElement(eventTable, _pointerID); } else if( abs(eventTable[_pointerID].downStart.x() - _pos.x()) >= localLimit.DpiOffset || abs(eventTable[_pointerID].downStart.y() - _pos.y()) >= localLimit.DpiOffset ){ cleanElement(eventTable, _pointerID); } } if(true == eventTable[_pointerID].isUsed) { // save start time eventTable[_pointerID].lastTimeEvent = currentTime; // generate DOWN Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentApplicationEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::statusDown, _pos); } else { // Mark it used : eventTable[_pointerID].isUsed = true; // Save current position : eventTable[_pointerID].downStart = _pos; // save start time eventTable[_pointerID].lastTimeEvent = currentTime; // set the element inside ... eventTable[_pointerID].isInside = true; ememory::SharedPtr<gale::Application> tmpApplication = m_grabApplication.lock(); // get destination Application : if(nullptr != tmpWindows) { if ( tmpApplication != nullptr && _type == gale::key::typeMouse) { eventTable[_pointerID].curentApplicationEvent = tmpApplication; } else { eventTable[_pointerID].curentApplicationEvent = tmpWindows->getApplicationAtPos(_pos); } } else { eventTable[_pointerID].curentApplicationEvent.reset(); } tmpApplication = eventTable[_pointerID].curentApplicationEvent.lock(); if (tmpApplication != nullptr) { eventTable[_pointerID].origin = tmpApplication->getOrigin(); eventTable[_pointerID].size = tmpApplication->getSize(); eventTable[_pointerID].destinationInputId = localGetDestinationId(_type, tmpApplication, _pointerID); } else { eventTable[_pointerID].destinationInputId = -1; } // generate DOWN Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpApplication, eventTable[_pointerID].destinationInputId, gale::key::statusDown, _pos); } } else { EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [UP] " << _pos); if(false == eventTable[_pointerID].isUsed) { // bad case ... ??? GALE_DEBUG("Up event without previous down ... "); // Mark it un-used : eventTable[_pointerID].isUsed = false; // revove the Application ... eventTable[_pointerID].curentApplicationEvent.reset(); } else { ememory::SharedPtr<gale::Application> tmpApplication = eventTable[_pointerID].curentApplicationEvent.lock(); // generate UP Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [UP] " << _pos); eventTable[_pointerID].posEvent = _pos; // send up event after the single event to prevent multiple Application getting elements localEventInput(_type, tmpApplication, _pointerID, gale::key::statusUp, _pos); // generate event (single) if( abs(eventTable[_pointerID].downStart.x() - _pos.x()) < localLimit.DpiOffset && abs(eventTable[_pointerID].downStart.y() - _pos.y()) < localLimit.DpiOffset ){ // Save current position : eventTable[_pointerID].downStart = _pos; // save start time eventTable[_pointerID].lastTimeEvent = currentTime; int32_t nbClickMax = 0; if(tmpApplication != nullptr) { nbClickMax = tmpApplication->getMouseLimit(); if (nbClickMax>5) { nbClickMax = 5; } } // in grab mode the single to quinte event are not generated .... if( ( m_grabApplication.lock() == nullptr || _type != gale::key::typeMouse ) && eventTable[_pointerID].nbClickEvent < nbClickMax) { // generate event SINGLE : eventTable[_pointerID].nbClickEvent++; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [" << eventTable[_pointerID].nbClickEvent << "] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpApplication, eventTable[_pointerID].destinationInputId, (enum gale::key::status)(gale::key::statusSingle + eventTable[_pointerID].nbClickEvent-1), _pos); if( eventTable[_pointerID].nbClickEvent >= nbClickMax) { eventTable[_pointerID].nbClickEvent = 0; } } else { eventTable[_pointerID].nbClickEvent = 0; } } // send up event after the single event to prevent multiple Application getting elements localEventInput(_type, tmpApplication, _pointerID, gale::key::statusUpAfter, _pos); // specific for tuch event if (_type == gale::key::typeFinger) { cleanElement(eventTable, _pointerID); } } } }
static void handle_readable(EventSelector *es, int fd, unsigned int flags, void *data) { EventTcpState *state = (EventTcpState *) data; int done = state->cur - state->buf; int togo = state->len - done; int nread = 0; int flag; EVENT_DEBUG(("tcp_handle_readable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data)); if (flags & EVENT_FLAG_TIMEOUT) { errno = ETIMEDOUT; (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT, state->data); free_state(state); return; } if (state->delim < 0) { nread = read(fd, state->cur, togo); if (nread <= 0) { if (nread < 0 && errno == ECONNRESET && done > 0) { nread = 0; } flag = (nread) ? EVENT_TCP_FLAG_IOERROR : EVENT_TCP_FLAG_EOF; (state->f)(es, state->socket, state->buf, done, flag, state->data); free_state(state); return; } state->cur += nread; done += nread; if (done >= state->len) { (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_COMPLETE, state->data); free_state(state); return; } } else { while ( (togo > 0) && (nread = read(fd, state->cur, 1)) == 1) { togo--; done++; state->cur++; if (*(state->cur - 1) == state->delim) break; } if (nread <= 0) { if (nread < 0 && errno == EAGAIN) return; } if (nread < 0) { flag = EVENT_TCP_FLAG_IOERROR; } else if (nread == 0) { flag = EVENT_TCP_FLAG_EOF; } else { flag = EVENT_TCP_FLAG_COMPLETE; } (state->f)(es, state->socket, state->buf, done, flag, state->data); free_state(state); return; } }
/********************************************************************** * %FUNCTION: handle_readable * %ARGUMENTS: * es -- event selector * fd -- the readable socket * flags -- ignored * data -- the EventTcpState object * %RETURNS: * Nothing * %DESCRIPTION: * Continues to fill buffer. Calls callback when done. ***********************************************************************/ static void handle_readable(EventSelector *es, int fd, unsigned int flags, void *data) { EventTcpState *state = (EventTcpState *) data; int done = state->cur - state->buf; int togo = state->len - done; int nread = 0; int flag; EVENT_DEBUG(("tcp_handle_readable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data)); /* Timed out? */ if (flags & EVENT_FLAG_TIMEOUT) { errno = ETIMEDOUT; (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT, state->data); free_state(state); return; } if (state->delim < 0) { /* Not looking for a delimiter */ /* togo had better not be zero here! */ nread = read(fd, state->cur, togo); if (nread <= 0) { /* Change connection reset to EOF if we have read at least one char */ if (nread < 0 && errno == ECONNRESET && done > 0) { nread = 0; } flag = (nread) ? EVENT_TCP_FLAG_IOERROR : EVENT_TCP_FLAG_EOF; /* error or EOF */ (state->f)(es, state->socket, state->buf, done, flag, state->data); free_state(state); return; } state->cur += nread; done += nread; if (done >= state->len) { /* Read enough! */ (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_COMPLETE, state->data); free_state(state); return; } } else { /* Looking for a delimiter */ while ( (togo > 0) && (nread = read(fd, state->cur, 1)) == 1) { togo--; done++; state->cur++; if (*(state->cur - 1) == state->delim) break; } if (nread <= 0) { /* Error or EOF -- check for EAGAIN */ if (nread < 0 && errno == EAGAIN) return; } /* Some other error, or EOF, or delimiter, or read enough */ if (nread < 0) { flag = EVENT_TCP_FLAG_IOERROR; } else if (nread == 0) { flag = EVENT_TCP_FLAG_EOF; } else { flag = EVENT_TCP_FLAG_COMPLETE; } (state->f)(es, state->socket, state->buf, done, flag, state->data); free_state(state); return; } }
/********************************************************************** * %FUNCTION: EventTcp_WriteBuf * %ARGUMENTS: * es -- event selector * socket -- socket to read from * buf -- buffer to write * len -- number of bytes to write * f -- function to call on EOF or when all bytes have been read * timeout -- timeout after which to cancel operation * data -- extra data to pass to function f. * %RETURNS: * A new EventTcpState token or NULL on error * %DESCRIPTION: * Sets up a handler to fill a buffer from a socket. ***********************************************************************/ EventTcpState * EventTcp_WriteBuf(EventSelector *es, int socket, char *buf, int len, EventTcpIOFinishedFunc f, int timeout, void *data) { EventTcpState *state; int flags; struct timeval t; EVENT_DEBUG(("EventTcp_WriteBuf(es=%p, socket=%d, len=%d, timeout=%d)\n", es, socket, len, timeout)); if (len <= 0) return NULL; if (socket < 0) return NULL; /* Make sure socket is non-blocking */ flags = fcntl(socket, F_GETFL, 0); if (flags == -1) { return NULL; } if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) { return NULL; } state = malloc(sizeof(EventTcpState)); if (!state) return NULL; memset(state, 0, sizeof(EventTcpState)); state->socket = socket; state->buf = malloc(len); if (!state->buf) { free_state(state); return NULL; } memcpy(state->buf, buf, len); state->cur = state->buf; state->len = len; state->f = f; state->es = es; if (timeout <= 0) { t.tv_sec = -1; t.tv_usec = -1; } else { t.tv_sec = timeout; t.tv_usec = 0; } state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_WRITEABLE, t, handle_writeable, (void *) state); if (!state->eh) { free_state(state); return NULL; } state->data = data; state->delim = -1; EVENT_DEBUG(("EventTcp_WriteBuf() -> %p\n", state)); return state; }
void ewol::context::InputManager::state(enum gale::key::type _type, int _pointerID, bool _isDown, vec2 _pos) { if (_pointerID >= MAX_MANAGE_INPUT) { // reject pointer == > out of IDs... return; } EVENT_DEBUG("event pointerId=" << _pointerID); // convert position in open-GL coordonates ... InputPoperty *eventTable = nullptr; InputLimit localLimit; if (_type == gale::key::type::mouse) { eventTable = m_eventMouseSaved; localLimit = m_eventMouseLimit; } else if (_type == gale::key::type::finger) { eventTable = m_eventInputSaved; localLimit = m_eventInputLimit; } else { EWOL_ERROR("Unknown type of event"); return; } if( _pointerID > MAX_MANAGE_INPUT || _pointerID <= 0) { // not manage input return; } // get the curent time ... echrono::Clock currentTime = echrono::Clock::now(); ewol::widget::WindowsShared tmpWindows = m_context.getWindows(); if (_isDown == true) { EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); if(eventTable[_pointerID].isUsed == true) { // we have an event previously ... check delay between click and offset position if (currentTime - eventTable[_pointerID].lastTimeEvent > localLimit.sepatateTime) { cleanElement(eventTable, _pointerID); } else if( std::abs(eventTable[_pointerID].downStart.x() - _pos.x()) >= localLimit.DpiOffset || std::abs(eventTable[_pointerID].downStart.y() - _pos.y()) >= localLimit.DpiOffset ){ cleanElement(eventTable, _pointerID); } } if(eventTable[_pointerID].isUsed == true) { // save start time eventTable[_pointerID].lastTimeEvent = currentTime; // generate DOWN Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::status::down, _pos); } else { // Mark it used : eventTable[_pointerID].isUsed = true; // Save current position : eventTable[_pointerID].downStart = _pos; // save start time eventTable[_pointerID].lastTimeEvent = currentTime; // set the element inside ... eventTable[_pointerID].isInside = true; ewol::WidgetShared tmpWidget = m_grabWidget.lock(); // get destination widget : if(tmpWindows != nullptr) { if ( tmpWidget != nullptr && _type == gale::key::type::mouse) { eventTable[_pointerID].curentWidgetEvent = tmpWidget; } else { tmpWidget = tmpWindows->getWidgetAtPos(_pos); eventTable[_pointerID].curentWidgetEvent = tmpWidget; if (tmpWidget != nullptr) { EVENT_DEBUG("Get widget at pos=" << _pos << " type: " << tmpWidget->getObjectType()); } else { EVENT_DEBUG("Get widget at pos=" << _pos << " NO WIDGET"); } } } else { eventTable[_pointerID].curentWidgetEvent.reset(); } tmpWidget = eventTable[_pointerID].curentWidgetEvent.lock(); if (tmpWidget != nullptr) { eventTable[_pointerID].origin = tmpWidget->getOrigin(); eventTable[_pointerID].size = tmpWidget->getSize(); eventTable[_pointerID].destinationInputId = localGetDestinationId(_type, tmpWidget, _pointerID); } else { eventTable[_pointerID].destinationInputId = -1; } // generate DOWN Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, gale::key::status::down, _pos); } } else { EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [UP] " << _pos); ewol::WidgetShared tmpWidget = eventTable[_pointerID].curentWidgetEvent.lock(); if(eventTable[_pointerID].isUsed == false) { // bad case ... ??? EWOL_DEBUG("Up event without previous down ... "); // Mark it un-used : eventTable[_pointerID].isUsed = false; // revove the widget ... eventTable[_pointerID].curentWidgetEvent.reset(); } else if (tmpWidget == nullptr) { // The widget has been removed: EVENT_DEBUG(" Object Removed ..."); // Mark it un-used : eventTable[_pointerID].isUsed = false; // revove the widget ... eventTable[_pointerID].curentWidgetEvent.reset(); } else { // generate UP Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [UP] " << _pos); eventTable[_pointerID].posEvent = _pos; // send up event after the single event to prevent multiple widget getting elements localEventInput(_type, tmpWidget, _pointerID, gale::key::status::up, _pos); // generate event (single) if( std::abs(eventTable[_pointerID].downStart.x() - _pos.x()) < localLimit.DpiOffset && std::abs(eventTable[_pointerID].downStart.y() - _pos.y()) < localLimit.DpiOffset ){ // Save current position : eventTable[_pointerID].downStart = _pos; // save start time eventTable[_pointerID].lastTimeEvent = currentTime; int32_t nbClickMax = 0; if(tmpWidget != nullptr) { nbClickMax = tmpWidget->getMouseLimit(); if (nbClickMax>5) { nbClickMax = 5; } } // in grab mode the single to quinte event are not generated .... if( ( m_grabWidget.lock() == nullptr || _type != gale::key::type::mouse ) && eventTable[_pointerID].nbClickEvent < nbClickMax) { // generate event SINGLE : eventTable[_pointerID].nbClickEvent++; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [" << eventTable[_pointerID].nbClickEvent << "] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, (enum gale::key::status)(uint32_t(gale::key::status::pressSingle) + eventTable[_pointerID].nbClickEvent-1), _pos); if( eventTable[_pointerID].nbClickEvent >= nbClickMax) { eventTable[_pointerID].nbClickEvent = 0; } } else { eventTable[_pointerID].nbClickEvent = 0; } } // send up event after the single event to prevent multiple widget getting elements localEventInput(_type, tmpWidget, _pointerID, gale::key::status::upAfter, _pos); // specific for tuch event if (_type == gale::key::type::finger) { cleanElement(eventTable, _pointerID); } } } }