static void art_cb (RBExtDBKey *key, const char *filename, GValue *data, MxFrame *frame) { ClutterActor *image; GdkPixbuf *pixbuf; if (data == NULL || G_VALUE_HOLDS (data, GDK_TYPE_PIXBUF) == FALSE) { return; } clutter_threads_enter (); image = gtk_clutter_texture_new (); pixbuf = GDK_PIXBUF (g_value_get_object (data)); gtk_clutter_texture_set_from_pixbuf (GTK_CLUTTER_TEXTURE (image), pixbuf, NULL); if (clutter_actor_get_height (image) > MAX_IMAGE_HEIGHT) { clutter_actor_set_height (image, MAX_IMAGE_HEIGHT); clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (image), TRUE); } if (clutter_actor_get_width (image) > MAX_IMAGE_HEIGHT) { clutter_actor_set_width (image, MAX_IMAGE_HEIGHT); } mx_bin_set_child (MX_BIN (frame), image); clutter_actor_show_all (CLUTTER_ACTOR (frame)); clutter_threads_leave (); }
static void prev_clicked_cb (MxButton *button, RBShellPlayer *player) { clutter_threads_leave (); rb_shell_player_do_previous (player, NULL); clutter_threads_enter (); }
static void playpause_clicked_cb (MxButton *button, RBShellPlayer *player) { clutter_threads_leave (); rb_shell_player_playpause (player, FALSE, NULL); clutter_threads_enter (); }
static void update_track_info_lock (MxLabel *label, RhythmDB *db, RhythmDBEntry *entry, const char *streaming_title) { clutter_threads_enter (); update_track_info (label, db, entry, streaming_title); clutter_threads_leave (); }
static void elapsed_changed_cb (RBShellPlayer *player, guint elapsed, ClutterActor *label) { clutter_threads_enter (); update_elapsed (label, player, elapsed); clutter_threads_leave (); }
static gboolean clutter_event_source_wayland_dispatch (GSource *base, GSourceFunc callback, gpointer data) { ClutterEventSourceWayland *source = (ClutterEventSourceWayland *) base; ClutterEvent *event; clutter_threads_enter (); if (source->pfd.revents) { wl_display_iterate (source->display, WL_DISPLAY_READABLE); source->pfd.revents = 0; } event = clutter_event_get (); if (event) { /* forward the event into clutter for emission etc. */ clutter_do_event (event); clutter_event_free (event); } clutter_threads_leave (); return TRUE; }
static gboolean clutter_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterBackend *backend = ((ClutterEventSource *) source)->backend; ClutterEvent *event; clutter_threads_enter (); /* 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) { /* forward the event into clutter for emission etc. */ clutter_do_event (event); clutter_event_free (event); } clutter_threads_leave (); return TRUE; }
static gboolean clutter_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterEvent *event; MSG msg; clutter_threads_enter (); /* Process Windows messages until we've got one that translates into the clutter event queue */ while (!clutter_events_pending () && PeekMessageW (&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageW (&msg); /* Pop an event off the queue if any */ if ((event = clutter_event_get ())) { /* forward the event into clutter for emission etc. */ clutter_do_event (event); clutter_event_free (event); } clutter_threads_leave (); return TRUE; }
/** * 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; /* 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_enter (); backend = clutter_get_default_backend (); event = clutter_event_new (CLUTTER_NOTHING); 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_do_event (event); clutter_event_free (event); --spin; } out: clutter_threads_leave (); return result; }
static void playing_changed_cb (RBShellPlayer *player, gboolean playing, MxButton *button) { clutter_threads_enter (); update_playing (button, playing); clutter_threads_leave (); }
static void on_stage_destroyed(gpointer *user_data) { TempiClutterStageNode *self = (TempiClutterStageNode *) user_data; (void) self; clutter_threads_enter(); clutter_main_quit(); clutter_threads_leave(); }
static gboolean stage_key_release_cb (ClutterActor *stage, ClutterEvent *event, RBVisualizerPage *page) { if (event->key.keyval == CLUTTER_KEY_Escape) { clutter_threads_leave (); stop_fullscreen (page); clutter_threads_enter (); } return FALSE; }
static void cover_art_entry_changed_cb (RBShellPlayer *player, RhythmDBEntry *entry, MxFrame *frame) { clutter_threads_enter (); set_blank_image (frame); clutter_actor_show_all (CLUTTER_ACTOR (frame)); clutter_threads_leave (); request_cover_art (frame, entry); }
static gboolean clutter_clock_check (GSource *source) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClock *master_clock = clock_source->master_clock; int delay; clutter_threads_enter (); delay = master_clock_next_frame_delay (master_clock); clutter_threads_leave (); return delay == 0; }
static gboolean stage_button_press_cb (ClutterActor *stage, ClutterEvent *event, RBVisualizerPage *page) { if (event->button.button == 1 && event->button.click_count == 2) { clutter_threads_leave (); toggle_fullscreen (page); clutter_threads_enter (); } else if (event->button.button == 3) { rb_display_page_show_popup (RB_DISPLAY_PAGE (page)); } return FALSE; }
static gboolean clutter_event_source_wayland_check (GSource *base) { ClutterEventSourceWayland *source = (ClutterEventSourceWayland *) base; gboolean retval; clutter_threads_enter (); retval = clutter_events_pending () || source->pfd.revents; clutter_threads_leave (); return retval; }
static gboolean clutter_event_prepare (GSource *source, gint *timeout) { gboolean retval; clutter_threads_enter (); *timeout = -1; retval = (clutter_events_pending () || check_msg_pending ()); clutter_threads_leave (); return retval; }
void rb_visualizer_fullscreen_add_widgets (GtkWidget *window, ClutterActor *stage, RBShell *shell) { ClutterActor *track_info; ClutterActor *controls; GdkScreen *screen; GdkRectangle geom; int x; int y; int monitor; clutter_threads_enter (); /* get geometry for the monitor we're going to appear on */ screen = gtk_widget_get_screen (window); monitor = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (window)); gdk_screen_get_monitor_geometry (screen, monitor, &geom); /* create and place the track info display */ track_info = create_track_info (shell); clutter_container_add_actor (CLUTTER_CONTAINER (stage), track_info); g_object_set_data (G_OBJECT (stage), TRACK_INFO_DATA, track_info); /* XXX rtl? */ clutter_actor_set_position (track_info, FULLSCREEN_BORDER_WIDTH, FULLSCREEN_BORDER_WIDTH); /* create and place the playback controls */ controls = create_controls (shell); clutter_container_add_actor (CLUTTER_CONTAINER (stage), controls); g_object_set_data (G_OBJECT (stage), CONTROLS_DATA, controls); /* put this bit somewhere near the bottom */ /* XXX rtl */ x = FULLSCREEN_BORDER_WIDTH; y = geom.height - (clutter_actor_get_height (controls) + FULLSCREEN_BORDER_WIDTH); clutter_actor_set_position (controls, x, y); /* hide mouse cursor when not moving, hide playback controls when mouse not moving * and outside them */ g_signal_connect_object (stage, "motion-event", G_CALLBACK (stage_motion_event_cb), controls, 0); g_signal_connect (controls, "leave-event", G_CALLBACK (controls_leave_event_cb), NULL); g_signal_connect (controls, "enter-event", G_CALLBACK (controls_enter_event_cb), NULL); start_hide_timer (controls); clutter_threads_leave (); }
static gboolean clutter_clock_prepare (GSource *source, gint *timeout) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClock *master_clock = clock_source->master_clock; int delay; clutter_threads_enter (); delay = master_clock_next_frame_delay (master_clock); clutter_threads_leave (); *timeout = delay; return delay == 0; }
static gboolean clutter_event_prepare (GSource *source, gint *timeout) { ClutterBackend *backend = ((ClutterEventSource *) source)->backend; gboolean retval; clutter_threads_enter (); *timeout = -1; retval = (clutter_events_pending () || check_xpending (backend)); clutter_threads_leave (); return retval; }
static gboolean clutter_event_check (GSource *source) { ClutterEventSource *event_source = (ClutterEventSource *) source; gboolean retval; clutter_threads_enter (); if ((event_source->event_poll_fd.revents & G_IO_IN)) retval = (clutter_events_pending () || check_msg_pending ()); else retval = FALSE; clutter_threads_leave (); return retval; }
static gboolean clutter_event_source_wayland_prepare (GSource *base, gint *timeout) { ClutterEventSourceWayland *source = (ClutterEventSourceWayland *) base; gboolean retval; clutter_threads_enter (); *timeout = -1; /* We have to add/remove the GPollFD if we want to update our * poll event mask dynamically. Instead, let's just flush all * writes on idle */ wl_display_flush (source->display); retval = clutter_events_pending (); clutter_threads_leave (); return retval; }
// starts the thread void Worker::operator()() { StageManager::ptr manager; g_thread_init(NULL); clutter_threads_init(); int argc = 0; char **argv = NULL; if (clutter_init(&argc, &argv) != CLUTTER_INIT_SUCCESS) { std::cerr << __FUNCTION__ << "(): Error calling clutter_init()\n"; return; } clutter_threads_enter(); manager->initStage(); clutter_main(); clutter_threads_leave(); return; // done with this thread }
int main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *rect; ClutterColor stage_color = { 0xcc, 0xcc, 0xcc, 0xff }; ClutterColor rect_color = { 0xee, 0x55, 0x55, 0x99 }; ClutterColor progress_color = { 0x55, 0xee, 0x55, 0xbb }; ClutterBehaviour *r_behaviour, *p_behaviour; const ClutterKnot knots[] = { { 75, 150 }, { 400, 150 } }; g_thread_init (NULL); clutter_threads_init (); clutter_init (&argc, &argv); stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); clutter_actor_set_size (stage, 600, 300); count_label = clutter_label_new_with_text ("Mono 12", "Counter"); clutter_actor_set_position (count_label, 350, 50); help_label = clutter_label_new_with_text ("Mono 12", "Press 's' to start"); clutter_actor_set_position (help_label, 50, 50); rect = clutter_rectangle_new_with_color (&rect_color); clutter_actor_set_position (rect, 75, 150); clutter_actor_set_size (rect, 50, 50); clutter_actor_set_anchor_point (rect, 25, 25); progress_rect = clutter_rectangle_new_with_color (&progress_color); clutter_actor_set_position (progress_rect, 50, 225); clutter_actor_set_size (progress_rect, 350, 50); clutter_container_add (CLUTTER_CONTAINER (stage), count_label, help_label, rect, progress_rect, NULL); timeline = clutter_timeline_new (150, 50); clutter_timeline_set_loop (timeline, TRUE); r_behaviour = clutter_behaviour_rotate_new (clutter_alpha_new_full (timeline, CLUTTER_ALPHA_RAMP_INC, NULL, NULL), CLUTTER_Z_AXIS, CLUTTER_ROTATE_CW, 0.0, 360.0); clutter_behaviour_apply (r_behaviour, rect); p_behaviour = clutter_behaviour_path_new (clutter_alpha_new_full (timeline, CLUTTER_ALPHA_SINE, NULL, NULL), knots, G_N_ELEMENTS (knots)); clutter_behaviour_apply (p_behaviour, rect); g_signal_connect (stage, "button-press-event", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press_event), NULL); clutter_actor_show (stage); clutter_threads_enter (); clutter_main (); clutter_threads_leave (); g_object_unref (p_behaviour); g_object_unref (r_behaviour); g_object_unref (timeline); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { ClutterActor *stage; WebKitWebView *web_view; ClutterConstraint *width_binding; ClutterConstraint *height_binding; ClutterConstraint *web_view_height_binding; gfloat stageWidth, stageHeight; ClutterActorBox stageAllocation; ClutterLayoutManager *mainLayout; ClutterActor *mainLayoutContainer; ClutterLayoutManager *toolbarLayout; ClutterActor *toolbarContainer; ClutterLayoutManager *toolbarBinLayout; ClutterActor *toolbarBinContainer; ClutterActor *toolbarBgr; ClutterActor *statusBar; ClutterActor *backFwdBtns; ClutterActor *backBtn; ClutterActor *fwdBtn; ClutterActor *uriGroup; ClutterActor *uriBgr; ClutterActor *uriText; ClutterActor *spacer; GError *error = NULL; ClutterColor whiteColor = { 255, 255, 255, 255 }; ClutterColor blackColor = { 0, 0, 0, 255 }; ClutterColor grayColor = { 200, 200, 200, 255 }; ClutterColor transparentColor = { 0, 0, 0, 0 }; gchar *toolbarBgrPath = clutter_launcher_file_path("toolbar_bgr.png"); gchar *backBtnPath = clutter_launcher_file_path("back_btn.png"); gchar *fwdBtnPath = clutter_launcher_file_path("fwd_btn.png"); g_thread_init(NULL); clutter_threads_init(); clutter_init(&argc, &argv); stage = clutter_stage_get_default(); clutter_actor_set_size(stage, 1024, 768); clutter_stage_set_color(CLUTTER_STAGE(stage), &stage_color); g_signal_connect (stage, "destroy", G_CALLBACK(clutter_main_quit), NULL); /* make the stage resizable */ clutter_stage_set_user_resizable(CLUTTER_STAGE(stage), TRUE); clutter_actor_show(stage); mainLayout = clutter_box_layout_new(); clutter_box_layout_set_vertical(CLUTTER_BOX_LAYOUT(mainLayout), TRUE); clutter_actor_get_allocation_box(stage, &stageAllocation); stageWidth = stageAllocation.x2 - stageAllocation.x1; stageHeight = stageAllocation.y2 - stageAllocation.y1; web_view = WEBKIT_WEB_VIEW(webkit_web_view_new((guint)stageWidth, (guint)stageHeight - (toolbarHeight + statusBarHeight))); g_object_set(web_view, "reactive", TRUE, NULL); mainLayoutContainer = clutter_box_new(mainLayout); clutter_actor_set_size(mainLayoutContainer, stageWidth, stageHeight); width_binding = clutter_bind_constraint_new(stage, CLUTTER_BIND_WIDTH, 0); height_binding = clutter_bind_constraint_new(stage, CLUTTER_BIND_HEIGHT, 0); /* web_view_height_binding = clutter_bind_constraint_new(stage, CLUTTER_BIND_HEIGHT, -(toolbarHeight + statusBarHeight)); */ clutter_actor_add_constraint(mainLayoutContainer, width_binding); clutter_actor_add_constraint(mainLayoutContainer, height_binding); /* clutter_actor_add_constraint(CLUTTER_ACTOR(web_view), web_view_height_binding); */ toolbarBinLayout = clutter_bin_layout_new(CLUTTER_BIN_ALIGNMENT_FILL, CLUTTER_BIN_ALIGNMENT_CENTER); toolbarBinContainer = clutter_box_new(toolbarBinLayout); toolbarBgr = clutter_texture_new_from_file(toolbarBgrPath, &error); if (toolbarBgr == NULL) { fprintf(stderr, "Can't load file: %s. Aborting...\n", toolbarBgrPath); exit(1); } clutter_actor_set_height(toolbarBgr, toolbarHeight); clutter_texture_set_repeat(CLUTTER_TEXTURE(toolbarBgr), TRUE, FALSE); clutter_box_pack(CLUTTER_BOX(toolbarBinContainer), toolbarBgr, NULL, NULL); toolbarLayout = clutter_box_layout_new(); clutter_box_layout_set_vertical(CLUTTER_BOX_LAYOUT(toolbarLayout), FALSE); clutter_box_layout_set_spacing(CLUTTER_BOX_LAYOUT(toolbarLayout), 16); toolbarContainer = clutter_box_new(toolbarLayout); spacer = clutter_rectangle_new_with_color(&transparentColor); clutter_actor_set_size(spacer, 1, 1); clutter_box_pack(CLUTTER_BOX(toolbarContainer), spacer, NULL, NULL); backFwdBtns = clutter_group_new(); backBtn = clutter_texture_new_from_file(backBtnPath, &error); if (backBtn == NULL) { fprintf(stderr, "Can't load file: %s. Aborting...\n", backBtnPath); exit(1); } clutter_actor_set_reactive(backBtn, TRUE); /* connect the release event */ g_signal_connect (backBtn, "button-release-event", G_CALLBACK (on_back_release_cb), web_view); fwdBtn = clutter_texture_new_from_file(fwdBtnPath, &error); if (fwdBtn == NULL) { fprintf(stderr, "Can't load file: %s. Aborting...\n", fwdBtnPath); exit(1); } clutter_actor_set_reactive(fwdBtn, TRUE); /* connect the release event */ g_signal_connect (fwdBtn, "button-release-event", G_CALLBACK (on_fwd_release_cb), web_view); clutter_actor_set_position(fwdBtn, clutter_actor_get_width(backBtn), 0); clutter_container_add(CLUTTER_CONTAINER(backFwdBtns), backBtn, fwdBtn, NULL); clutter_box_pack(CLUTTER_BOX(toolbarContainer), backFwdBtns, NULL, NULL); uriGroup = clutter_group_new(); uriBgr = clutter_rectangle_new_with_color(&whiteColor); clutter_rectangle_set_border_color(CLUTTER_RECTANGLE(uriBgr), &blackColor); clutter_rectangle_set_border_width(CLUTTER_RECTANGLE(uriBgr), 1); clutter_actor_set_size(uriBgr, 400, 25); uriText = clutter_text_new_full("Helvetica 11px", "http://www.google.com", &blackColor); clutter_text_set_editable(CLUTTER_TEXT(uriText), TRUE); clutter_text_set_single_line_mode(CLUTTER_TEXT(uriText), TRUE); clutter_actor_set_position(uriText, 5, 7); clutter_actor_set_size(uriText, 390, 17); clutter_actor_set_reactive(uriText, TRUE); g_signal_connect(uriText, "activate", G_CALLBACK(on_uri_activate_cb), web_view); clutter_container_add(CLUTTER_CONTAINER(uriGroup), uriBgr, uriText, NULL); clutter_box_pack(CLUTTER_BOX(toolbarContainer), uriGroup, NULL, NULL); clutter_box_pack(CLUTTER_BOX(toolbarBinContainer), toolbarContainer, NULL, NULL); clutter_box_pack(CLUTTER_BOX(mainLayoutContainer), toolbarBinContainer, "y-align", CLUTTER_BOX_ALIGNMENT_START, NULL); clutter_box_layout_set_expand(CLUTTER_BOX_LAYOUT(mainLayout), toolbarBinContainer, TRUE); clutter_box_layout_set_fill(CLUTTER_BOX_LAYOUT(mainLayout), toolbarBinContainer, TRUE, FALSE); statusBar = clutter_rectangle_new_with_color(&grayColor); clutter_actor_set_height(statusBar, statusBarHeight); clutter_box_pack(CLUTTER_BOX(mainLayoutContainer), statusBar, "y-align", CLUTTER_BOX_ALIGNMENT_END, NULL); clutter_box_layout_set_expand(CLUTTER_BOX_LAYOUT(mainLayout), statusBar, TRUE); clutter_box_layout_set_fill(CLUTTER_BOX_LAYOUT(mainLayout), statusBar, TRUE, FALSE); clutter_box_pack_after(CLUTTER_BOX(mainLayoutContainer), CLUTTER_ACTOR(web_view), toolbarBinContainer, "y-align", CLUTTER_BOX_ALIGNMENT_START, NULL); clutter_box_layout_set_expand(CLUTTER_BOX_LAYOUT(mainLayout), CLUTTER_ACTOR(web_view), TRUE); clutter_box_layout_set_fill(CLUTTER_BOX_LAYOUT(mainLayout), CLUTTER_ACTOR(web_view), TRUE, TRUE); clutter_container_add(CLUTTER_CONTAINER(stage), mainLayoutContainer, NULL); g_signal_connect(web_view, "webkit-load-finished", G_CALLBACK(load_finished_cb), web_view); g_signal_connect(web_view, "notify::progress", G_CALLBACK (notify_progress_cb), web_view); /* g_signal_connect(stage, "delete-event", G_CALLBACK(delete_cb), web_view);*/ g_signal_connect(web_view, "notify::uri", G_CALLBACK(notify_uri_cb), uriText); gchar *uri = (gchar*) (argc > 1 ? argv[1] : "http://www.google.com/"); gchar *fileURL = filenameToURL(uri); webkit_web_view_load_uri(web_view, fileURL ? fileURL : uri); printf("%s\n", fileURL ? fileURL : uri); g_free(fileURL); g_timeout_add_full(G_PRIORITY_DEFAULT, 3000, timeout_cb, web_view, 0); clutter_threads_enter (); clutter_main(); clutter_threads_leave (); return EXIT_SUCCESS; }
IO_METHOD(IoClutter, threadLeave) { clutter_threads_leave(); return self; }
/** * clutter_x11_handle_event: * @xevent: pointer to XEvent structure * * This function processes a single X event; it can be used to hook * into external X event retrieval (for example that done by GDK). * * 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) { ClutterBackend *backend; ClutterBackendX11Class *backend_x11_class; ClutterEvent *event; ClutterMainContext *clutter_context; ClutterX11FilterReturn result; gint spin = 1; /* 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_enter (); clutter_context = _clutter_context_get_default (); backend = clutter_context->backend; backend_x11_class = CLUTTER_BACKEND_X11_GET_CLASS (backend); /* If the backend just observed the event and didn't want it * removed it could return FALSE, so assume that a TRUE return * means that our caller should also do no further processing. */ if (backend_x11_class->handle_event (CLUTTER_BACKEND_X11(backend), xevent)) return CLUTTER_X11_FILTER_REMOVE; event = clutter_event_new (CLUTTER_NOTHING); if (event_translate (backend, event, xevent)) { /* push directly here to avoid copy of queue_put */ result = CLUTTER_X11_FILTER_REMOVE; g_queue_push_head (clutter_context->events_queue, event); } 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_do_event (event); clutter_event_free (event); --spin; } out: clutter_threads_leave (); return result; }
static gboolean clutter_clock_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClock *master_clock = clock_source->master_clock; ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); gboolean stages_updated = FALSE; GSList *stages, *l; CLUTTER_STATIC_TIMER (master_dispatch_timer, "Mainloop", "Master Clock", "Master clock dispatch", 0); CLUTTER_STATIC_TIMER (master_event_process, "Master Clock", "Event Processing", "The time spent processing events on all stages", 0); CLUTTER_TIMER_START (_clutter_uprof_context, master_dispatch_timer); CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); clutter_threads_enter (); /* Get the time to use for this frame */ #if GLIB_CHECK_VERSION (2, 27, 3) master_clock->cur_tick = g_source_get_time (source); #else { GTimeVal source_time; g_source_get_current_time (source, &source_time); master_clock->cur_tick = source_time.tv_sec * 1000000L + source_time.tv_usec; } #endif /* We need to protect ourselves against stages being destroyed during * event handling */ stages = clutter_stage_manager_list_stages (stage_manager); g_slist_foreach (stages, (GFunc) g_object_ref, NULL); CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process); master_clock->idle = FALSE; /* Process queued events */ for (l = stages; l != NULL; l = l->next) { /* NB: If a stage is busy waiting for a swap-buffers completion then * we don't process its events so we can maximize the benefits of * motion compression, and avoid multiple picks per frame. */ if (_clutter_stage_get_pending_swaps (l->data) == 0) _clutter_stage_process_queued_events (l->data); } CLUTTER_TIMER_STOP (_clutter_uprof_context, master_event_process); _clutter_master_clock_advance (master_clock); _clutter_run_repaint_functions (); /* Update any stage that needs redraw/relayout after the clock * is advanced. */ for (l = stages; l != NULL; l = l->next) { /* If a stage has a swap-buffers pending we don't want to draw to it * in case the driver may block the CPU while it waits for the next * backbuffer to become available. * * TODO: We should be able to identify if we are running triple or N * buffered and in these cases we can still draw if there is 1 swap * pending so we can hopefully always be ready to swap for the next * vblank and really match the vsync frequency. */ if (_clutter_stage_get_pending_swaps (l->data) == 0) stages_updated |= _clutter_stage_do_update (l->data); } /* 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; g_slist_foreach (stages, (GFunc) g_object_unref, NULL); g_slist_free (stages); master_clock->prev_tick = master_clock->cur_tick; clutter_threads_leave (); CLUTTER_TIMER_STOP (_clutter_uprof_context, master_dispatch_timer); return TRUE; }
int main (int argc, char *argv[]) { GLenum err = 0; #ifdef WIN32 HGLRC clutter_gl_context = 0; HDC clutter_dc = 0; #else Display *clutter_display = NULL; Window clutter_win = 0; GLXContext clutter_gl_context = NULL; #endif GstPipeline *pipeline = NULL; GstBus *bus = NULL; GstElement *glupload = NULL; GstState state = 0; ClutterActor *stage = NULL; ClutterActor *clutter_texture = NULL; GAsyncQueue *queue_input_buf = NULL; GAsyncQueue *queue_output_buf = NULL; GstElement *fakesink = NULL; /* init gstreamer then clutter */ gst_init (&argc, &argv); clutter_threads_init (); clutter_init (&argc, &argv); clutter_threads_enter (); g_print ("clutter version: %s\n", CLUTTER_VERSION_S); /* init glew */ err = glewInit (); if (err != GLEW_OK) g_debug ("failed to init GLEW: %s", glewGetErrorString (err)); /* avoid to dispatch unecesary events */ clutter_ungrab_keyboard (); clutter_ungrab_pointer (); /* retrieve and turn off clutter opengl context */ stage = clutter_stage_get_default (); /* retrieve and turn off clutter opengl context */ #ifdef WIN32 clutter_gl_context = wglGetCurrentContext (); clutter_dc = wglGetCurrentDC (); wglMakeCurrent (0, 0); #else clutter_display = clutter_x11_get_default_display (); clutter_win = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); clutter_gl_context = glXGetCurrentContext (); glXMakeCurrent (clutter_display, None, 0); #endif /* setup gstreamer pipeline */ pipeline = GST_PIPELINE (gst_parse_launch ("videotestsrc ! video/x-raw-yuv, width=320, height=240, framerate=(fraction)30/1 ! " "glupload ! gleffects effect=5 ! glfiltercube ! fakesink sync=1", NULL)); /* setup bus */ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message::error", G_CALLBACK (end_stream_cb), NULL); g_signal_connect (bus, "message::warning", G_CALLBACK (end_stream_cb), NULL); g_signal_connect (bus, "message::eos", G_CALLBACK (end_stream_cb), NULL); gst_object_unref (bus); /* clutter_gl_context is an external OpenGL context with which gst-plugins-gl want to share textures */ glupload = gst_bin_get_by_name (GST_BIN (pipeline), "glupload0"); g_object_set (G_OBJECT (glupload), "external-opengl-context", clutter_gl_context, NULL); g_object_unref (glupload); /* NULL to PAUSED state pipeline to make sure the gst opengl context is created and * shared with the clutter one */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED); state = GST_STATE_PAUSED; if (gst_element_get_state (GST_ELEMENT (pipeline), &state, NULL, GST_CLOCK_TIME_NONE) != GST_STATE_CHANGE_SUCCESS) { g_debug ("failed to pause pipeline\n"); return -1; } /* turn on back clutter opengl context */ #ifdef WIN32 wglMakeCurrent (clutter_dc, clutter_gl_context); #else glXMakeCurrent (clutter_display, clutter_win, clutter_gl_context); #endif /* clutter stage */ clutter_actor_set_size (stage, 640, 480); clutter_actor_set_position (stage, 0, 0); clutter_stage_set_title (CLUTTER_STAGE (stage), "clutter and gst-plugins-gl"); clutter_texture = setup_stage (CLUTTER_STAGE (stage)); /* append a gst-gl texture to this queue when you do not need it no more */ queue_input_buf = g_async_queue_new (); queue_output_buf = g_async_queue_new (); g_object_set_data (G_OBJECT (clutter_texture), "queue_input_buf", queue_input_buf); g_object_set_data (G_OBJECT (clutter_texture), "queue_output_buf", queue_output_buf); /* set a callback to retrieve the gst gl textures */ fakesink = gst_bin_get_by_name (GST_BIN (pipeline), "fakesink0"); g_object_set (G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL); g_signal_connect (fakesink, "handoff", G_CALLBACK (on_gst_buffer), clutter_texture); g_object_unref (fakesink); /* play gst */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); /* main loop */ clutter_main (); /* before to deinitialize the gst-gl-opengl context, * no shared context (here the clutter one) must be current */ #ifdef WIN32 wglMakeCurrent (0, 0); #else glXMakeCurrent (clutter_display, None, 0); #endif clutter_threads_leave (); /* stop and clean up the pipeline */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); g_object_unref (pipeline); /* make sure there is no pending gst gl buffer in the communication queues * between clutter and gst-gl */ while (g_async_queue_length (queue_input_buf) > 0) { GstBuffer *buf = g_async_queue_pop (queue_input_buf); gst_buffer_unref (buf); } while (g_async_queue_length (queue_output_buf) > 0) { GstBuffer *buf = g_async_queue_pop (queue_output_buf); gst_buffer_unref (buf); } return 0; }