/* * Copyright © 2011-2014 Intel Corporation * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of the * copyright holders not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied * warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #if !defined(SYSV) && !defined(WIN32) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xwayland-screen.h" #include "xwayland-vidmode.h" #ifdef XF86VIDMODE #include extern _X_EXPORT Bool noXFree86VidModeExtension; #endif void ddxGiveUp(enum ExitCode error) { } void OsVendorInit(void) { if (serverGeneration == 1) ForceClockId(CLOCK_MONOTONIC); } void OsVendorFatalError(const char *f, va_list args) { } #if defined(DDXBEFORERESET) void ddxBeforeReset(void) { return; } #endif #if INPUTTHREAD /** This function is called in Xserver/os/inputthread.c when starting the input thread. */ void ddxInputThreadInit(void) { } #endif void ddxUseMsg(void) { ErrorF("-rootless run rootless, requires wm support\n"); ErrorF("-fullscreen run fullscreen when rootful\n"); ErrorF("-geometry WxH set Xwayland window size when rootful\n"); ErrorF("-host-grab disable host keyboard shortcuts when rootful\n"); ErrorF("-wm fd create X client for wm on given fd\n"); ErrorF("-initfd fd add given fd as a listen socket for initialization clients\n"); ErrorF("-listenfd fd add given fd as a listen socket\n"); ErrorF("-listen fd deprecated, use \"-listenfd\" instead\n"); #ifdef XWL_HAS_EGLSTREAM ErrorF("-eglstream use eglstream backend for nvidia GPUs\n"); #endif ErrorF("-shm use shared memory for passing buffers\n"); ErrorF("-verbose [n] verbose startup messages\n"); ErrorF("-version show the server version and exit\n"); ErrorF("-noTouchPointerEmulation disable touch pointer emulation\n"); ErrorF("-force-xrandr-emulation force non-native modes to be exposed when viewporter is not exposed by the compositor\n"); #ifdef XWL_HAS_LIBDECOR ErrorF("-decorate add decorations to Xwayland when rootful (experimental)\n"); #endif } static int init_fd = -1; static int wm_fd = -1; static int listen_fds[5] = { -1, -1, -1, -1, -1 }; static int listen_fd_count = 0; static int verbosity = 0; static void xwl_show_version(void) { ErrorF("%s Xwayland %s (%d)\n", VENDOR_NAME, VENDOR_MAN_VERSION, VENDOR_RELEASE); ErrorF("X Protocol Version %d, Revision %d\n", X_PROTOCOL, X_PROTOCOL_REVISION); #if defined(BUILDERSTRING) if (strlen(BUILDERSTRING)) ErrorF("%s\n", BUILDERSTRING); #endif } static void try_raising_nofile_limit(void) { #ifdef RLIMIT_NOFILE struct rlimit rlim; /* Only fiddle with the limit if not set explicitly from the command line */ if (limitNoFile >= 0) return; if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { ErrorF("Failed to get the current nofile limit: %s\n", strerror(errno)); return; } rlim.rlim_cur = rlim.rlim_max; if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { ErrorF("Failed to set the current nofile limit: %s\n", strerror(errno)); return; } LogMessageVerb(X_INFO, 3, "Raising the file descriptors limit to %li\n", rlim.rlim_max); #endif } static void xwl_add_listen_fd(int argc, char *argv[], int i) { NoListenAll = TRUE; if (listen_fd_count == ARRAY_SIZE(listen_fds)) FatalError("Too many -listen arguments given, max is %zu\n", ARRAY_SIZE(listen_fds)); listen_fds[listen_fd_count++] = atoi(argv[i + 1]); } int ddxProcessArgument(int argc, char *argv[], int i) { if (strcmp(argv[i], "-rootless") == 0) { return 1; } else if (strcmp(argv[i], "-listen") == 0) { CHECK_FOR_REQUIRED_ARGUMENTS(1); /* Not an FD */ if (!isdigit(*argv[i + 1])) return 0; LogMessageVerb(X_WARNING, 0, "Option \"-listen\" for file descriptors is deprecated\n" "Please use \"-listenfd\" instead.\n"); xwl_add_listen_fd (argc, argv, i); return 2; } else if (strcmp(argv[i], "-listenfd") == 0) { CHECK_FOR_REQUIRED_ARGUMENTS(1); xwl_add_listen_fd (argc, argv, i); return 2; } else if (strcmp(argv[i], "-wm") == 0) { CHECK_FOR_REQUIRED_ARGUMENTS(1); wm_fd = atoi(argv[i + 1]); return 2; } else if (strcmp(argv[i], "-initfd") == 0) { CHECK_FOR_REQUIRED_ARGUMENTS(1); init_fd = atoi(argv[i + 1]); return 2; } else if (strcmp(argv[i], "-shm") == 0) { return 1; } else if (strcmp(argv[i], "-verbose") == 0) { if (++i < argc && argv[i]) { char *end; long val; val = strtol(argv[i], &end, 0); if (*end == '\0') { verbosity = val; LogSetParameter(XLOG_VERBOSITY, verbosity); return 2; } } LogSetParameter(XLOG_VERBOSITY, ++verbosity); return 1; } else if (strcmp(argv[i], "-eglstream") == 0) { return 1; } else if (strcmp(argv[i], "-version") == 0) { xwl_show_version(); exit(0); } else if (strcmp(argv[i], "-noTouchPointerEmulation") == 0) { touchEmulatePointer = FALSE; return 1; } else if (strcmp(argv[i], "-force-xrandr-emulation") == 0) { return 1; } else if (strcmp(argv[i], "-geometry") == 0) { CHECK_FOR_REQUIRED_ARGUMENTS(1); return 2; } else if (strcmp(argv[i], "-fullscreen") == 0) { return 1; } else if (strcmp(argv[i], "-host-grab") == 0) { return 1; } else if (strcmp(argv[i], "-decorate") == 0) { return 1; } return 0; } static CARD32 add_client_fd(OsTimerPtr timer, CARD32 time, void *arg) { if (!AddClientOnOpenFD(wm_fd)) FatalError("Failed to add wm client\n"); TimerFree(timer); return 0; } static void listen_on_fds(void) { int i; for (i = 0; i < listen_fd_count; i++) ListenOnOpenFD(listen_fds[i], FALSE); } static void wm_selection_callback(CallbackListPtr *p, void *data, void *arg) { SelectionInfoRec *info = arg; struct xwl_screen *xwl_screen = data; static const char atom_name[] = "WM_S0"; static Atom atom_wm_s0; if (atom_wm_s0 == None) atom_wm_s0 = MakeAtom(atom_name, strlen(atom_name), TRUE); if (info->selection->selection != atom_wm_s0 || info->kind != SelectionSetOwner) return; listen_on_fds(); DeleteCallback(&SelectionCallback, wm_selection_callback, xwl_screen); } static void _X_ATTRIBUTE_PRINTF(1, 0) xwl_log_handler(const char *format, va_list args) { char msg[256]; vsnprintf(msg, sizeof msg, format, args); ErrorF("XWAYLAND: %s", msg); } #ifdef XWL_HAS_XWAYLAND_EXTENSION #include Bool noXwaylandExtension = FALSE; static int ProcXwlQueryVersion(ClientPtr client) { xXwlQueryVersionReply reply; int major, minor; REQUEST(xXwlQueryVersionReq); REQUEST_SIZE_MATCH(xXwlQueryVersionReq); if (version_compare(stuff->majorVersion, stuff->minorVersion, XWAYLAND_EXTENSION_MAJOR, XWAYLAND_EXTENSION_MINOR) < 0) { major = stuff->majorVersion; minor = stuff->minorVersion; } else { major = XWAYLAND_EXTENSION_MAJOR; minor = XWAYLAND_EXTENSION_MINOR; } reply = (xXwlQueryVersionReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = 0, .majorVersion = major, .minorVersion = minor, }; if (client->swapped) { swaps(&reply.sequenceNumber); swapl(&reply.length); swaps(&reply.majorVersion); swaps(&reply.minorVersion); } WriteReplyToClient(client, sizeof(reply), &reply); return Success; } static int _X_COLD SProcXwlQueryVersion(ClientPtr client) { REQUEST(xXwlQueryVersionReq); swaps(&stuff->length); REQUEST_AT_LEAST_SIZE(xXwlQueryVersionReq); swaps(&stuff->majorVersion); swaps(&stuff->minorVersion); return ProcXwlQueryVersion(client); } static int ProcXwaylandDispatch(ClientPtr client) { REQUEST(xReq); switch (stuff->data) { case X_XwlQueryVersion: return ProcXwlQueryVersion(client); } return BadRequest; } static int SProcXwaylandDispatch(ClientPtr client) { REQUEST(xReq); switch (stuff->data) { case X_XwlQueryVersion: return SProcXwlQueryVersion(client); } return BadRequest; } static void xwlExtensionInit(void) { AddExtension(XWAYLAND_EXTENSION_NAME, XwlNumberEvents, XwlNumberErrors, ProcXwaylandDispatch, SProcXwaylandDispatch, NULL, StandardMinorOpcode); } #endif static const ExtensionModule xwayland_extensions[] = { #ifdef XF86VIDMODE { xwlVidModeExtensionInit, XF86VIDMODENAME, &noXFree86VidModeExtension }, #endif #ifdef XWL_HAS_XWAYLAND_EXTENSION { xwlExtensionInit, XWAYLAND_EXTENSION_NAME, &noXwaylandExtension }, #endif }; void InitOutput(ScreenInfo * screen_info, int argc, char **argv) { int depths[] = { 1, 4, 8, 15, 16, 24, 32 }; int bpp[] = { 1, 8, 8, 16, 16, 32, 32 }; int i; for (i = 0; i < ARRAY_SIZE(depths); i++) { screen_info->formats[i].depth = depths[i]; screen_info->formats[i].bitsPerPixel = bpp[i]; screen_info->formats[i].scanlinePad = BITMAP_SCANLINE_PAD; } screen_info->imageByteOrder = IMAGE_BYTE_ORDER; screen_info->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; screen_info->bitmapScanlinePad = BITMAP_SCANLINE_PAD; screen_info->bitmapBitOrder = BITMAP_BIT_ORDER; screen_info->numPixmapFormats = ARRAY_SIZE(depths); if (serverGeneration == 1) { try_raising_nofile_limit(); LoadExtensionList(xwayland_extensions, ARRAY_SIZE(xwayland_extensions), FALSE); } wl_log_set_handler_client(xwl_log_handler); if (AddScreen(xwl_screen_init, argc, argv) == -1) { FatalError("Couldn't add screen\n"); } xorgGlxCreateVendor(); LocalAccessScopeUser(); if (wm_fd >= 0 || init_fd >= 0) { if (wm_fd >= 0) TimerSet(NULL, 0, 1, add_client_fd, NULL); if (init_fd >= 0) ListenOnOpenFD(init_fd, FALSE); AddCallback(&SelectionCallback, wm_selection_callback, NULL); } else if (listen_fd_count > 0) { listen_on_fds(); } }