static void clutter_backend_gdk_finalize (GObject *gobject) { ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (gobject); gdk_window_remove_filter (NULL, cogl_gdk_filter, NULL); g_object_unref (backend_gdk->display); G_OBJECT_CLASS (clutter_backend_gdk_parent_class)->finalize (gobject); }
void _clutter_backend_gdk_events_init (ClutterBackend *backend) { ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend); CLUTTER_NOTE (EVENT, "initialising the event loop"); backend->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_GDK, "backend", backend, "gdk-display", backend_gdk->display, NULL); if (!disable_event_retrieval) gdk_event_handler_set (gdk_event_handler, NULL, NULL); }
static gboolean _clutter_backend_gdk_post_parse (ClutterBackend *backend, GError **error) { ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend); if (_foreign_dpy != NULL) backend_gdk->display = _foreign_dpy; /* Init Gdk, if outside code did not already */ if (!gdk_init_check (NULL, NULL)) return FALSE; /* * Only open connection if not already set by prior call to * clutter_gdk_set_display() */ if (backend_gdk->display == NULL) backend_gdk->display = g_object_ref (gdk_display_get_default ()); g_assert (backend_gdk->display != NULL); #ifdef GDK_WINDOWING_X11 if (GDK_IS_X11_DISPLAY (backend_gdk->display)) { /* Cogl needs to know the Xlib display connection for CoglTexturePixmapX11 */ cogl_xlib_set_display (gdk_x11_display_get_xdisplay (backend_gdk->display)); } #endif backend_gdk->screen = gdk_display_get_default_screen (backend_gdk->display); /* add event filter for Cogl events */ gdk_window_add_filter (NULL, cogl_gdk_filter, NULL); clutter_backend_gdk_init_settings (backend_gdk); CLUTTER_NOTE (BACKEND, "Gdk Display '%s' opened", gdk_display_get_name (backend_gdk->display)); return TRUE; }
/** * clutter_gdk_get_default_display: * * Retrieves the pointer to the default display. * * Return value: (transfer none): the default display * * Since: 0.6 */ GdkDisplay * clutter_gdk_get_default_display (void) { ClutterBackend *backend = clutter_get_default_backend (); if (backend == NULL) { g_critical ("The Clutter backend has not been initialised"); return NULL; } if (!CLUTTER_IS_BACKEND_GDK (backend)) { g_critical ("The Clutter backend is not a GDK backend"); return NULL; } return CLUTTER_BACKEND_GDK (backend)->display; }
static CoglRenderer * clutter_backend_gdk_get_renderer (ClutterBackend *backend, GError **error) { ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend); CoglRenderer *renderer = cogl_renderer_new (); #if defined(GDK_WINDOWING_X11) && defined(COGL_HAS_XLIB_SUPPORT) if (GDK_IS_X11_DISPLAY (backend_gdk->display)) { Display *xdisplay = gdk_x11_display_get_xdisplay (backend_gdk->display); cogl_xlib_renderer_set_foreign_display (renderer, xdisplay); } else #endif #if defined(GDK_WINDOWING_WIN32) if (GDK_IS_WIN32_DISPLAY (backend_gdk->display)) { /* Force a WGL winsys on windows */ cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_WGL); } else #endif { g_set_error (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_BACKEND, _("Could not find a suitable CoglWinsys for a GdkDisplay of type %s"), G_OBJECT_TYPE_NAME (backend_gdk->display)); cogl_object_unref (renderer); return NULL; } return renderer; }
static CoglDisplay * clutter_backend_gdk_get_display (ClutterBackend *backend, CoglRenderer *renderer, CoglSwapChain *swap_chain, GError **error) { ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend); CoglOnscreenTemplate *onscreen_template; GError *internal_error = NULL; CoglDisplay *display; gboolean has_rgba_visual; gboolean res; has_rgba_visual = gdk_screen_get_rgba_visual (backend_gdk->screen) == NULL; CLUTTER_NOTE (BACKEND, "Alpha on Cogl swap chain: %s", has_rgba_visual ? "enabled" : "disabled"); cogl_swap_chain_set_has_alpha (swap_chain, has_rgba_visual); onscreen_template = cogl_onscreen_template_new (swap_chain); res = cogl_renderer_check_onscreen_template (renderer, onscreen_template, &internal_error); if (!res && has_rgba_visual) { CLUTTER_NOTE (BACKEND, "Creation of a context with a ARGB visual failed: %s", internal_error != NULL ? internal_error->message : "Unknown reason"); g_clear_error (&internal_error); /* It's possible that the current renderer doesn't support transparency * in a swap_chain so lets see if we can fallback to not having any * transparency... * * XXX: It might be nice to have a CoglRenderer feature we could * explicitly check for ahead of time. */ cogl_swap_chain_set_has_alpha (swap_chain, FALSE); res = cogl_renderer_check_onscreen_template (renderer, onscreen_template, &internal_error); } if (!res) { g_set_error_literal (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_BACKEND, internal_error->message); g_error_free (internal_error); cogl_object_unref (onscreen_template); return NULL; } display = cogl_display_new (renderer, onscreen_template); cogl_object_unref (onscreen_template); return display; }
static gboolean clutter_stage_gdk_realize (ClutterStageWindow *stage_window) { ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); ClutterBackend *backend = CLUTTER_BACKEND (stage_cogl->backend); ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend); GdkWindowAttr attributes; gboolean cursor_visible; gboolean use_alpha; gfloat width, height; if (stage_gdk->foreign_window) { width = gdk_window_get_width (stage_gdk->window); height = gdk_window_get_height (stage_gdk->window); } else { if (stage_gdk->window != NULL) { /* complete realizing the stage */ cairo_rectangle_int_t geometry; clutter_stage_gdk_get_geometry (stage_window, &geometry); clutter_actor_set_size (CLUTTER_ACTOR (stage_cogl->wrapper), geometry.width, geometry.height); gdk_window_ensure_native (stage_gdk->window); gdk_window_set_events (stage_gdk->window, CLUTTER_STAGE_GDK_EVENT_MASK); return TRUE; } else { attributes.title = NULL; g_object_get (stage_cogl->wrapper, "cursor-visible", &cursor_visible, "title", &attributes.title, "width", &width, "height", &height, "use-alpha", &use_alpha, NULL); attributes.width = width; attributes.height = height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_TOPLEVEL; attributes.event_mask = CLUTTER_STAGE_GDK_EVENT_MASK; attributes.cursor = NULL; if (!cursor_visible) { if (stage_gdk->blank_cursor == NULL) stage_gdk->blank_cursor = gdk_cursor_new_for_display (backend_gdk->display, GDK_BLANK_CURSOR); attributes.cursor = stage_gdk->blank_cursor; } attributes.visual = NULL; if (use_alpha) { attributes.visual = gdk_screen_get_rgba_visual (backend_gdk->screen); if (attributes.visual == NULL) clutter_stage_set_use_alpha (stage_cogl->wrapper, FALSE); } if (attributes.visual == NULL) { /* This could still be an RGBA visual, although normally it's not */ attributes.visual = gdk_screen_get_system_visual (backend_gdk->screen); } stage_gdk->foreign_window = FALSE; stage_gdk->window = gdk_window_new (NULL, &attributes, GDK_WA_TITLE | GDK_WA_CURSOR | GDK_WA_VISUAL); g_free (attributes.title); } clutter_stage_gdk_set_gdk_geometry (stage_gdk); } gdk_window_ensure_native (stage_gdk->window); g_object_set_data (G_OBJECT (stage_gdk->window), "clutter-stage-window", stage_gdk); stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context, width, height); #if defined(GDK_WINDOWING_X11) && defined(COGL_HAS_XLIB_SUPPORT) if (GDK_IS_X11_WINDOW (stage_gdk->window)) { cogl_x11_onscreen_set_foreign_window_xid (stage_cogl->onscreen, GDK_WINDOW_XID (stage_gdk->window), clutter_stage_gdk_update_foreign_event_mask, stage_gdk); } else #endif #if defined(GDK_WINDOWING_WAYLAND) && defined(COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT) if (GDK_IS_WAYLAND_WINDOW (stage_gdk->window)) { cogl_wayland_onscreen_set_foreign_surface (stage_cogl->onscreen, gdk_wayland_window_get_wl_surface (stage_gdk->window)); } else #endif #if defined(GDK_WINDOWING_WIN32) && defined(COGL_HAS_WIN32_SUPPORT) if (GDK_IS_WIN32_WINDOW (stage_gdk->window)) { cogl_win32_onscreen_set_foreign_window (stage_cogl->onscreen, gdk_win32_window_get_handle (stage_gdk->window)); } else #endif { g_warning ("Cannot find an appropriate CoglWinsys for a " "GdkWindow of type %s", G_OBJECT_TYPE_NAME (stage_gdk->window)); cogl_object_unref (stage_cogl->onscreen); stage_cogl->onscreen = NULL; if (!stage_gdk->foreign_window) gdk_window_destroy (stage_gdk->window); stage_gdk->window = NULL; return FALSE; } return clutter_stage_window_parent_iface->realize (stage_window); }
/** * 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; }