/** * FreeRDP: A Remote Desktop Protocol Implementation * * Copyright 2011-2014 Marc-Andre Moreau * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "x11_shadow.h" int x11_shadow_cursor_init(x11ShadowSubsystem* subsystem) { #ifdef WITH_XFIXES int event; int error; if (!XFixesQueryExtension(subsystem->display, &event, &error)) { fprintf(stderr, "XFixesQueryExtension failed\n"); return -1; } subsystem->xfixes_notify_event = event + XFixesCursorNotify; XFixesSelectCursorInput(subsystem->display, DefaultRootWindow(subsystem->display), XFixesDisplayCursorNotifyMask); #endif return 0; } #ifdef WITH_XDAMAGE void x11_shadow_xdamage_init(x11ShadowSubsystem* subsystem) { int damage_event; int damage_error; int major, minor; XGCValues values; if (XDamageQueryExtension(subsystem->display, &damage_event, &damage_error) == 0) { fprintf(stderr, "XDamageQueryExtension failed\n"); return; } XDamageQueryVersion(subsystem->display, &major, &minor); if (XDamageQueryVersion(subsystem->display, &major, &minor) == 0) { fprintf(stderr, "XDamageQueryVersion failed\n"); return; } else if (major < 1) { fprintf(stderr, "XDamageQueryVersion failed: major:%d minor:%d\n", major, minor); return; } subsystem->xdamage_notify_event = damage_event + XDamageNotify; subsystem->xdamage = XDamageCreate(subsystem->display, subsystem->root_window, XDamageReportDeltaRectangles); if (subsystem->xdamage == None) { fprintf(stderr, "XDamageCreate failed\n"); return; } #ifdef WITH_XFIXES subsystem->xdamage_region = XFixesCreateRegion(subsystem->display, NULL, 0); if (subsystem->xdamage_region == None) { fprintf(stderr, "XFixesCreateRegion failed\n"); XDamageDestroy(subsystem->display, subsystem->xdamage); subsystem->xdamage = None; return; } #endif values.subwindow_mode = IncludeInferiors; subsystem->xdamage_gc = XCreateGC(subsystem->display, subsystem->root_window, GCSubwindowMode, &values); XSetFunction(subsystem->display, subsystem->xdamage_gc, GXcopy); } #endif int x11_shadow_xshm_init(x11ShadowSubsystem* server) { Bool pixmaps; int major, minor; if (XShmQueryExtension(server->display) != False) { XShmQueryVersion(server->display, &major, &minor, &pixmaps); if (pixmaps != True) { fprintf(stderr, "XShmQueryVersion failed\n"); return -1; } } else { fprintf(stderr, "XShmQueryExtension failed\n"); return -1; } server->fb_shm_info.shmid = -1; server->fb_shm_info.shmaddr = (char*) -1; server->fb_image = XShmCreateImage(server->display, server->visual, server->depth, ZPixmap, NULL, &(server->fb_shm_info), server->width, server->height); if (!server->fb_image) { fprintf(stderr, "XShmCreateImage failed\n"); return -1; } server->fb_shm_info.shmid = shmget(IPC_PRIVATE, server->fb_image->bytes_per_line * server->fb_image->height, IPC_CREAT | 0600); if (server->fb_shm_info.shmid == -1) { fprintf(stderr, "shmget failed\n"); return -1; } server->fb_shm_info.readOnly = False; server->fb_shm_info.shmaddr = shmat(server->fb_shm_info.shmid, 0, 0); server->fb_image->data = server->fb_shm_info.shmaddr; if (server->fb_shm_info.shmaddr == ((char*) -1)) { fprintf(stderr, "shmat failed\n"); return -1; } XShmAttach(server->display, &(server->fb_shm_info)); XSync(server->display, False); shmctl(server->fb_shm_info.shmid, IPC_RMID, 0); fprintf(stderr, "display: %p root_window: %p width: %d height: %d depth: %d\n", server->display, (void*) server->root_window, server->fb_image->width, server->fb_image->height, server->fb_image->depth); server->fb_pixmap = XShmCreatePixmap(server->display, server->root_window, server->fb_image->data, &(server->fb_shm_info), server->fb_image->width, server->fb_image->height, server->fb_image->depth); return 0; } int x11_shadow_subsystem_init(x11ShadowSubsystem* subsystem) { int i; int pf_count; int vi_count; XVisualInfo* vi; XVisualInfo* vis; XVisualInfo template; XPixmapFormatValues* pf; XPixmapFormatValues* pfs; /** * Recent X11 servers drop support for shared pixmaps * To see if your X11 server supports shared pixmaps, use: * xdpyinfo -ext MIT-SHM | grep "shared pixmaps" */ subsystem->use_xshm = TRUE; setenv("DISPLAY", ":0", 1); /* Set DISPLAY variable if not already set */ if (!XInitThreads()) fprintf(stderr, "warning: XInitThreads() failure\n"); subsystem->display = XOpenDisplay(NULL); if (!subsystem->display) { fprintf(stderr, "failed to open display: %s\n", XDisplayName(NULL)); exit(1); } subsystem->xfds = ConnectionNumber(subsystem->display); subsystem->number = DefaultScreen(subsystem->display); subsystem->screen = ScreenOfDisplay(subsystem->display, subsystem->number); subsystem->depth = DefaultDepthOfScreen(subsystem->screen); subsystem->width = WidthOfScreen(subsystem->screen); subsystem->height = HeightOfScreen(subsystem->screen); subsystem->root_window = DefaultRootWindow(subsystem->display); pfs = XListPixmapFormats(subsystem->display, &pf_count); if (!pfs) { fprintf(stderr, "XListPixmapFormats failed\n"); exit(1); } for (i = 0; i < pf_count; i++) { pf = pfs + i; if (pf->depth == subsystem->depth) { subsystem->bpp = pf->bits_per_pixel; subsystem->scanline_pad = pf->scanline_pad; break; } } XFree(pfs); ZeroMemory(&template, sizeof(template)); template.class = TrueColor; template.screen = subsystem->number; vis = XGetVisualInfo(subsystem->display, VisualClassMask | VisualScreenMask, &template, &vi_count); if (!vis) { fprintf(stderr, "XGetVisualInfo failed\n"); exit(1); } for (i = 0; i < vi_count; i++) { vi = vis + i; if (vi->depth == subsystem->depth) { subsystem->visual = vi->visual; break; } } XFree(vis); XSelectInput(subsystem->display, subsystem->root_window, SubstructureNotifyMask); if (subsystem->use_xshm) { if (x11_shadow_xshm_init(subsystem) < 0) subsystem->use_xshm = FALSE; } if (subsystem->use_xshm) printf("Using X Shared Memory Extension (XShm)\n"); #ifdef WITH_XDAMAGE x11_shadow_xdamage_init(subsystem); #endif x11_shadow_cursor_init(subsystem); subsystem->bytesPerPixel = 4; return 1; } int x11_shadow_subsystem_uninit(x11ShadowSubsystem* subsystem) { if (!subsystem) return -1; if (subsystem->display) { XCloseDisplay(subsystem->display); subsystem->display = NULL; } return 1; } rdpShadowSubsystem* x11_shadow_subsystem_new(rdpShadowServer* server) { x11ShadowSubsystem* subsystem; subsystem = (x11ShadowSubsystem*) calloc(1, sizeof(x11ShadowSubsystem)); if (!subsystem) return NULL; subsystem->server = server; x11_shadow_subsystem_init(subsystem); return (rdpShadowSubsystem*) subsystem; } void x11_shadow_subsystem_free(rdpShadowSubsystem* subsystem) { if (!subsystem) return; x11_shadow_subsystem_uninit((x11ShadowSubsystem*) subsystem); free(subsystem); }