static void queue_redraw_for_overlay (MetaStage *stage, MetaOverlay *overlay) { cairo_rectangle_int_t clip; /* Clear the location the overlay was at before, if we need to. */ if (overlay->previous_is_valid) { clip.x = overlay->previous_rect.x; clip.y = overlay->previous_rect.y; clip.width = overlay->previous_rect.width; clip.height = overlay->previous_rect.height; clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip); overlay->previous_is_valid = FALSE; } /* Draw the overlay at the new position */ if (overlay->enabled) { clip.x = overlay->current_rect.x; clip.y = overlay->current_rect.y; clip.width = overlay->current_rect.width; clip.height = overlay->current_rect.height; clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip); } }
static ClutterTranslateReturn clutter_stage_x11_translate_event (ClutterEventTranslator *translator, gpointer native, ClutterEvent *event) { ClutterStageX11 *stage_x11; ClutterStageCogl *stage_cogl; ClutterTranslateReturn res = CLUTTER_TRANSLATE_CONTINUE; ClutterBackendX11 *backend_x11; Window stage_xwindow; XEvent *xevent = native; ClutterStage *stage; stage_cogl = clutter_x11_get_stage_window_from_window (xevent->xany.window); if (stage_cogl == NULL) return CLUTTER_TRANSLATE_CONTINUE; stage = stage_cogl->wrapper; stage_x11 = CLUTTER_STAGE_X11 (stage_cogl); backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); stage_xwindow = stage_x11->xwin; switch (xevent->type) { case ConfigureNotify: if (!stage_x11->is_foreign_xwin) { gboolean size_changed = FALSE; CLUTTER_NOTE (BACKEND, "ConfigureNotify[%x] (%d, %d)", (unsigned int) stage_x11->xwin, xevent->xconfigure.width, xevent->xconfigure.height); /* When fullscreen, we'll keep the xwin_width/height variables to track the old size of the window and we'll assume all ConfigureNotifies constitute a size change */ if (_clutter_stage_is_fullscreen (stage)) size_changed = TRUE; else if ((stage_x11->xwin_width != xevent->xconfigure.width) || (stage_x11->xwin_height != xevent->xconfigure.height)) { size_changed = TRUE; stage_x11->xwin_width = xevent->xconfigure.width; stage_x11->xwin_height = xevent->xconfigure.height; } clutter_actor_set_size (CLUTTER_ACTOR (stage), xevent->xconfigure.width, xevent->xconfigure.height); CLUTTER_UNSET_PRIVATE_FLAGS (stage_cogl->wrapper, CLUTTER_IN_RESIZE); if (size_changed) { /* XXX: This is a workaround for a race condition when * resizing windows while there are in-flight * glXCopySubBuffer blits happening. * * The problem stems from the fact that rectangles for the * blits are described relative to the bottom left of the * window and because we can't guarantee control over the X * window gravity used when resizing so the gravity is * typically NorthWest not SouthWest. * * This means if you grow a window vertically the server * will make sure to place the old contents of the window * at the top-left/north-west of your new larger window, but * that may happen asynchronous to GLX preparing to do a * blit specified relative to the bottom-left/south-west of * the window (based on the old smaller window geometry). * * When the GLX issued blit finally happens relative to the * new bottom of your window, the destination will have * shifted relative to the top-left where all the pixels you * care about are so it will result in a nasty artefact * making resizing look very ugly! * * We can't currently fix this completely, in-part because * the window manager tends to trample any gravity we might * set. This workaround instead simply disables blits for a * while if we are notified of any resizes happening so if * the user is resizing a window via the window manager then * they may see an artefact for one frame but then we will * fallback to redrawing the full stage until the cooling * off period is over. */ if (stage_x11->clipped_redraws_cool_off) g_source_remove (stage_x11->clipped_redraws_cool_off); stage_x11->clipped_redraws_cool_off = clutter_threads_add_timeout (1000, clipped_redraws_cool_off_cb, stage_x11); /* Queue a relayout - we want glViewport to be called * with the correct values, and this is done in ClutterStage * via cogl_onscreen_clutter_backend_set_size (). * * We queue a relayout, because if this ConfigureNotify is * in response to a size we set in the application, the * set_size() call above is essentially a null-op. * * Make sure we do this only when the size has changed, * otherwise we end up relayouting on window moves. */ clutter_actor_queue_relayout (CLUTTER_ACTOR (stage)); /* the resize process is complete, so we can ask the stage * to set up the GL viewport with the new size */ clutter_stage_ensure_viewport (stage); } } break; case PropertyNotify: if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE && xevent->xproperty.window == stage_xwindow && !stage_x11->is_foreign_xwin) { Atom type; gint format; gulong n_items, bytes_after; guchar *data = NULL; gboolean fullscreen_set = FALSE; clutter_x11_trap_x_errors (); XGetWindowProperty (backend_x11->xdpy, stage_xwindow, backend_x11->atom_NET_WM_STATE, 0, G_MAXLONG, False, XA_ATOM, &type, &format, &n_items, &bytes_after, &data); clutter_x11_untrap_x_errors (); if (type != None && data != NULL) { gboolean is_fullscreen = FALSE; Atom *atoms = (Atom *) data; gulong i; for (i = 0; i < n_items; i++) { if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN) fullscreen_set = TRUE; } is_fullscreen = _clutter_stage_is_fullscreen (stage_cogl->wrapper); if (fullscreen_set != is_fullscreen) { if (fullscreen_set) _clutter_stage_update_state (stage_cogl->wrapper, 0, CLUTTER_STAGE_STATE_FULLSCREEN); else _clutter_stage_update_state (stage_cogl->wrapper, CLUTTER_STAGE_STATE_FULLSCREEN, 0); } XFree (data); } } break; case FocusIn: if (!_clutter_stage_is_activated (stage_cogl->wrapper)) { _clutter_stage_update_state (stage_cogl->wrapper, 0, CLUTTER_STAGE_STATE_ACTIVATED); } break; case FocusOut: if (_clutter_stage_is_activated (stage_cogl->wrapper)) { _clutter_stage_update_state (stage_cogl->wrapper, CLUTTER_STAGE_STATE_ACTIVATED, 0); } break; case EnterNotify: #if HAVE_XFIXES if (!stage_x11->is_cursor_visible && !stage_x11->cursor_hidden_xfixes) { XFixesHideCursor (backend_x11->xdpy, stage_x11->xwin); stage_x11->cursor_hidden_xfixes = TRUE; } #endif break; case LeaveNotify: #if HAVE_XFIXES if (stage_x11->cursor_hidden_xfixes) { XFixesShowCursor (backend_x11->xdpy, stage_x11->xwin); stage_x11->cursor_hidden_xfixes = FALSE; } #endif break; case Expose: { XExposeEvent *expose = (XExposeEvent *) xevent; cairo_rectangle_int_t clip; CLUTTER_NOTE (EVENT, "expose for stage: %s[%p], win:0x%x - " "redrawing area (x: %d, y: %d, width: %d, height: %d)", _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)), stage, (unsigned int) stage_xwindow, expose->x, expose->y, expose->width, expose->height); clip.x = expose->x; clip.y = expose->y; clip.width = expose->width; clip.height = expose->height; clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip); } break; case DestroyNotify: CLUTTER_NOTE (EVENT, "Destroy notification received for stage %s[%p], win:0x%x", _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)), stage, (unsigned int) stage_xwindow); event->any.type = CLUTTER_DESTROY_NOTIFY; event->any.stage = stage; res = CLUTTER_TRANSLATE_QUEUE; break; case ClientMessage: CLUTTER_NOTE (EVENT, "Client message for stage %s[%p], win:0x%x", _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)), stage, (unsigned int) stage_xwindow); if (handle_wm_protocols_event (backend_x11, stage_x11, xevent)) { event->any.type = CLUTTER_DELETE; event->any.stage = stage; res = CLUTTER_TRANSLATE_QUEUE; } break; case MappingNotify: CLUTTER_NOTE (EVENT, "Refresh keyboard mapping"); XRefreshKeyboardMapping (&xevent->xmapping); backend_x11->keymap_serial += 1; res = CLUTTER_TRANSLATE_REMOVE; break; default: res = CLUTTER_TRANSLATE_CONTINUE; break; } return res; }