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); } }
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); }
/** * meta_shape_cow_for_window: * @compositor: A #MetaCompositor * @window: (nullable): A #MetaWindow to shape the COW for * * Sets an bounding shape on the COW so that the given window * is exposed. If @window is %NULL it clears the shape again. * * Used so we can unredirect windows, by shaping away the part * of the COW, letting the raw window be seen through below. */ static void meta_shape_cow_for_window (MetaCompositor *compositor, MetaWindow *window) { MetaDisplay *display = compositor->display; Display *xdisplay = meta_display_get_xdisplay (display); if (window == NULL) XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); else { XserverRegion output_region; XRectangle screen_rect, window_bounds; int width, height; MetaRectangle rect; meta_window_get_frame_rect (window, &rect); window_bounds.x = rect.x; window_bounds.y = rect.y; window_bounds.width = rect.width; window_bounds.height = rect.height; meta_screen_get_size (display->screen, &width, &height); screen_rect.x = 0; screen_rect.y = 0; screen_rect.width = width; screen_rect.height = height; output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region); XFixesDestroyRegion (xdisplay, output_region); } }
/* * Shapes the cow so that the given window is exposed, * when metaWindow is NULL it clears the shape again */ static void meta_shape_cow_for_window (MetaScreen *screen, MetaWindow *metaWindow) { MetaCompScreen *info = meta_screen_get_compositor_data (screen); Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen)); if (metaWindow == NULL) XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); else { XserverRegion output_region; XRectangle screen_rect, window_bounds; int width, height; MetaRectangle rect; meta_window_get_outer_rect (metaWindow, &rect); window_bounds.x = rect.x; window_bounds.y = rect.y; window_bounds.width = rect.width; window_bounds.height = rect.height; meta_screen_get_size (screen, &width, &height); screen_rect.x = 0; screen_rect.y = 0; screen_rect.width = width; screen_rect.height = height; output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, output_region); XFixesDestroyRegion (xdisplay, output_region); } }
EAPI void ecore_x_region_window_shape_set(Ecore_X_Region region, Ecore_X_Window win, Ecore_X_Shape_Type type, int x_offset, int y_offset) { #ifdef ECORE_XFIXES LOGFN(__FILE__, __LINE__, __FUNCTION__); XFixesSetWindowShapeRegion(_ecore_x_disp, win, type, x_offset, y_offset, region); #endif /* ifdef ECORE_XFIXES */ } /* ecore_x_region_window_shape_set */
EffectInstance::EffectInstance(Effect *owner, int64_t started, bool right, QWidget *parent) :QMainWindow(parent), time_started(started), label(this), owner(owner) { // Set window properties the same as the pony window setAttribute(Qt::WA_TranslucentBackground, true); setAttribute(Qt::WA_ShowWithoutActivating); #ifdef Q_WS_X11 // Disables shadows under the pony window. setAttribute(Qt::WA_X11NetWmWindowTypeDock); #endif #if defined QT_MAC_USE_COCOA && QT_VERSION >= 0x040800 // Removes shadows that lag behind animation on OS X. QT 4.8+ needed. setAttribute(Qt::WA_MacNoShadow, true); #endif #ifdef QT_MAC_USE_COCOA // On OS X, tool windows are hidden when another program gains focus. Qt::WindowFlags windowflags = Qt::FramelessWindowHint; #else Qt::WindowFlags windowflags = Qt::FramelessWindowHint | Qt::Tool; #endif if(ConfigWindow::getSetting<bool>("general/always-on-top")) { windowflags |= Qt::WindowStaysOnTopHint; } #ifdef Q_WS_X11 if(ConfigWindow::getSetting<bool>("general/bypass-wm")) { // Bypass the window manager windowflags |= Qt::X11BypassWindowManagerHint; } #endif setWindowFlags( windowflags ); #ifdef Q_WS_X11 // Qt on X11 does not support the skip taskbar/pager window flags, we have to set them ourselves // We let Qt initialize the other window properties, which aren't deleted when we replace them with ours // (they probably are appended on show()) Atom window_state = XInternAtom( QX11Info::display(), "_NET_WM_STATE", False ); Atom window_props[] = { XInternAtom( QX11Info::display(), "_NET_WM_STATE_SKIP_TASKBAR", False ), XInternAtom( QX11Info::display(), "_NET_WM_STATE_SKIP_PAGER" , False ) }; XChangeProperty( QX11Info::display(), window()->winId(), window_state, XA_ATOM, 32, PropModeReplace, (unsigned char*)&window_props, 2 ); // Set a null input region mask for the event window, so that it does not interfere with mouseover effects. XRectangle rect{0,0,0,0}; XserverRegion shapeRegion = XFixesCreateRegion(QX11Info::display(), &rect, 1); XFixesSetWindowShapeRegion(QX11Info::display(), winId(), ShapeInput, 0, 0, shapeRegion); XFixesDestroyRegion(QX11Info::display(), shapeRegion); #endif // TODO: add WS_EX_TRANSPARENT extended window style on windows. #ifdef Q_WS_X11 // Make sure the effect gets drawn on the same desktop as the pony Atom wm_desktop = XInternAtom(QX11Info::display(), "_NET_WM_DESKTOP", False); Atom type_ret; int fmt_ret; unsigned long nitems_ret; unsigned long bytes_after_ret; int *desktop = NULL; if(XGetWindowProperty(QX11Info::display(), owner->parent_pony->window()->winId(), wm_desktop, 0, 1, False, XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret, reinterpret_cast<unsigned char **>(&desktop)) == Success && desktop != NULL) { XChangeProperty(QX11Info::display(), window()->winId(), wm_desktop, XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<unsigned char*>(desktop), 1); XFree(desktop); } #endif // Load animations and verify them // TODO: Do we need to change the direction of active effects? Maybe we only need to display the image for the direction at witch it was spawned. animation_left = new QMovie(QString("%1/%2/%3").arg(ConfigWindow::getSetting<QString>("general/pony-directory"), owner->path, owner->image_left )); animation_right = new QMovie(QString("%1/%2/%3").arg(ConfigWindow::getSetting<QString>("general/pony-directory"), owner->path, owner->image_right)); if(!animation_left->isValid()) qCritical() << "Effect:"<< owner->path <<"Error opening left animation:"<< owner->image_left << "for effect:"<< owner->name; if(!animation_right->isValid()) qCritical() << "Effect:"<< owner->path <<"Error opening right animation:"<< owner->image_right << "for behavior:"<< owner->name; animation_left->setCacheMode(QMovie::CacheAll); animation_right->setCacheMode(QMovie::CacheAll); if(right){ current_animation = animation_right; }else{ current_animation = animation_left; } current_animation->jumpToFrame(0); image_width = current_animation->currentImage().width(); image_height = current_animation->currentImage().height(); if(right){ offset = get_location(owner->location_right, owner->center_right); }else{ offset = get_location(owner->location_left, owner->center_left); } current_animation->start(); update_animation(); show(); }
void meta_compositor_manage (MetaCompositor *compositor) { MetaDisplay *display = compositor->display; Display *xdisplay = display->xdisplay; MetaScreen *screen = display->screen; MetaBackend *backend = meta_get_backend (); meta_screen_set_cm_selection (display->screen); compositor->stage = meta_backend_get_stage (backend); /* 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); compositor->feedback_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); clutter_actor_add_child (compositor->stage, compositor->feedback_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 { Window xwin; compositor->output = screen->composite_overlay_window; xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend)); 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); compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay); } redirect_windows (display->screen); compositor->plugin_mgr = meta_plugin_manager_new (compositor); }
void ignore_input(Window w) { XserverRegion region = XFixesCreateRegion(dpy, NULL, 0); XFixesSetWindowShapeRegion(dpy, w, ShapeBounding, 0, 0, 0); XFixesSetWindowShapeRegion(dpy, w, ShapeInput, 0, 0, region); XFixesDestroyRegion(dpy, region); }
// Creates the event addon void* FcitxTabletCreate(FcitxInstance* instance) { FcitxTablet* tablet = fcitx_utils_new(FcitxTablet); FcitxTabletLoadConfig(&tablet->config); // TODO select driver from config, currently using lxbi { // Initialise the driver switch(tablet->config.Driver) { case DRIVER_LXBI: tablet->driverInstance = &lxbi; break; // add other drivers here } tablet->driverData = tablet->driverInstance->Create(); tablet->driverPacket = (char*) malloc(tablet->driverInstance->packet_size); } { // Initialise the X display if(NULL == (tablet->xDisplay = FcitxX11GetDisplay(instance))) { FcitxLog(ERROR, "Unable to open X display"); return NULL; } // get dimensions int screen = DefaultScreen(tablet->xDisplay); tablet->xWidth = tablet->config.Width; tablet->xHeight = tablet->config.Height; int x = tablet->config.XPos > 0 ? tablet->config.XPos : XDisplayWidth(tablet->xDisplay, screen) - tablet->xWidth + tablet->config.XPos; int y = tablet->config.YPos > 0 ? tablet->config.YPos : XDisplayHeight(tablet->xDisplay, screen) - tablet->xHeight + tablet->config.YPos; // create colours XColor back; XColor fore; { char colourString[32]; { int r = (255*tablet->config.BackgroundColour.r); int g = (255*tablet->config.BackgroundColour.g); int b = (255*tablet->config.BackgroundColour.b); sprintf(colourString,"rgb:%x/%x/%x",r,g,b); } Colormap defaultCMap = DefaultColormap(tablet->xDisplay, screen); XParseColor(tablet->xDisplay, defaultCMap, colourString, &back); XAllocColor(tablet->xDisplay, defaultCMap, &back); { int r = (255*tablet->config.StrokeColour.r); int g = (255*tablet->config.StrokeColour.g); int b = (255*tablet->config.StrokeColour.b); sprintf(colourString,"rgb:%x/%x/%x",r,g,b); } XParseColor(tablet->xDisplay, defaultCMap, colourString, &fore); XAllocColor(tablet->xDisplay, defaultCMap, &fore); } // set window attributes and create window XSetWindowAttributes attrs; attrs.override_redirect = True; attrs.background_pixel = back.pixel; tablet->xWindow = XCreateWindow(tablet->xDisplay, DefaultRootWindow(tablet->xDisplay), x, y, tablet->xWidth, tablet->xHeight, tablet->config.BorderWidth, CopyFromParent, InputOutput, CopyFromParent, CWBackPixel | CWOverrideRedirect, &attrs); // set up the foreground line (stroke) style XGCValues gcv; gcv.function = GXcopy; gcv.subwindow_mode = IncludeInferiors; gcv.line_width = 3; gcv.cap_style = CapRound; gcv.join_style = JoinRound; tablet->xGC = XCreateGC(tablet->xDisplay, tablet->xWindow, GCFunction | GCSubwindowMode | GCLineWidth | GCCapStyle | GCJoinStyle, &gcv); XSetForeground(tablet->xDisplay, tablet->xGC, fore.pixel); // prevent the window from getting focus or input XRectangle rect = {0,0,0,0}; XserverRegion region = XFixesCreateRegion(tablet->xDisplay,&rect, 1); XFixesSetWindowShapeRegion(tablet->xDisplay, tablet->xWindow, ShapeInput, 0, 0, region); XFixesDestroyRegion(tablet->xDisplay, region); } { // Initialise the stroke buffer tablet->strokesBufferSize = 2048; // should be heaps. Will get automatically enlarged if required tablet->strokesBuffer = (pt_t*) malloc(sizeof(pt_t) * tablet->strokesBufferSize); tablet->strokesPtr = tablet->strokesBuffer; } { // instantiate the engine switch(tablet->config.Engine) { case ENGINE_ZINNIA: tablet->engineInstance = &engZinnia; break; case ENGINE_FORK: tablet->engineInstance = &engFork; break; // add other engines here } tablet->engineData = tablet->engineInstance->Create(&tablet->config); } { // set up the timerfd tablet->timeoutFd = timerfd_create(CLOCK_MONOTONIC, 0); tablet->delay.it_interval.tv_sec = 0; tablet->delay.it_interval.tv_nsec = 0; tablet->delay.it_value.tv_sec = tablet->config.CommitCharMs / 1000; tablet->delay.it_value.tv_nsec = (tablet->config.CommitCharMs % 1000) * 1000000; tablet->timeoutCommitPending = 0; } tablet->fcitx = instance; return tablet; }
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); }
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); }