void hide_cursor(void) { if (debug) printf("keystroke, %shiding cursor\n", (hiding ? "already " : "")); if (!hiding) { XFixesHideCursor(dpy, DefaultRootWindow(dpy)); hiding = 1; } }
static gboolean meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite) { MetaCursorRendererX11 *x11 = META_CURSOR_RENDERER_X11 (renderer); MetaCursorRendererX11Private *priv = meta_cursor_renderer_x11_get_instance_private (x11); MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ()); Window xwindow = meta_backend_x11_get_xwindow (backend); Display *xdisplay = meta_backend_x11_get_xdisplay (backend); if (xwindow == None) { if (cursor_sprite) meta_cursor_sprite_realize_texture (cursor_sprite); return FALSE; } gboolean has_server_cursor = FALSE; if (cursor_sprite) { MetaCursor cursor = meta_cursor_sprite_get_meta_cursor (cursor_sprite); if (cursor != META_CURSOR_NONE) { Cursor xcursor = meta_cursor_create_x_cursor (xdisplay, cursor); XDefineCursor (xdisplay, xwindow, xcursor); XFlush (xdisplay); XFreeCursor (xdisplay, xcursor); has_server_cursor = TRUE; } } if (has_server_cursor != priv->server_cursor_visible) { if (has_server_cursor) XFixesShowCursor (xdisplay, xwindow); else XFixesHideCursor (xdisplay, xwindow); priv->server_cursor_visible = has_server_cursor; } if (!priv->server_cursor_visible && cursor_sprite) meta_cursor_sprite_realize_texture (cursor_sprite); return priv->server_cursor_visible; }
void meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, gboolean visible) { if (visible == tracker->is_showing) return; tracker->is_showing = visible; if (visible) XFixesShowCursor (tracker->screen->display->xdisplay, tracker->screen->xroot); else XFixesHideCursor (tracker->screen->display->xdisplay, tracker->screen->xroot); }
static inline void set_cursor_visible (ClutterStageX11 *stage_x11) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); if (stage_x11->xwin == None) return; CLUTTER_NOTE (BACKEND, "setting cursor state ('%s') over stage window (%u)", stage_x11->is_cursor_visible ? "visible" : "invisible", (unsigned int) stage_x11->xwin); if (stage_x11->is_cursor_visible) { #if HAVE_XFIXES if (stage_x11->cursor_hidden_xfixes) { XFixesShowCursor (backend_x11->xdpy, stage_x11->xwin); stage_x11->cursor_hidden_xfixes = FALSE; } #else XUndefineCursor (backend_x11->xdpy, stage_x11->xwin); #endif /* HAVE_XFIXES */ } else { #if HAVE_XFIXES XFixesHideCursor (backend_x11->xdpy, stage_x11->xwin); stage_x11->cursor_hidden_xfixes = TRUE; #else XColor col; Pixmap pix; Cursor curs; pix = XCreatePixmap (backend_x11->xdpy, stage_x11->xwin, 1, 1, 1); memset (&col, 0, sizeof (col)); curs = XCreatePixmapCursor (backend_x11->xdpy, pix, pix, &col, &col, 1, 1); XFreePixmap (backend_x11->xdpy, pix); XDefineCursor (backend_x11->xdpy, stage_x11->xwin, curs); #endif /* HAVE_XFIXES */ } }
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; } }
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; }
int main(int argc, char *argv[]) { Display *dpy; int hiding = 0, ch; XEvent e; while ((ch = getopt(argc, argv, "d")) != -1) switch (ch) { case 'd': debug = 1; break; default: usage(); } argc -= optind; argv += optind; if (!(dpy = XOpenDisplay(NULL))) errx(1, "can't open display %s", XDisplayName(NULL)); XSetErrorHandler(swallow_error); /* recurse from root window down */ snoop(dpy, DefaultRootWindow(dpy)); for (;;) { XNextEvent(dpy, &e); switch (e.type) { case KeyRelease: if (debug) printf("keystroke %d, %shiding cursor\n", e.xkey.keycode, (hiding ? "already " : "")); if (!hiding) { XFixesHideCursor(dpy, DefaultRootWindow(dpy)); hiding = 1; } break; case ButtonRelease: case MotionNotify: if (debug) printf("mouse moved to %d,%d, %sunhiding " "cursor\n", e.xmotion.x_root, e.xmotion.y_root, (hiding ? "" : "already ")); if (hiding) { XFixesShowCursor(dpy, DefaultRootWindow(dpy)); hiding = 0; } break; case CreateNotify: if (debug) printf("created new window, snooping on it\n"); /* not sure why snooping directly on the window doesn't * work, so snoop on all windows from its parent * (probably root) */ snoop(dpy, e.xcreatewindow.parent); break; } } }