static void _stage_added (ClutterStageManager *manager, ClutterStage *stage, gpointer data) { Window xid = clutter_x11_get_stage_window (stage); if (xid != None) { XSelectInput (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xid, StructureNotifyMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | ExposureMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask); gdk_window_add_filter (NULL, gdk_to_clutter_event_pump__, GINT_TO_POINTER (xid)); } else { g_signal_connect_after (stage, "realize", G_CALLBACK (_stage_realized), NULL); } }
/** * shell_global_grab_keyboard: * @global: a #ShellGlobal * * Grab the keyboard to the stage window. The stage will receive * all keyboard events until shell_global_ungrab_keyboard() is called. * This is appropriate to do when the desktop goes into a special * mode where no normal global key shortcuts or application keyboard * processing should happen. */ gboolean shell_global_grab_keyboard (ShellGlobal *global) { MetaScreen *screen = mutter_plugin_get_screen (global->plugin); MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); ClutterStage *stage = CLUTTER_STAGE (mutter_plugin_get_stage (global->plugin)); Window stagewin = clutter_x11_get_stage_window (stage); /* FIXME: we need to coordinate with the rest of Metacity or we * may grab the keyboard away from other portions of Metacity * and leave Metacity in a confused state. An X client is allowed * to overgrab itself, though not allowed to grab they keyboard * away from another applications. */ if (global->keyboard_grabbed) return FALSE; if (XGrabKeyboard (xdisplay, stagewin, False, /* owner_events - steal events from the rest of metacity */ GrabModeAsync, GrabModeAsync, CurrentTime) != Success) return FALSE; /* probably AlreadyGrabbed, some other app has a keyboard grab */ global->keyboard_grabbed = TRUE; return TRUE; }
void meta_compositor_sync_screen_size (MetaCompositor *compositor, MetaScreen *screen, guint width, guint height) { MetaDisplay *display = meta_screen_get_display (screen); MetaCompScreen *info = meta_screen_get_compositor_data (screen); Display *xdisplay; Window xwin; DEBUG_TRACE ("meta_compositor_sync_screen_size\n"); g_return_if_fail (info); xdisplay = meta_display_get_xdisplay (display); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); XResizeWindow (xdisplay, xwin, width, height); meta_background_actor_screen_size_changed (screen); meta_verbose ("Changed size for stage on screen %d to %dx%d\n", meta_screen_get_screen_number (screen), width, height); }
void meta_set_stage_input_region (MetaScreen *screen, XserverRegion region) { /* As a wayland compositor we can simply ignore all this trickery * for setting an input region on the stage for capturing events in * clutter since all input comes to us first and we get to choose * who else sees them. */ if (!meta_is_wayland_compositor ()) { MetaDisplay *display = screen->display; MetaCompositor *compositor = display->compositor; Display *xdpy = meta_display_get_xdisplay (display); Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); /* It's generally a good heuristic that when a crossing event is generated because * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - * it's not the user doing something, it's the environment changing under the user. */ meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); XFixesSetWindowShapeRegion (xdpy, compositor->output, ShapeInput, 0, 0, region); } }
/* Class functions */ gboolean scim_bridge_client_imcontext_filter_key_event (ClutterIMContext *context, ClutterKeyEvent *event) { scim_bridge_pdebugln (8, "scim_bridge_client_imcontext_filter_key_event ()"); ScimBridgeClientIMContext *imcontext = SCIM_BRIDGE_CLIENT_IMCONTEXT (context); if (scim_bridge_client_is_messenger_opened () && imcontext != NULL ) { if (context->actor != NULL) { ClutterActor *stage = clutter_actor_get_stage (context->actor); Window current_window, root, parent, *childs; unsigned int nchild; XWindowAttributes winattr; Display *xdpy; int new_window_x; int new_window_y; clutter_actor_get_transformed_position (context->actor, &new_window_x, &new_window_y); xdpy = clutter_x11_get_default_display (); current_window = clutter_x11_get_stage_window(CLUTTER_STAGE(stage)); while(1) { XGetWindowAttributes (xdpy, current_window, &winattr); new_window_x += winattr.x; new_window_y += winattr.y; XQueryTree(xdpy, current_window, &root, &parent, &childs, &nchild); current_window = parent; if (root == parent) break; } if (imcontext->window_x != new_window_x || imcontext->window_y != new_window_y) { imcontext->window_x = new_window_x; imcontext->window_y = new_window_y; scim_bridge_pdebugln (1, "The cursor location is changed: x = %d + %d\ty = %d + %d", imcontext->window_x, imcontext->cursor_x, imcontext->window_y, imcontext->cursor_y); if (set_cursor_location (imcontext, new_window_x, new_window_y, imcontext->cursor_x, imcontext->cursor_y)) { scim_bridge_perrorln ("An IOException occurred at scim_bridge_client_imcontext_filter_key_event ()"); return clutter_im_context_filter_keypress (fallback_imcontext, event); } } } boolean consumed = FALSE; if (filter_key_event (imcontext, event, &consumed)) { scim_bridge_perrorln ("An IOException occurred at scim_bridge_client_imcontext_filter_key_event ()"); } else if (consumed) { return TRUE; } } if (imcontext == NULL || !imcontext->enabled) { return clutter_im_context_filter_keypress (fallback_imcontext, event); } return FALSE; }
/** * shell_global_begin_modal: * @global: a #ShellGlobal * * Grabs the keyboard and mouse to the stage window. The stage will * receive all keyboard and mouse events until shell_global_end_modal() * is called. This is used to implement "modes" for the shell, such as the * overview mode or the "looking glass" debug overlay, that block * application and normal key shortcuts. * * Returns value: %TRUE if we succesfully entered the mode. %FALSE if we couldn't * enter the mode. Failure may occur because an application has the pointer * or keyboard grabbed, because Mutter is in a mode itself like moving a * window or alt-Tab window selection, or because shell_global_begin_modal() * was previouly called. */ gboolean shell_global_begin_modal (ShellGlobal *global, guint32 timestamp) { ClutterStage *stage = CLUTTER_STAGE (mutter_plugin_get_stage (global->plugin)); Window stagewin = clutter_x11_get_stage_window (stage); return mutter_plugin_begin_modal (global->plugin, stagewin, None, 0, timestamp); }
static void _set_cursor_location_internal(FcitxIMContext *fcitxcontext) { ClutterIMContext* context = CLUTTER_IM_CONTEXT(fcitxcontext); ClutterActor *stage = clutter_actor_get_stage (context->actor); Window current_window, root, parent, *childs; unsigned int nchild; XWindowAttributes winattr; Display *xdpy; float fx, fy; gint x, y; if (!stage) return; clutter_actor_get_transformed_position (context->actor, &fx, &fy); x = fx; y = fy; xdpy = clutter_x11_get_default_display (); current_window = clutter_x11_get_stage_window(CLUTTER_STAGE(stage)); if (!xdpy || !current_window) return; while(1) { XGetWindowAttributes (xdpy, current_window, &winattr); x += winattr.x; y += winattr.y; XQueryTree(xdpy, current_window, &root, &parent, &childs, &nchild); current_window = parent; if (root == parent) break; } if (fcitxcontext->area.x != x || fcitxcontext->area.y != y) { fcitxcontext->area.x = x; fcitxcontext->area.y = y; } if (context->actor == NULL || !IsFcitxIMClientValid(fcitxcontext->client)) { return; } ClutterIMRectangle area = fcitxcontext->area; if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) { area.y = 0; area.x = 0; } FcitxIMClientSetCursorLocation(fcitxcontext->client, area.x, area.y + area.height); return; }
static void mpl_panel_clutter_ensure_window (MplPanelClutter *panel) { MplPanelClutterPrivate *priv = panel->priv; Window xwin = None; Display *xdpy; gint32 myint; Atom atom1, atom2; if (priv->xwindow) return; xdpy = clutter_x11_get_default_display (); clutter_actor_realize (priv->stage); priv->xwindow = xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (priv->stage)); g_object_set (panel, "xid", xwin, NULL); if (priv->needs_gdk_pump) mpl_panel_clutter_setup_events_with_gtk_for_xid (xwin); if (!mpl_utils_panel_in_standalone_mode ()) { MPL_X_ERROR_TRAP (); /* * Make dock, sticky and position at the correct place. */ atom1 = XInternAtom(xdpy, "_NET_WM_WINDOW_TYPE", False); atom2 = XInternAtom(xdpy, "_NET_WM_WINDOW_TYPE_DOCK", False); XChangeProperty (xdpy, xwin, atom1, XA_ATOM, 32, PropModeReplace, (unsigned char *) &atom2, 1); atom1 = XInternAtom(xdpy, "_NET_WM_DESKTOP", False); myint = -1; XChangeProperty (xdpy, xwin, atom1, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &myint, 1); XSync (xdpy, False); MPL_X_ERROR_UNTRAP (); } }
static void do_set_stage_input_region (MetaScreen *screen, XserverRegion region) { MetaCompScreen *info = meta_screen_get_compositor_data (screen); MetaDisplay *display = meta_screen_get_display (screen); Display *xdpy = meta_display_get_xdisplay (display); Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); /* It's generally a good heuristic that when a crossing event is generated because * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - * it's not the user doing something, it's the environment changing under the user. */ meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region); }
static ClutterX11FilterReturn xfixes_cursor_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data) { ShellXFixesCursor *xfixes_cursor = data; if (xev->xany.window != clutter_x11_get_stage_window (xfixes_cursor->stage)) return CLUTTER_X11_FILTER_CONTINUE; if (xev->xany.type == xfixes_cursor->xfixes_event_base + XFixesCursorNotify) { XFixesCursorNotifyEvent *notify_event = (XFixesCursorNotifyEvent *)xev; if (notify_event->subtype == XFixesDisplayCursorNotify) xfixes_cursor_reset_image (xfixes_cursor); } return CLUTTER_X11_FILTER_CONTINUE; }
/* This is an IBus workaround. The flow of events with IBus is that every time * it gets gets a key event, it: * * Sends it to the daemon via D-Bus asynchronously * When it gets an reply, synthesizes a new GdkEvent and puts it into the * GDK event queue with gdk_event_put(), including * IBUS_FORWARD_MASK = 1 << 25 in the state to prevent a loop. * * (Normally, IBus uses the GTK+ key snooper mechanism to get the key * events early, but since our key events aren't visible to GTK+ key snoopers, * IBus will instead get the events via the standard * GtkIMContext.filter_keypress() mechanism.) * * There are a number of potential problems here; probably the worst * problem is that IBus doesn't forward the timestamp with the event * so that every key event that gets delivered ends up with * GDK_CURRENT_TIME. This creates some very subtle bugs; for example * if you have IBus running and a keystroke is used to trigger * launching an application, focus stealing prevention won't work * right. http://code.google.com/p/ibus/issues/detail?id=1184 * * In any case, our normal flow of key events is: * * GDK filter function => clutter_x11_handle_event => clutter actor * * So, if we see a key event that gets delivered via the GDK event handler * function - then we know it must be one of these synthesized events, and * we should push it back to clutter. * * To summarize, the full key event flow with IBus is: * * GDK filter function * => Mutter * => gnome_cinnamon_plugin_xevent_filter() * => clutter_x11_handle_event() * => clutter event delivery to actor * => gtk_im_context_filter_event() * => sent to IBus daemon * => response received from IBus daemon * => gdk_event_put() * => GDK event handler * => <this function> * => clutter_event_put() * => clutter event delivery to actor * * Anything else we see here we just pass on to the normal GDK event handler * gtk_main_do_event(). */ static void gnome_cinnamon_gdk_event_handler (GdkEvent *event_gdk, gpointer data) { if (event_gdk->type == GDK_KEY_PRESS || event_gdk->type == GDK_KEY_RELEASE) { ClutterActor *stage; Window stage_xwindow; stage = clutter_stage_get_default (); stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); if (GDK_WINDOW_XID (event_gdk->key.window) == stage_xwindow) { ClutterDeviceManager *device_manager = clutter_device_manager_get_default (); ClutterInputDevice *keyboard = clutter_device_manager_get_core_device (device_manager, CLUTTER_KEYBOARD_DEVICE); ClutterEvent *event_clutter = clutter_event_new ((event_gdk->type == GDK_KEY_PRESS) ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE); event_clutter->key.time = event_gdk->key.time; event_clutter->key.flags = CLUTTER_EVENT_NONE; event_clutter->key.stage = CLUTTER_STAGE (stage); event_clutter->key.source = NULL; /* This depends on ClutterModifierType and GdkModifierType being * identical, which they are currently. (They both match the X * modifier state in the low 16-bits and have the same extensions.) */ event_clutter->key.modifier_state = event_gdk->key.state; event_clutter->key.keyval = event_gdk->key.keyval; event_clutter->key.hardware_keycode = event_gdk->key.hardware_keycode; event_clutter->key.unicode_value = gdk_keyval_to_unicode (event_clutter->key.keyval); event_clutter->key.device = keyboard; clutter_event_put (event_clutter); clutter_event_free (event_clutter); return; } } gtk_main_do_event (event_gdk); }
static gboolean handle_xembed_event (ClutterBackendX11 *backend_x11, XEvent *xevent) { ClutterActor *stage; stage = clutter_stage_get_default (); switch (xevent->xclient.data.l[1]) { case XEMBED_EMBEDDED_NOTIFY: CLUTTER_NOTE (EVENT, "got XEMBED_EMBEDDED_NOTIFY from %lx", xevent->xclient.data.l[3]); ParentEmbedderWin = xevent->xclient.data.l[3]; clutter_actor_realize (stage); clutter_actor_show (stage); xembed_set_info (backend_x11, clutter_x11_get_stage_window (CLUTTER_STAGE (stage)), XEMBED_MAPPED); break; case XEMBED_WINDOW_ACTIVATE: CLUTTER_NOTE (EVENT, "got XEMBED_WINDOW_ACTIVATE"); break; case XEMBED_WINDOW_DEACTIVATE: CLUTTER_NOTE (EVENT, "got XEMBED_WINDOW_DEACTIVATE"); break; case XEMBED_FOCUS_IN: CLUTTER_NOTE (EVENT, "got XEMBED_FOCUS_IN"); if (ParentEmbedderWin) xembed_send_message (backend_x11, ParentEmbedderWin, XEMBED_FOCUS_NEXT, 0, 0, 0); break; default: CLUTTER_NOTE (EVENT, "got unknown XEMBED message"); break; } /* do not propagate the XEMBED events to the stage */ return FALSE; }
static void set_above_and_fullscreen (void) { Display *dpy = clutter_x11_get_default_display (); Window win = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); char *atom_names[2] = { "_NET_WM_STATE_FULLSCREEN", "_NET_WM_STATE_ABOVE", }; Atom states[G_N_ELEMENTS (atom_names)]; XInternAtoms (dpy, atom_names, G_N_ELEMENTS (atom_names), False, states); XChangeProperty (dpy, win, XInternAtom (dpy, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *) states, G_N_ELEMENTS (atom_names)); }
/* Returns a new reference to window */ static GdkWindow * window_for_actor (ClutterActor *actor) { GdkDisplay *display = gdk_display_get_default (); ClutterActor *stage; Window xwindow; GdkWindow *window; stage = clutter_actor_get_stage (actor); xwindow = clutter_x11_get_stage_window ((ClutterStage *)stage); window = gdk_x11_window_lookup_for_display (display, xwindow); if (window) g_object_ref (window); else window = gdk_x11_window_foreign_new_for_display (display, xwindow); return window; }
void cinnamon_tray_manager_manage_stage (CinnamonTrayManager *manager, ClutterStage *stage, StWidget *theme_widget) { Window stage_xwindow; GdkWindow *stage_window; GdkDisplay *display; GdkScreen *screen; g_return_if_fail (manager->priv->stage == NULL); manager->priv->stage = g_object_ref (stage); stage_xwindow = clutter_x11_get_stage_window (stage); /* This is a pretty ugly way to get the GdkScreen for the stage; it * will normally go through the foreign_new() case with a * round-trip to the X server, it might be nicer to pass the screen * in in some way. (The Clutter/Muffin combo is currently incapable * of multi-screen operation, so alternatively we could just assume * that clutter_x11_get_default_screen() gives us the right * screen.) We assume, in any case, that we are using the default * GDK display. */ display = gdk_display_get_default(); stage_window = gdk_x11_window_lookup_for_display (display, stage_xwindow); if (stage_window) g_object_ref (stage_window); else stage_window = gdk_x11_window_foreign_new_for_display (display, stage_xwindow); screen = gdk_window_get_screen (stage_window); g_object_unref (stage_window); na_tray_manager_manage_screen (manager->priv->na_manager, screen); g_signal_connect (theme_widget, "style-changed", G_CALLBACK (cinnamon_tray_manager_style_changed), manager); cinnamon_tray_manager_style_changed (theme_widget, manager); }
static void shell_embedded_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (object); switch (prop_id) { case PROP_STAGE: window->priv->stage_xwindow = clutter_x11_get_stage_window (g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
gboolean meta_stage_is_focused (MetaScreen *screen) { ClutterStage *stage; Window window; if (meta_is_wayland_compositor ()) return TRUE; stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen)); if (!stage) return FALSE; window = clutter_x11_get_stage_window (stage); if (window == None) return FALSE; return (screen->display->focus_xwindow == window); }
static void setup_standalone (DawatiStatusPanel *status_panel) { ClutterActor *stage, *status; Window xwin; status = make_status (status_panel); clutter_actor_set_size (status, 1000, 600); stage = clutter_stage_new (); clutter_actor_set_size (stage, 1000, 600); clutter_container_add_actor (CLUTTER_CONTAINER (stage), status); clutter_actor_realize (stage); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); mpl_panel_clutter_setup_events_with_gtk_for_xid (xwin); clutter_actor_show (stage); }
void meta_focus_stage_window (MetaScreen *screen, guint32 timestamp) { ClutterStage *stage; Window window; stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen)); if (!stage) return; window = clutter_x11_get_stage_window (stage); if (window == None) return; meta_display_set_input_focus_xwindow (screen->display, screen, window, timestamp); }
static void xfixes_cursor_hide (ShellXFixesCursor *xfixes_cursor) { int minor, major; Display *xdisplay; Window xwindow; if (xfixes_cursor->is_showing == FALSE) return; if (!xfixes_cursor->have_xfixes || !xfixes_cursor->stage) return; xdisplay = clutter_x11_get_default_display (); xwindow = clutter_x11_get_stage_window (xfixes_cursor->stage); XFixesQueryVersion (xdisplay, &major, &minor); if (major >= 4) { XFixesHideCursor (xdisplay, xwindow); xfixes_cursor->is_showing = FALSE; } }
ScreenSaver * screensaver_new (ClutterStage * stage) { ScreenSaver *screensaver; screensaver = g_new0 (ScreenSaver, 1); screensaver->disabled = FALSE; screensaver->stage = stage; #if HAVE_X11 screensaver->display = clutter_x11_get_default_display (); screensaver->window = clutter_x11_get_stage_window (stage); screensaver_init_x11 (screensaver); #endif #ifdef ENABLE_DBUS screensaver_init_dbus (screensaver); #endif return screensaver; }
static void xfixes_cursor_set_stage (ShellXFixesCursor *xfixes_cursor, ClutterStage *stage) { if (xfixes_cursor->stage == stage) return; if (xfixes_cursor->stage) { g_signal_handlers_disconnect_by_func (xfixes_cursor->stage, (void *)xfixes_cursor_on_stage_destroy, xfixes_cursor); clutter_x11_remove_filter (xfixes_cursor_event_filter, xfixes_cursor); } xfixes_cursor->stage = stage; if (xfixes_cursor->stage) { int error_base; xfixes_cursor->stage = stage; g_signal_connect (xfixes_cursor->stage, "destroy", G_CALLBACK (xfixes_cursor_on_stage_destroy), xfixes_cursor); clutter_x11_add_filter (xfixes_cursor_event_filter, xfixes_cursor); xfixes_cursor->have_xfixes = XFixesQueryExtension (clutter_x11_get_default_display (), &xfixes_cursor->xfixes_event_base, &error_base); if (xfixes_cursor->have_xfixes) XFixesSelectCursorInput (clutter_x11_get_default_display (), clutter_x11_get_stage_window (stage), XFixesDisplayCursorNotifyMask); xfixes_cursor_reset_image (xfixes_cursor); } }
void meta_compositor_sync_screen_size (MetaCompositor *compositor, guint width, guint height) { MetaDisplay *display = compositor->display; if (meta_is_wayland_compositor ()) { /* FIXME: when we support a sliced stage, this is the place to do it But! This is not the place to apply KMS config, here we only notify Clutter/Cogl/GL that the framebuffer sizes changed. And because for now clutter does not do sliced, we use one framebuffer the size of the whole screen, and when running on bare metal MetaMonitorManager will do the necessary tricks to show the right portions on the right screens. */ clutter_actor_set_size (compositor->stage, width, height); } else { Display *xdisplay; Window xwin; xdisplay = meta_display_get_xdisplay (display); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); XResizeWindow (xdisplay, xwin, width, height); } meta_verbose ("Changed size for stage on screen %d to %dx%d\n", meta_screen_get_screen_number (display->screen), width, height); }
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; }
void meta_compositor_manage_screen (MetaCompositor *compositor, MetaScreen *screen) { MetaCompScreen *info; MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); int screen_number = meta_screen_get_screen_number (screen); Window xroot = meta_screen_get_xroot (screen); Window xwin; gint width, height; XWindowAttributes attr; long event_mask; guint n_retries; guint max_retries; /* Check if the screen is already managed */ if (meta_screen_get_compositor_data (screen)) return; if (meta_get_replace_current_wm ()) max_retries = 5; else max_retries = 1; n_retries = 0; /* Some compositors (like old versions of Muffin) might not properly unredirect * subwindows before destroying the WM selection window; so we wait a while * for such a compositor to exit before giving up. */ while (TRUE) { meta_error_trap_push_with_return (display); XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual); XSync (xdisplay, FALSE); if (!meta_error_trap_pop_with_return (display)) break; if (n_retries == max_retries) { /* This probably means that a non-WM compositor like xcompmgr is running; * we have no way to get it to exit */ meta_fatal (_("Another compositing manager is already running on screen %i on display \"%s\"."), screen_number, display->name); } n_retries++; g_usleep (G_USEC_PER_SEC); } info = g_new0 (MetaCompScreen, 1); /* * We use an empty input region for Clutter as a default because that allows * the user to interact with all the windows displayed on the screen. * We have to initialize info->pending_input_region to an empty region explicitly, * because None value is used to mean that the whole screen is an input region. */ info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0); info->screen = screen; meta_screen_set_compositor_data (screen, info); info->output = None; info->windows = NULL; meta_screen_set_cm_selection (screen); info->stage = clutter_stage_new (); meta_screen_get_size (screen, &width, &height); clutter_actor_realize (info->stage); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); XResizeWindow (xdisplay, xwin, width, height); event_mask = FocusChangeMask | ExposureMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PropertyChangeMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask; if (XGetWindowAttributes (xdisplay, xwin, &attr)) { event_mask |= attr.your_event_mask; } XSelectInput (xdisplay, xwin, event_mask); info->window_group = meta_window_group_new (screen); info->background_actor = meta_background_actor_new_for_screen (screen); info->bottom_window_group = clutter_group_new(); info->overlay_group = clutter_group_new (); info->top_window_group = meta_window_group_new (screen); info->hidden_group = clutter_group_new (); clutter_container_add (CLUTTER_CONTAINER (info->window_group), info->background_actor, NULL); clutter_container_add (CLUTTER_CONTAINER (info->stage), info->window_group, info->overlay_group, info->hidden_group, NULL); clutter_actor_hide (info->hidden_group); info->plugin_mgr = meta_plugin_manager_get (screen); meta_plugin_manager_initialize (info->plugin_mgr); /* * Delay the creation of the overlay window as long as we can, to avoid * blanking out the screen. This means that during the plugin loading, the * overlay window is not accessible; if the plugin needs to access it * directly, it should hook into the "show" signal on stage, and do * its stuff there. */ info->output = get_output_window (screen); XReparentWindow (xdisplay, xwin, info->output, 0, 0); /* Make sure there isn't any left-over output shape on the * overlay window by setting the whole screen to be an * output region. * * Note: there doesn't seem to be any real chance of that * because the X server will destroy the overlay window * when the last client using it exits. */ XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); do_set_stage_input_region (screen, info->pending_input_region); if (info->pending_input_region != None) { XFixesDestroyRegion (xdisplay, info->pending_input_region); info->pending_input_region = None; } clutter_actor_show (info->overlay_group); clutter_actor_show (info->stage); }
Window meta_backend_x11_get_xwindow (MetaBackendX11 *x11) { ClutterActor *stage = meta_backend_get_stage (META_BACKEND (x11)); return clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); }
void meta_compositor_manage (MetaCompositor *compositor) { MetaDisplay *display = compositor->display; Display *xdisplay = display->xdisplay; MetaScreen *screen = display->screen; Window xwin = 0; gint width, height; meta_screen_set_cm_selection (display->screen); if (meta_is_wayland_compositor ()) { MetaWaylandCompositor *wayland_compositor = meta_wayland_compositor_get_default (); compositor->stage = meta_stage_new (); wayland_compositor->stage = compositor->stage; meta_screen_get_size (screen, &width, &height); clutter_actor_set_size (compositor->stage, width, height); clutter_actor_show (compositor->stage); } else { compositor->stage = clutter_stage_new (); meta_screen_get_size (screen, &width, &height); clutter_actor_realize (compositor->stage); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); XResizeWindow (xdisplay, xwin, width, height); { MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ()); Display *backend_xdisplay = meta_backend_x11_get_xdisplay (backend); unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; XISetMask (mask.mask, XI_KeyPress); XISetMask (mask.mask, XI_KeyRelease); XISetMask (mask.mask, XI_ButtonPress); XISetMask (mask.mask, XI_ButtonRelease); XISetMask (mask.mask, XI_Enter); XISetMask (mask.mask, XI_Leave); XISetMask (mask.mask, XI_FocusIn); XISetMask (mask.mask, XI_FocusOut); XISetMask (mask.mask, XI_Motion); XIClearMask (mask.mask, XI_TouchBegin); XIClearMask (mask.mask, XI_TouchEnd); XIClearMask (mask.mask, XI_TouchUpdate); XISelectEvents (backend_xdisplay, xwin, &mask, 1); } } /* We use connect_after() here to accomodate code in GNOME Shell that, * when benchmarking drawing performance, connects to ::after-paint * and calls glFinish(). The timing information from that will be * more accurate if we hold off until that completes before we signal * apps to begin drawing the next frame. If there are no other * connections to ::after-paint, connect() vs. connect_after() doesn't * matter. */ g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint", G_CALLBACK (after_stage_paint), compositor); clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY); compositor->window_group = meta_window_group_new (screen); compositor->top_window_group = meta_window_group_new (screen); clutter_actor_add_child (compositor->stage, compositor->window_group); clutter_actor_add_child (compositor->stage, compositor->top_window_group); if (meta_is_wayland_compositor ()) { /* NB: When running as a wayland compositor we don't need an X * composite overlay window, and we don't need to play any input * region tricks to redirect events into clutter. */ compositor->output = None; } else { compositor->output = screen->composite_overlay_window; XReparentWindow (xdisplay, xwin, compositor->output, 0, 0); meta_empty_stage_input_region (screen); /* Make sure there isn't any left-over output shape on the * overlay window by setting the whole screen to be an * output region. * * Note: there doesn't seem to be any real chance of that * because the X server will destroy the overlay window * when the last client using it exits. */ XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); /* Map overlay window before redirecting windows offscreen so we catch their * contents until we show the stage. */ XMapWindow (xdisplay, compositor->output); } redirect_windows (display->screen); compositor->plugin_mgr = meta_plugin_manager_new (compositor); }
int main (int argc, char *argv[]) { GstPipeline *pipeline; GstBus *bus; GstElement *srcbin; GstElement *tee; GstElement *queue[N_ACTORS], *sink[N_ACTORS]; GstElement *upload[N_ACTORS]; /* GstElement *effect[N_ACTORS]; */ ClutterActor *stage; GstGLClutterActor *actor[N_ACTORS]; Display *disp; Window stage_win; const gchar *desc; gint i; gint ok = FALSE; ClutterInitError clutter_err = CLUTTER_INIT_ERROR_UNKNOWN; clutter_err = clutter_init (&argc, &argv); if (clutter_err != CLUTTER_INIT_SUCCESS) g_warning ("Failed to initalize clutter: %d\n", clutter_err); gst_init (&argc, &argv); disp = clutter_x11_get_default_display (); if (!clutter_x11_has_composite_extension ()) { g_error ("XComposite extension missing"); } stage = clutter_stage_get_default (); clutter_actor_set_size (CLUTTER_ACTOR (stage), W * COLS + (COLS - 1), H * ROWS + (ROWS - 1)); stage_win = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); XCompositeRedirectSubwindows (disp, stage_win, CompositeRedirectManual); for (i = 0; i < N_ACTORS; i++) { actor[i] = g_new0 (GstGLClutterActor, 1); actor[i]->stage = stage; actor[i]->win = XCreateSimpleWindow (disp, stage_win, 0, 0, W, H, 0, 0, 0); XMapRaised (disp, actor[i]->win); XSync (disp, FALSE); } /* desc = g_strdup_printf ("v4l2src ! " "video/x-raw, width=640, height=480, framerate=30/1 ! " "videoscale !" "video/x-raw, width=%d, height=%d ! " "identity", W, H); */ desc = g_strdup_printf ("videotestsrc ! " "video/x-raw, format=RGB, width=%d, height=%d !" "identity", W, H); pipeline = GST_PIPELINE (gst_pipeline_new (NULL)); srcbin = gst_parse_bin_from_description (desc, TRUE, NULL); if (!srcbin) g_error ("Source bin creation failed"); tee = gst_element_factory_make ("tee", NULL); gst_bin_add_many (GST_BIN (pipeline), srcbin, tee, NULL); for (i = 0; i < N_ACTORS; i++) { queue[i] = gst_element_factory_make ("queue", NULL); upload[i] = gst_element_factory_make ("glupload", NULL); /* effect[i] = gst_element_factory_make ("gleffects", NULL); */ sink[i] = gst_element_factory_make ("glimagesink", NULL); /* gst_bin_add_many (GST_BIN (pipeline), queue[i], upload[i], effect[i], sink[i], NULL); */ gst_bin_add_many (GST_BIN (pipeline), queue[i], upload[i], sink[i], NULL); } gst_element_link_many (srcbin, tee, NULL); for (i = 0; i < N_ACTORS; i++) { ok |= // gst_element_link_many (tee, queue[i], upload[i], effect[i], sink[i], gst_element_link_many (tee, queue[i], upload[i], sink[i], NULL); } if (!ok) g_error ("Failed to link one or more elements"); /* for (i = 0; i < N_ACTORS; i++) { g_message ("setting effect %d on %s", i + 1, gst_element_get_name (effect[i])); g_object_set (G_OBJECT (effect[i]), "effect", i + 1, NULL); } */ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, actor, NULL); gst_object_unref (bus); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); clutter_actor_show_all (stage); clutter_main (); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); gst_object_unref (pipeline); return 0; }
gboolean toon_clutter_stage_set_window_icon(ClutterStage *stage, const gchar *path, GError ** /*error*/ ) { (void) stage; (void) path; #if 0 // TODO: assign some GError* to error in case of failure. Display *dpy = clutter_x11_get_default_display(); Window win = clutter_x11_get_stage_window(stage); static Atom net_wm_icon = None; if (! net_wm_icon) net_wm_icon = XInternAtom(dpy, "_NET_WM_ICON", False); GdkPixbuf *pixbuf = NULL; GError *pixbuf_error = NULL; gint pixels_w = 32; gint pixels_h = 32; //g_info("Loading image at size of %dx%d\n", pixels_w, pixels_h); pixbuf = gdk_pixbuf_new_from_file_at_scale(path, pixels_w, pixels_h, FALSE, &pixbuf_error); if (! pixbuf) { g_error("Error loading image %s: %s", path, pixbuf_error->message); g_error_free(pixbuf_error); pixbuf_error = NULL; g_object_unref(pixbuf); return FALSE; } int n_channels = gdk_pixbuf_get_n_channels(pixbuf); if (n_channels != 4) { g_critical("Image has no alpha channel and we require one."); g_object_unref(pixbuf); return FALSE; } g_assert(gdk_pixbuf_get_colorspace(pixbuf) == GDK_COLORSPACE_RGB); g_assert(gdk_pixbuf_get_bits_per_sample(pixbuf) == 8); g_assert(gdk_pixbuf_get_has_alpha(pixbuf)); g_assert(n_channels == 4); gulong bufsize = pixels_w * pixels_h * sizeof(char) * 4; guchar *data = (guchar *) g_malloc(bufsize + (sizeof(gulong) * 2)); ((gulong *)data)[0] = pixels_w; ((gulong *)data)[1] = pixels_h; guchar *pixels = gdk_pixbuf_get_pixels(pixbuf); memcpy((void *) &(((gulong *)data)[2]), (void *) pixels, bufsize); ///* For some inexplicable reason XChangeProperty always takes // * an array of longs when the format == 32 even on 64-bit // * architectures where sizeof(long) != 32. Therefore we need // * to pointlessly pad each 32-bit value with an extra 4 // * bytes so that libX11 can remove them again to send the // * request. We can do this in-place if we start from the // * end // */ //if (sizeof(gulong) != 4) //{ // const guint32 *src = (guint32 *) (data + 2) + pixels_w * pixels_h; // gulong *dst = data + 2 + pixels_w * pixels_h; // while (dst > data + 2) // { // *(--dst) = *(--src); // } //} XChangeProperty( dpy, // X11 display win, // X11 window net_wm_icon, // name of property XA_CARDINAL, // type of property 32, // format PropModeReplace, // mode (unsigned char *) data, // data (we must cast it to unsigned char* if format is 32) pixels_w * pixels_h + 2); // nelements g_free(data); g_object_unref(pixbuf); #endif return TRUE; }
int main (int argc, char *argv[]) { ClutterTimeline *timeline; ClutterAlpha *alpha; ClutterBehaviour *scaler_1, *scaler_2; ClutterActor *stage; ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff }; SuperOH *oh; gint i; GError *error; #ifdef REQ_NON_COMPOSITION Window xwin; Atom non_comp_atom; Display *dpy; int one = 1; #endif error = NULL; clutter_init_with_args (&argc, &argv, NULL, super_oh_entries, NULL, &error); if (error) { g_warning ("Unable to initialise Clutter:\n%s", error->message); g_error_free (error); exit (1); } stage = clutter_stage_get_default (); clutter_actor_set_size (stage, 800, 600); clutter_stage_set_title (CLUTTER_STAGE (stage), "Actors Test"); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); #ifdef REQ_NON_COMPOSITION /* request non-composited mode */ clutter_stage_fullscreen (stage); xwin = clutter_x11_get_stage_window (stage); dpy = XOpenDisplay(NULL); non_comp_atom = XInternAtom(dpy, "_HILDON_NON_COMPOSITED_WINDOW", False); XChangeProperty (dpy, xwin, non_comp_atom, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &one, 1); printf ("stage win is %lx\n", xwin); XSync (dpy, False); #endif oh = g_new(SuperOH, 1); /* Create a timeline to manage animation */ timeline = clutter_timeline_new (360, 60); /* num frames, fps */ g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */ /* fire a callback for frame change */ g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), oh); /* Set up some behaviours to handle scaling */ alpha = clutter_alpha_new_full (timeline, CLUTTER_ALPHA_SINE, NULL, NULL); scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, 1.0, 1.0); scaler_2 = clutter_behaviour_scale_new (alpha, 1.0, 1.0, 0.5, 0.5); /* create a new group to hold multiple actors in a group */ oh->group = clutter_group_new(); oh->hand = g_new (ClutterActor*, n_hands); for (i = 0; i < n_hands; i++) { gint x, y, w, h; gint radius = get_radius (); /* Create a texture from file, then clone in to same resources */ if (i == 0) { if ((oh->hand[i] = clutter_texture_new_from_file ("redhand.png", &error)) == NULL) { g_error ("image load failed: %s", error->message); exit (1); } } else oh->hand[i] = clutter_clone_texture_new (CLUTTER_TEXTURE(oh->hand[0])); /* Place around a circle */ w = clutter_actor_get_width (oh->hand[0]); h = clutter_actor_get_height (oh->hand[0]); x = CLUTTER_STAGE_WIDTH () / 2 + radius * cos (i * M_PI / (n_hands / 2)) - w / 2; y = CLUTTER_STAGE_HEIGHT () / 2 + radius * sin (i * M_PI / (n_hands / 2)) - h / 2; clutter_actor_set_position (oh->hand[i], x, y); clutter_actor_move_anchor_point_from_gravity (oh->hand[i], CLUTTER_GRAVITY_CENTER); /* Add to our group group */ clutter_container_add_actor (CLUTTER_CONTAINER (oh->group), oh->hand[i]); #if 1 /* FIXME: disabled as causes drift? - see comment above */ if (i % 2) clutter_behaviour_apply (scaler_1, oh->hand[i]); else clutter_behaviour_apply (scaler_2, oh->hand[i]); #endif } /* Add the group to the stage */ clutter_container_add_actor (CLUTTER_CONTAINER (stage), CLUTTER_ACTOR (oh->group)); /* Show everying ( and map window ) */ clutter_actor_show (stage); g_signal_connect (stage, "button-press-event", G_CALLBACK (input_cb), oh); g_signal_connect (stage, "key-release-event", G_CALLBACK (input_cb), oh); /* and start it */ clutter_timeline_start (timeline); clutter_main (); g_free (oh->hand); g_free (oh); return 0; }