static gboolean clutter_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterBackendX11 *backend = ((ClutterEventSource *) source)->backend; ClutterEvent *event; _clutter_threads_acquire_lock (); /* Grab the event(s), translate and figure out double click. * The push onto queue (stack) if valid. */ events_queue (backend); /* Pop an event off the queue if any */ event = clutter_event_get (); if (event != NULL) { /* forward the event into clutter for emission etc. */ _clutter_stage_queue_event (event->any.stage, event, FALSE); } _clutter_threads_release_lock (); return TRUE; }
static gboolean clutter_clock_prepare (GSource *source, gint *timeout) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClockDefault *master_clock = clock_source->master_clock; int delay; _clutter_threads_acquire_lock (); if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_CONTINUOUS_REDRAW)) { ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); const GSList *stages, *l; stages = clutter_stage_manager_peek_stages (stage_manager); /* Queue a full redraw on all of the stages */ for (l = stages; l != NULL; l = l->next) clutter_actor_queue_redraw (l->data); } delay = master_clock_next_frame_delay (master_clock); _clutter_threads_release_lock (); *timeout = delay; return delay == 0; }
static gboolean clutter_clock_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClockDefault *master_clock = clock_source->master_clock; gboolean stages_updated = FALSE; GSList *stages; CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); _clutter_threads_acquire_lock (); /* Get the time to use for this frame */ master_clock->cur_tick = g_source_get_time (source); #ifdef CLUTTER_ENABLE_DEBUG master_clock->remaining_budget = master_clock->frame_budget; #endif /* We need to protect ourselves against stages being destroyed during * event handling - master_clock_list_ready_stages() returns a * list of referenced that we'll unref afterwards. */ stages = master_clock_list_ready_stages (master_clock); master_clock->idle = FALSE; /* Each frame is split into three separate phases: */ /* 1. process all the events; each stage goes through its events queue * and processes each event according to its type, then emits the * various signals that are associated with the event */ master_clock_process_events (master_clock, stages); /* 2. advance the timelines */ master_clock_advance_timelines (master_clock); /* 3. relayout and redraw the stages */ stages_updated = master_clock_update_stages (master_clock, stages); /* The master clock goes idle if no stages were updated and falls back * to polling for timeline progressions... */ if (!stages_updated) master_clock->idle = TRUE; master_clock_reschedule_stage_updates (master_clock, stages); g_slist_foreach (stages, (GFunc) g_object_unref, NULL); g_slist_free (stages); master_clock->prev_tick = master_clock->cur_tick; _clutter_threads_release_lock (); return TRUE; }
static gboolean clutter_clock_check (GSource *source) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClockDefault *master_clock = clock_source->master_clock; int delay; _clutter_threads_acquire_lock (); delay = master_clock_next_frame_delay (master_clock); _clutter_threads_release_lock (); return delay == 0; }
static gboolean clutter_event_prepare (GSource *source, gint *timeout) { ClutterBackendX11 *backend = ((ClutterEventSource *) source)->backend; gboolean retval; _clutter_threads_acquire_lock (); *timeout = -1; retval = (clutter_events_pending () || XPending (backend->xdpy)); _clutter_threads_release_lock (); return retval; }
static gboolean clutter_event_check (GSource *source) { ClutterEventSource *event_source = (ClutterEventSource *) source; ClutterBackendX11 *backend = event_source->backend; gboolean retval; _clutter_threads_acquire_lock (); if (event_source->event_poll_fd.revents & G_IO_IN) retval = (clutter_events_pending () || XPending (backend->xdpy)); else retval = FALSE; _clutter_threads_release_lock (); return retval; }
/** * clutter_x11_handle_event: * @xevent: pointer to XEvent structure * * This function processes a single X event; it can be used to hook * into external X11 event processing (for example, a GDK filter * function). * * If clutter_x11_disable_event_retrieval() has been called, you must * let this function process events to update Clutter's internal state. * * Return value: #ClutterX11FilterReturn. %CLUTTER_X11_FILTER_REMOVE * indicates that Clutter has internally handled the event and the * caller should do no further processing. %CLUTTER_X11_FILTER_CONTINUE * indicates that Clutter is either not interested in the event, * or has used the event to update internal state without taking * any exclusive action. %CLUTTER_X11_FILTER_TRANSLATE will not * occur. * * Since: 0.8 */ ClutterX11FilterReturn clutter_x11_handle_event (XEvent *xevent) { ClutterX11FilterReturn result; ClutterBackend *backend; ClutterEvent *event; gint spin = 1; #ifdef HAVE_XGE ClutterBackendX11 *backend_x11; Display *xdisplay; gboolean allocated_event; #endif /* The return values here are someone approximate; we return * CLUTTER_X11_FILTER_REMOVE if a clutter event is * generated for the event. This mostly, but not entirely, * corresponds to whether other event processing should be * excluded. As long as the stage window is not shared with another * toolkit it should be safe, and never return * %CLUTTER_X11_FILTER_REMOVE when more processing is needed. */ result = CLUTTER_X11_FILTER_CONTINUE; _clutter_threads_acquire_lock (); backend = clutter_get_default_backend (); event = clutter_event_new (CLUTTER_NOTHING); #ifdef HAVE_XGE backend_x11 = CLUTTER_BACKEND_X11 (backend); xdisplay = backend_x11->xdpy; allocated_event = XGetEventData (xdisplay, &xevent->xcookie); #endif if (_clutter_backend_translate_event (backend, xevent, event)) { _clutter_event_push (event, FALSE); result = CLUTTER_X11_FILTER_REMOVE; } else { clutter_event_free (event); goto out; } /* * Motion events can generate synthetic enter and leave events, so if we * are processing a motion event, we need to spin the event loop at least * two extra times to pump the enter/leave events through (otherwise they * just get pushed down the queue and never processed). */ if (event->type == CLUTTER_MOTION) spin += 2; while (spin > 0 && (event = clutter_event_get ())) { /* forward the event into clutter for emission etc. */ _clutter_stage_queue_event (event->any.stage, event, FALSE); --spin; } out: #ifdef HAVE_XGE if (allocated_event) XFreeEventData (xdisplay, &xevent->xcookie); #endif _clutter_threads_release_lock (); return result; }
/** * clutter_gdk_handle_event: * @event: a #GdkEvent * * This function processes a single GDK event; it can be used to hook * into external event processing * * Return value: #GdkFilterReturn. %GDK_FILTER_REMOVE indicates that * Clutter has internally handled the event and the caller should do * no further processing. %GDK_FILTER_CONTINUE indicates that Clutter * is either not interested in the event, or has used the event to * update internal state without taking any exclusive action. * %GDK_FILTER_TRANSLATE will not occur. * */ GdkFilterReturn clutter_gdk_handle_event (GdkEvent *gdk_event) { ClutterDeviceManager *device_manager; ClutterBackendGdk *backend_gdk; ClutterBackend *backend; ClutterStage *stage = NULL; ClutterEvent *event = NULL; gint spin = 0; GdkFilterReturn result = GDK_FILTER_CONTINUE; ClutterInputDevice *device, *source_device; GdkDevice *gdk_device; backend = clutter_get_default_backend (); if (!CLUTTER_IS_BACKEND_GDK (backend)) return GDK_FILTER_CONTINUE; if (gdk_event->any.window == NULL) return GDK_FILTER_CONTINUE; device_manager = clutter_device_manager_get_default (); if (G_UNLIKELY (device_manager == NULL)) return GDK_FILTER_CONTINUE; backend_gdk = CLUTTER_BACKEND_GDK (backend); stage = clutter_gdk_get_stage_from_window (gdk_event->any.window); gdk_device = gdk_event_get_device (gdk_event); if (gdk_device != NULL) device = _clutter_device_manager_gdk_lookup_device (device_manager, gdk_device); else device = NULL; gdk_device = gdk_event_get_source_device (gdk_event); if (gdk_device != NULL) source_device = _clutter_device_manager_gdk_lookup_device (device_manager, gdk_device); else source_device = NULL; if (stage == NULL) return GDK_FILTER_CONTINUE; _clutter_threads_acquire_lock (); switch (gdk_event->type) { case GDK_DELETE: event = clutter_event_new (CLUTTER_DELETE); break; case GDK_DESTROY: event = clutter_event_new (CLUTTER_DESTROY_NOTIFY); break; case GDK_EXPOSE: { ClutterPaintVolume clip; ClutterVertex origin; CLUTTER_NOTE (EVENT, "Expose for stage '%s' [%p] { %d, %d - %d x %d }", _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)), stage, gdk_event->expose.area.x, gdk_event->expose.area.y, gdk_event->expose.area.width, gdk_event->expose.area.height); origin.x = gdk_event->expose.area.x; origin.y = gdk_event->expose.area.y; origin.z = 0; _clutter_paint_volume_init_static (&clip, CLUTTER_ACTOR (stage)); clutter_paint_volume_set_origin (&clip, &origin); clutter_paint_volume_set_width (&clip, gdk_event->expose.area.width); clutter_paint_volume_set_height (&clip, gdk_event->expose.area.height); _clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), 0, &clip); clutter_paint_volume_free (&clip); } break; case GDK_DAMAGE: /* This is handled by cogl */ break; case GDK_MOTION_NOTIFY: event = clutter_event_new (CLUTTER_MOTION); event->motion.time = gdk_event->motion.time; event->motion.x = gdk_event->motion.x; event->motion.y = gdk_event->motion.y; event->motion.axes = NULL; /* It's all X in the end, right? */ event->motion.modifier_state = gdk_event->motion.state; clutter_event_set_device (event, device); clutter_event_set_source_device (event, source_device); CLUTTER_NOTE (EVENT, "Motion notifiy [%.2f, %.2f]", event->motion.x, event->motion.y); break; case GDK_BUTTON_PRESS: case GDK_BUTTON_RELEASE: event = clutter_event_new (gdk_event->type == GDK_BUTTON_PRESS ? CLUTTER_BUTTON_PRESS : CLUTTER_BUTTON_RELEASE); event->button.time = gdk_event->button.time; event->button.x = gdk_event->button.x; event->button.y = gdk_event->button.y; event->button.axes = NULL; event->button.modifier_state = gdk_event->button.state; event->button.button = gdk_event->button.button; event->button.click_count = 1; clutter_event_set_device (event, device); clutter_event_set_source_device (event, source_device); CLUTTER_NOTE (EVENT, "Button %d %s [%.2f, %.2f]", event->button.button, event->type == CLUTTER_BUTTON_PRESS ? "press" : "release", event->button.x, event->button.y); break; case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: /* these are handled by clutter-main.c updating click_count */ break; case GDK_KEY_PRESS: case GDK_KEY_RELEASE: event = clutter_event_new (gdk_event->type == GDK_KEY_PRESS ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE); event->key.time = gdk_event->key.time; event->key.modifier_state = gdk_event->key.state; event->key.keyval = gdk_event->key.keyval; event->key.hardware_keycode = gdk_event->key.hardware_keycode; event->key.unicode_value = g_utf8_get_char (gdk_event->key.string); clutter_event_set_device (event, device); clutter_event_set_source_device (event, source_device); CLUTTER_NOTE (EVENT, "Key %d %s", event->key.keyval, event->type == CLUTTER_KEY_PRESS ? "press" : "release"); break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: event = clutter_event_new (gdk_event->type == GDK_ENTER_NOTIFY ? CLUTTER_ENTER : CLUTTER_LEAVE); event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.time = gdk_event_get_time (gdk_event); event->crossing.x = gdk_event->crossing.x; event->crossing.y = gdk_event->crossing.y; /* XXX: no better fallback here? */ clutter_event_set_device (event, device); clutter_event_set_source_device (event, source_device); if (gdk_event->type == GDK_ENTER_NOTIFY) _clutter_input_device_set_stage (clutter_event_get_device (event), stage); else _clutter_input_device_set_stage (clutter_event_get_device (event), NULL); CLUTTER_NOTE (EVENT, "Crossing %s [%.2f, %.2f]", event->type == CLUTTER_ENTER ? "enter" : "leave", event->crossing.x, event->crossing.y); break; case GDK_FOCUS_CHANGE: if (gdk_event->focus_change.in) _clutter_stage_update_state (stage, 0, CLUTTER_STAGE_STATE_ACTIVATED); else _clutter_stage_update_state (stage, CLUTTER_STAGE_STATE_ACTIVATED, 0); break; case GDK_CONFIGURE: { gfloat w, h; clutter_actor_get_size (CLUTTER_ACTOR (stage), &w, &h); if (w != gdk_event->configure.width || h != gdk_event->configure.height) { clutter_actor_set_size (CLUTTER_ACTOR (stage), gdk_event->configure.width, gdk_event->configure.height); } } break; case GDK_SCROLL: event = clutter_event_new (CLUTTER_SCROLL); event->scroll.time = gdk_event->scroll.time; event->scroll.x = gdk_event->scroll.x; event->scroll.y = gdk_event->scroll.y; event->scroll.modifier_state = gdk_event->scroll.state; event->scroll.axes = NULL; /* XXX: must keep ClutterScrollDirection compatible with GdkScrollDirection */ event->scroll.direction = (ClutterScrollDirection) gdk_event->scroll.direction; clutter_event_set_device (event, device); clutter_event_set_source_device (event, source_device); clutter_event_set_scroll_delta (event, gdk_event->scroll.delta_x, gdk_event->scroll.delta_y); break; case GDK_WINDOW_STATE: if (gdk_event->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) { gboolean is_fullscreen; is_fullscreen = (gdk_event->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0; if (is_fullscreen) _clutter_stage_update_state (stage, 0, CLUTTER_STAGE_STATE_FULLSCREEN); else _clutter_stage_update_state (stage, CLUTTER_STAGE_STATE_FULLSCREEN, 0); } break; case GDK_SETTING: _clutter_backend_gdk_update_setting (backend_gdk, gdk_event->setting.name); break; default: break; } if (event != NULL) { event->any.stage = stage; if (gdk_event->any.send_event) event->any.flags = CLUTTER_EVENT_FLAG_SYNTHETIC; _clutter_event_push (event, FALSE); spin = 1; CLUTTER_NOTE (EVENT, "Translated one event from Gdk"); /* handle also synthetic enter/leave events */ if (event->type == CLUTTER_MOTION) spin += 2; while (spin > 0 && (event = clutter_event_get ())) { /* forward the event into clutter for emission etc. */ clutter_do_event (event); clutter_event_free (event); --spin; } result = GDK_FILTER_REMOVE; } _clutter_threads_release_lock (); return result; }