x2gokdrive-0.0.0.2/ChangeLog0000644000000000000000000004041414500121262012367 0ustar x2gokdrive (0.0.0.2-0x2go1) unstable; urgency=medium [ Mike Gabriel ] * New upstream version (0.0.0.2): - Various typo fixes. - patches.xorg/: add 21.1.8 subdirectory for current Debian testing/unstable with rebased patch set. * debian/rules: + Unapply patches from patches.xorg// directory before re-applying. Also remove quilt's .pc/ patch tracking directory before applying patches. [ Mihai Moldovan ] * New upstream version (0.0.0.2): - x2gokdriveremote.c: more typo fixes. - x2gokdrive.c: typo fix. - x2gokdriveinit.c: typo fix. - x2gokdriveselection.c: typo fixes. -- X2Go Release Manager Tue, 12 Sep 2023 15:17:46 +0200 x2gokdrive (0.0.0.1-0x2go1) unstable; urgency=medium [ Oleksandr Shneyder ] * Initial release: - Calculate screen dimensions (in mm) according to dpi value. Default DPI (Xorg) is 75. User can set DPI using -dpi command line option. - Move selection functionality to separate thread. Use XCB API to manage selections. - add xcb-xfixes to deps. - send a receive feature versions. - reinit client version on new connection and awaka sending thread when client version received. - support sending and receiving selections on demand. Support reading and writing INCR properties. - move declaration of RemoteHostVars from x2gokdriveremote.h to x2gokdriveremote.c. - add some support for HTML5 client (like converting pointer cursors to PNG format). - fix crashing if client is sending unrequested selection. - extended clipboard support for HTML client. - add name of the thread to the debug output. - move calling of possibly thread-unsafe ospoll functions (SetNotifyFd, RemoveNotifyFd) to main thread. - (re)enable sessions debugging. - fix infinite loop if reading of cookie has failed. - improve initialization of cursor frame and cache element structures. - improve clearing of the frame list. - reiniting of frame and cursors caches by client request. - don't check cache data size, only amount of elements. - reduce amount of cache elements to save resources. - rootless mode for x2gokdrive. - improve icon handling in rootless mode. - don't show invisible windows. - sending KEYRELEASE immediately after KEYPRESS to avoid the "key sticking". - set initial geometry form the -geometry command line option. - change from alder32 to crc32 to avoid collisions on small frames. - automatically decrease the jpeg quality when to many frames in queue. - update the screen with png frames when no data is transmitted. - make screen repaint faster. - add command line option for initial JPEG quality. - fix building on Xorg < 11900000. - don't exit when setting command line arguments -xkb-model, -xkb-layout, -xkb-variant on Xorg < 11899001. - support for windows with type _NET_WM_WINDOW_TYPE_DND. Ignore windows with visibility >= 2. - don't ignore windows with visibility == 2. Client should hide them from taskbar. [ Mihai Moldovan ] * Initial release: - patches.legacy/README.legacy-patches.md: whitespace-only fix. - patches.legacy/README.legacy-patches.md: fix markdown syntax. - {./,patches.xorg/{common,1.18.4,1.19.{2,6},1.20.{1,4,5}}/}quilt.env: add new quilt environment helper mechanism. Should make using quilt a lot easier on the developer's machine. Requires SOURCING(!) the quilt.env file within a specific versioned sub-directory OR SOURCING(!) the top-level quilt.env file and exporting QUILT_PATCHES manually. - patches.xorg/common/quilt.env: add trailing slash to QUILT_PATCHES variable. - patches.xorg/1.20.4/xorg-server-configure-ac.patch: backport XORG_VERSION_CURRENT change from e0dbca73f11e9aa7a066e748e6d08ba256be69cf / 1.20.5. - patches.xorg/1.20.4: add missing/hw/xfree86/common/modeline2c.awk file, working around a bug in CentOS 7 and Fedora 30 (possibly others as well). - patches.xorg/1.20.5: likewise add missing modeline2c.awk file. Actually needed for Fedora 30. - patches.xorg/1.19.2/xorg-server-configure-ac.patch: backport XORG_VERSION_CURRENT change from e0dbca73f11e9aa7a066e748e6d08ba256be69cf / 1.20.5. - x2gokdrive{remote,selection}.c: warp initializer into another set of curly braces until the first POD is reached. Fixes compile errors on EPEL 7 and generally systems with older GCC versions. That warning, which is turned into an error later on, is generally overly strict, since {0} is widely used as an "universal zero initializer" in C, initializing all other elements that are not explicitly given in the list implicitly with zero. For some reason, GCC decided that it is an error to initialize a whole struct that way and explicitly requires that at least one plain-old-data type is initialized that way. Case in point, newer GCC versions removed that warning altogether and just blindly accepts the usual syntax. - x2gokdriveselection.c: fix compile error, the xEvent struct (made up of union of another struct) needs another layer of curly braces. - patches.xorg/: add skeleton for 1.20.3 - needed for OpenSuSE Leap 15.1. - patches.xorg/1.20.3: add actual (rebased) patches and potentially missing files. - patches.xorg/1.18.4: refresh against Ubuntu 16.04/xenial version. - x2gokdrive{.c,remote.c,init.{c,h}}: patch for X.Org 1.18.x compatibility, merging in the content from patches.legacy/osuse_42.3.patch via preprocessor defines. - patches.xorg/: add 1.20.6 files, essentially copied and refreshed from 1.20.5. - patches.xorg/: add 1.20.7 files, essentially copied and refreshed from 1.20.6. - x2gokdrive{,remote}.c: fix logic flaws. - x2gokdriveremote.h: remove duplicate function declaration for clientReadNotify (). - patches.xorg/1.18.4/xorg-server-configure-ac.patch: add -lpthread to X2GOKDRIVE_LIBS. - patches.xorg/1.19.6: refresh patch set for Ubuntu 18.04/bionic, including backporting of the XORG_VERSION_CURRENT change. - patches.xorg/1.18.4/xorg-server-configure-ac.patch: add -lz and also -ljpeg and -lpng to be on the safe side, since it seems that these libraries are universally missing. - Makefile.am: add print-debugging to figure out what is being generated on Ubuntu 16.04/xenial. - Makefile.am: revert print-debugging again. - patches.xorg/1.18.4/xorg-server-configure-ac.patch: correctly add -pthread and -lpthread references *after* the pkgconfig checks execute. - quilt.env: add instructions from where to run the source command, this got me confused two years later. - patches.xorg/: add 1.20.13 subdirectory for Ubuntu Focal (20.04) with rebased patch set. - patches.xorg/: add 21.1.4 subdirectory for Ubuntu Kinetic (22.10) with rebased patch set. - patches.xorg/21.1.4/xorg-server-configure-ac.patch: fix FTBFS, typo when applying patch. - patches.xorg/: add 21.1.7 subdirectory for Debian Bookworm (12) with rebased patch set. - misc: pre-release date update. * debian/control: + Grammar fix. + Remove dependencies that refer to disabled features. + Add build-dependency upon libpam-dev. It would really be libpam0g-dev currently, but that looks like a moving target. + Add B-D upon x11proto-gl-dev (or nil/hello). + Recommend x2goserver >= 4.1.0.4, we'll better stay on the 4.1.x line. + Try to pull libxfont1-dev (for old Ubuntu versions such as 16.04/xenial that don't support building X.Org against libXfont2) and fallback to libxfont-dev to retain the old, default behavior. + Make libxfont1-dev an entirely optional dependency and libxfont-dev a hard one. This should always install libxfont-dev (which typically is the libXfont2-version), but also the libXfont1-version if available. Ubuntu 16.04/xenial has X.Org Server 1.18.4 which is not compatible with libXfont2, but Debian 9/stretch uses X.Org Server 1.19.2, which is compatible with libXfont2 (and actually requires it), but also has both packages available. + Depend upon libxfont1-dev << 1.5.2 (which is the version in Debian 9/stretch) or fall back to libxfont-dev *and* make sure that the libxfont1-dev version is greater than 1.4.2. This should essentially emulate libxfont1-dev (>> 1.4.2 << 1.5.2) | libxfont-dev (>> 1.4.2) and fix issues with "hello" being picked with subsequent dependencies being dropped (like libunwind, which is usually not optional). * x2gokdrive.spec: + Drop Debian-style formatting in description. + Typo fixes. + Remove empty line at EOF. + Copy summary from Debian's short description. + Spell out each (build) dependency on one line. + Whitespace-only fixes. + Backport changes from debian/rules. + Copy *.la file removal mechanism from debian/rules. + Pull in lsb-release on *SuSE systems and redhat-lsb otherwise for lsb_release, needed at package configuration time. + Enable hardening in a low-effort way. + Disable debugsource... disabling. Debug packages are actually useful! + Copy configure flags from debian/rules{,.flags}. Most compiler flags should be getting passed down automatically through the %configure macro, but CPPFLAGS is special and seemingly not defined in redhat-rpm-macros (or the *SuSE equivalent) and is hence passed-down manually. %{__global_ldflags} is empty and unknown on some systems, so copy workaround from nx-libs for that one. + Sync dependency lists with debian/control. + Rename binary package to xorg-x11-server-x2gokdrive to be consistent with Fedora/*SuSE package naming. + It's still %endif, not %fi. + Let description be the description of xorg-x11-server-x2gokdrive, not the x2gokdrive source package. + Add/copy Summary tag to xorg-x11-server-x2gokdrive binary package. + Add description for x2gokdrive (source) package. It's a slightly modified version of the binary package description. + Fix typo pkgconfig(Xau) => pkgconfig(xau). + Backport escaping layer change from debian/rules. + Fix %autosetup usage - only use it when supported. RPM 4.11.x+. + %autosetup (or %setup) create a top-level BUILD directory into which the source tarball is extracted - but we also need a BUILD sub-directory. Create it. + Use pushd instead of cd. Minor change. + Build-depend upon libgcrypt-devel for "older" distros that don't define a libgcrypt pkgconfig() virtual provide. That means: Fedora < 29, EPEL < 8 and any *SuSE version that is not Tumbleweed. The most surprising part is probably *SuSE. + Untangle libjpeg-turbo-devel build-dependency. Recent *SuSE versions define a pkgconfig(libturbojpeg) virtual provide, which is unheard of in RHEL land. Older *SuSE versions sadly don't have any virtual provide for this, and, worse, don't even have libjpeg-turbo-devel packages, so we'll need to build-depend upon libjpeg62-devel instead and hope that this is actually the turbo variant. RHEL-land (including Fedora) is more forgiving and always ships the turbo variant, but sets the virtual provide to pkgconfig(libjpeg) (yes, for all versions down to RHEL 6, albit via the updates repository!) and do not mention "turbo" in there. + Rework gettext-autopoint build dependency. *SuSE uses gettext-tools (which provides a virtual gettext-devel package), while RHEL-land has a "real" gettext-devel package that virtually provides a gettext-autopoint package. + Also build-depend upon pam-devel. + Build verbosely. We do want to see actual compilation steps. + Copy xorg-server source verbosely. Matches debian/rules tar call more closely. + Use archive mode when copying xorg-server source. We probably want to keep stuff like timestamps to not break the Makefile dependencies. + *SuSE puts the xorg-server source code into /usr/src/xserver. + Change /usr/share/xserver to /usr/src/xserver. For real this time. + Add hack installing missing files into the xorg-server source tree. + Port change from debian/rules.flags to disable Xorg DDX building. + Delete old configure files that might have had the executable bit set. We want those to be re-generated with the correct permissions later on. + Port *.la file removal commenting from debian/rules. + Pull in pkgconfig(glproto) BR. Needed for *SuSE, that doesn't seem to pull it in by other means (while RHEL-land does). + Fix %exclude entry for protocol.txt, the new configure flags changed its path to %{_libexecdir}. + Downgrade dependency upon xorg-x11-server-common to 1.18.4. Strictly speaking, we'd have to define a unique dependency for each distro-version combination (e.g., Fedora 30 uses 1.20.5, EPEL 7 currently uses 1.20.4 etc.), but that's too complicated - let's depend on at least the earliest supported version for now. + Work around issue on *SuSE: for some reason, Mesa-libGL-devel doesn't pull Mesa-devel in, leading to a compile failure. Do that manually. + Depend on/recommend x2goserver >= 4.1.0.4, backported from debian/control. + Change libunwind build-dependency and usage: for ppc64(be), use it when not on RHEL/CentOS (this includes *SuSE and Fedora) and for ppc64le, use it on RHEL/CentOS 8+ or when not on RHEL/CentOS. + Fix syntax error due to unclosed %if. + X11 server package is not split up into binary and common packages on *SuSE, so change dependency to xorg-x11-server. * debian/rules: + Remove weird empty variable reference construct. + Whitespace-only fixes. + Move options to the front of commands. + Drop useless use of cat. + Avoid backticks, use $() instead. + "a && b || c" doesn't really mean "if a then b else c", but something... more difficult: "c" does also run if "a" is false. Switch to a proper if-else construct. + Split up subshell content onto unique lines and fix bash syntax error near "exit 1". + Use printf instead of echo. Plain echo doesn't even substitute escape sequences for their plain char counterparts and the -e switch is non-portable. + Avoid xargs, use find's -exec feature. + More and better quoting. + Verbosely remove *.la files. + Add missing single quotes - two strings were merged into one by accident. + Drop additional escape layer in sed expression. This was previously only needed due to the weird escaping/quoting rules for code in backticks. The more modern and equally POSIX-compatible $() syntax makes quoting and escaping within subshell calls a lot easier. + Comment out *.la file removal. We shouldn't need that any longer since we don't build the Xorg DDX anymore. * debian/rules.flags: + Define NULL variable and use it throughout the file. + Disable building Xorg DDX. We don't need it and it's only inflating build times. Older X.Org patches will need to be modified to define the version variable, but we can do that as we go and accept build failures for the time being. [ Mike Gabriel ] * Initial release: - patches.xorg/: Add 1.20.11 files, essentially copied and refreshed from 1.20.7. This is the X.Org Xserver version shipped with Debian bullseye. - x2gokdriveinit.c: Only define ddxInputThreadInit() prototype for XORG_VERSION_CURRENT less than 1.20.7. Starting with 1.20.8, the prototype definition is now available in include/os.h. - x2gokdrivedebug.h: Introduce this new file and move all EPHYR_DBG stuff into there. And: disable EPHYR_WANT_DEBUG as with it, the project fails to build with standard Debian compiler flags." - patches.xorg/: Support building against xorg-server 21.1.3. * debian/control: + Fix B-Ds for building against Ubuntu trusty. + Add B-D mesa-common-dev. Introduced here with the X.Org Xserver 1.20.11 patchset. + Add B-D: libxcvt (or 'sl' for not so recent versions of Debian/Ubuntu). + No alternative 'hello' B-D for libunwind-dev. -- X2Go Release Manager Wed, 07 Jun 2023 21:37:44 +0200 x2gokdrive-0.0.0.2/Makefile0000644000000000000000000000064514500121262012257 0ustar include ../ephyr/Makefile VPATH = ../../../../../../hw/kdrive/x2gokdrive X2GO_OBJECTS = x2gokdriveselection.o x2gokdrive.o \ x2gokdriveinit.o x2gokdrivecursor.o x2gokdriveremote.o x2gokdrive: $(X2GO_OBJECTS) $(Xephyr_DEPENDENCIES) $(EXTRA_Xephyr_DEPENDENCIES) $(AM_V_CCLD)$(Xephyr_LINK) $(X2GO_OBJECTS) $(Xephyr_LDADD) $(LIBS) -lz -ljpeg -lpng -lpthread -lxcb-xfixes x2goclean: rm *.o x2gokdrive x2go: x2gokdrive x2gokdrive-0.0.0.2/Makefile.am0000644000000000000000000000343314500121262012651 0ustar # Copyright © 2013 Intel Corporation # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. SUBDIRS = man AM_CPPFLAGS = \ @KDRIVE_INCS@ \ @KDRIVE_CFLAGS@ \ @X2GOKDRIVE_INCS@ \ @X2GOKDRIVE_CFLAGS@ \ -DHAVE_DIX_CONFIG_H \ -I$(top_srcdir) \ -I$(top_srcdir)/exa bin_PROGRAMS = x2gokdrive x2gokdrive_SOURCES = \ x2gokdriveremote.c \ x2gokdriveremote.h \ x2gokdrive.c \ x2gokdrivecursor.c \ x2gokdrive.h \ x2gokdriveinit.c \ x2gokdrivelog.h \ x2gokdriveselection.c \ x2gokdriveselection.h \ $() x2gokdrive_LDADD = \ $(top_builddir)/exa/libexa.la \ @KDRIVE_LIBS@ \ @X2GOKDRIVE_LIBS@ x2gokdrive_DEPENDENCIES = @KDRIVE_LOCAL_LIBS@ x2gokdrive_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) relink: $(AM_V_at)rm -f $(bin_PROGRAMS) && $(MAKE) $(bin_PROGRAMS) x2gokdrive-0.0.0.2/man/Makefile.am0000644000000000000000000000007614500121262013424 0ustar include $(top_srcdir)/manpages.am appman_PRE = x2gokdrive.man x2gokdrive-0.0.0.2/man/x2gokdrive.man0000644000000000000000000000473214500121262014154 0ustar .\" .\" Copyright (c) Mike Gabriel .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, 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. .\" .TH x2gokdrive @appmansuffix@ @vendorversion@ .SH NAME x2gokdrive - X server providing a graphical backend for X2Go Server .SH SYNOPSIS .B x2gokdrive .RI [\fB:\fP display ] .RI [ option .IR ... ] .SH DESCRIPTION .B x2gokdrive is a kdrive server that provides a graphical backend for X2Go desktop sessions, supporting modern extensions like composite, damage and randr. .PP Unlike .I nxagent (aka x2goagent) which is an X proxy, i.e. limited to the capabilities of the host X server, .B x2gokdrive is a real X server which uses the host X server window as "framebuffer" via fast SHM XImages. .SH OPTIONS The server accepts all the standard options of Xserver(@appmansuffix@). .PP Furthermore, it understands the \fInxagent\fR-way of providing session options via the $DISPLAY environment variable. Currently, only a subset of \fInxagent's\fR nx/nx display options is supported. Non-supported nx/nx options get ignored. .SH "SIGNALS" Sending the SIGHUP signal to \fBx2gokdrive\fR switches the X server from running to suspend state and back. .PP Sending the SIGTERM signal to \fBx2gokdrive\fR shuts down the X server (and ends all applications attached to its $DISPLAY). .SH CAVEATS .PP .IP \(bu 2 The '-host-cursor' cursor is static in its appearance. .IP \(bu 2 The build gets a warning about 'nanosleep'. I think the various '-D' build flags are causing this. I haven't figured as yet how to work round it. It doesn't appear to break anything however. .SH "SEE ALSO" X(@miscmansuffix@), Xserver(@appmansuffix@), nxagent(@appmansuffic@), x2goagent(@appmansuffix@) .SH AUTHOR This man page has been written by Mike Gabriel for the X2Go Project (https://wiki.x2go.org).x2gokdrive-0.0.0.2/patches.legacy/osuse_42.3.patch0000644000000000000000000001121414500121262016330 0ustar diff --git a/Makefile b/Makefile index 14dd3e4..8cbd927 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ X2GO_OBJECTS = x2gokdrive.o os.o \ x2gokdriveinit.o x2gokdrivecursor.o remote.o x2gokdrive: $(X2GO_OBJECTS) $(Xephyr_DEPENDENCIES) $(EXTRA_Xephyr_DEPENDENCIES) - $(AM_V_CCLD)$(Xephyr_LINK) $(X2GO_OBJECTS) $(Xephyr_LDADD) $(LIBS) -lz -ljpeg -lpng + $(AM_V_CCLD)$(Xephyr_LINK) $(X2GO_OBJECTS) $(Xephyr_LDADD) $(LIBS) -lz -ljpeg -lpng -lpthread x2goclean: rm *.o x2gokdrive diff --git a/os.c b/os.c index 80426eb..041b960 100644 --- a/os.c +++ b/os.c @@ -47,4 +47,5 @@ EphyrInit(void) KdOsFuncs EphyrOsFuncs = { .Init = EphyrInit, + .pollEvents = pollEvents, }; diff --git a/remote.c b/remote.c index 9553f82..680424f 100644 --- a/remote.c +++ b/remote.c @@ -1332,7 +1332,7 @@ void *send_frame_thread (void *threadid) //only accept one client, close server socket shutdown(remoteVars.serversock, SHUT_RDWR); close(remoteVars.serversock); - SetNotifyFd(remoteVars.clientsock, clientReadNotify, X_NOTIFY_READ, NULL); + //SetNotifyFd(remoteVars.clientsock, clientReadNotify, X_NOTIFY_READ, NULL); remoteVars.client_connected=TRUE; remoteVars.client_initialized=FALSE; remoteVars.con_start_time=time(NULL); @@ -1347,7 +1347,7 @@ void *send_frame_thread (void *threadid) if(!remoteVars.client_connected) { EPHYR_DBG ("TCP connection closed\n"); - RemoveNotifyFd(remoteVars.clientsock); + //RemoveNotifyFd(remoteVars.clientsock); shutdown(remoteVars.clientsock, SHUT_RDWR); close(remoteVars.clientsock); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); @@ -1838,6 +1838,28 @@ clientReadNotify(int fd, int ready, void *data) } } +void pollEvents(void) +{ + //EPHYR_DBG("polling events"); + struct pollfd fds[2]; + int nfds = 1; + BOOL con; + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + con=remoteVars.client_connected; + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + if(!con) + return; + + memset(fds, 0 , sizeof(fds)); + fds[0].fd = remoteVars.clientsock; + fds[0].events = POLLIN; + if(poll(fds, nfds, 0)) + { + clientReadNotify(remoteVars.clientsock, 0, NULL); + } +} + + unsigned int checkSocketConnection(OsTimerPtr timer, CARD32 time, void* args) { EPHYR_DBG("CHECKING ACCEPTED CONNECTION"); diff --git a/remote.h b/remote.h index a92c20f..83e118b 100644 --- a/remote.h +++ b/remote.h @@ -87,6 +87,8 @@ #include #include #include +#include + @@ -330,6 +332,8 @@ struct RemoteHostVars typedef struct RemoteHostVars RemoteHostVars; +void clientReadNotify(int fd, int ready, void *data); +void pollEvents(void); void clear_cache_data(uint32_t maxsize); void clear_frame_cache(uint32_t max_elements); diff --git a/x2gokdrive.c b/x2gokdrive.c index 08c4616..ff0fff8 100644 --- a/x2gokdrive.c +++ b/x2gokdrive.c @@ -231,7 +231,7 @@ ephyrMapFramebuffer(KdScreenInfo * screen) buffer_height = ephyrBufferHeight(screen); priv->base = - remote_screen_init(screen, screen->x, screen->y, + remote_screen_init(screen, 0, 0, screen->width, screen->height, buffer_height, &priv->bytes_per_line, &screen->fb.bitsPerPixel); @@ -350,7 +350,7 @@ ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout) EphyrScrPriv *scrpriv = screen->driver; pScreen->BlockHandler = scrpriv->BlockHandler; - (*pScreen->BlockHandler)(pScreen, timeout); + (*pScreen->BlockHandler)(pScreen, timeout,NULL); scrpriv->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = ephyrScreenBlockHandler; @@ -1095,11 +1095,11 @@ ScreenPtr ephyrCursorScreen; /* screen containing the cursor */ static void ephyrWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) { - input_lock(); + //input_lock(); ephyrCursorScreen = pScreen; miPointerWarpCursor(inputInfo.pointer, pScreen, x, y); - input_unlock(); + //input_unlock(); } miPointerScreenFuncRec ephyrPointerScreenFuncs = { diff --git a/x2gokdriveinit.c b/x2gokdriveinit.c index 3b4bfce..353af13 100644 --- a/x2gokdriveinit.c +++ b/x2gokdriveinit.c @@ -51,6 +51,9 @@ void processScreenOrOutputArg(const char *screen_size, const char *output, char void processOutputArg(const char *output, char *parent_id); void processScreenArg(const char *screen_size, char *parent_id); +int dix_main(int argc, char *argv[], char *envp[]); + + int main(int argc, char *argv[], char *envp[]) { x2gokdrive-0.0.0.2/patches.legacy/README.legacy-patches.md0000644000000000000000000000153114500121262017653 0ustar # Building X2Go KDrive against old X.org versions The patches in this folder modify a specific version of x2gokdrive so that it builds against older X.org versions. Versions of x2gokdrive are specified by the exact Git commit hash of the x2gokdrive.git upstream Git repository. From time to time, whenever X2Go KDrive development advances, these patches need to be rebased against the latest x2gokdrive version. Due to this, it is crucial to keep this README file up-to-date and document what patches apply to what Git revision of x2gokdrive upstream code. ## openSUSE 42.3 Patch file: osuse\_42.3.patch Git commit hash: 5f025a7de290ff03eef74d8c1b81a88b54b6342d X.org version: ## SUSE Linux Enterprise Server 12 (sp1) Patch file: sles12sp1.patch Git commit hash: 5f025a7de290ff03eef74d8c1b81a88b54b6342d X.org version: x2gokdrive-0.0.0.2/patches.legacy/sles12sp1.patch0000644000000000000000000001117414500121262016266 0ustar diff --git a/os.c b/os.c index 80426eb..041b960 100644 --- a/os.c +++ b/os.c @@ -47,4 +47,5 @@ EphyrInit(void) KdOsFuncs EphyrOsFuncs = { .Init = EphyrInit, + .pollEvents = pollEvents, }; diff --git a/remote.c b/remote.c index 9553f82..680424f 100644 --- a/remote.c +++ b/remote.c @@ -1332,7 +1332,7 @@ void *send_frame_thread (void *threadid) //only accept one client, close server socket shutdown(remoteVars.serversock, SHUT_RDWR); close(remoteVars.serversock); - SetNotifyFd(remoteVars.clientsock, clientReadNotify, X_NOTIFY_READ, NULL); + //SetNotifyFd(remoteVars.clientsock, clientReadNotify, X_NOTIFY_READ, NULL); remoteVars.client_connected=TRUE; remoteVars.client_initialized=FALSE; remoteVars.con_start_time=time(NULL); @@ -1347,7 +1347,7 @@ void *send_frame_thread (void *threadid) if(!remoteVars.client_connected) { EPHYR_DBG ("TCP connection closed\n"); - RemoveNotifyFd(remoteVars.clientsock); + //RemoveNotifyFd(remoteVars.clientsock); shutdown(remoteVars.clientsock, SHUT_RDWR); close(remoteVars.clientsock); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); @@ -1838,6 +1838,28 @@ clientReadNotify(int fd, int ready, void *data) } } +void pollEvents(void) +{ + //EPHYR_DBG("polling events"); + struct pollfd fds[2]; + int nfds = 1; + BOOL con; + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + con=remoteVars.client_connected; + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + if(!con) + return; + + memset(fds, 0 , sizeof(fds)); + fds[0].fd = remoteVars.clientsock; + fds[0].events = POLLIN; + if(poll(fds, nfds, 0)) + { + clientReadNotify(remoteVars.clientsock, 0, NULL); + } +} + + unsigned int checkSocketConnection(OsTimerPtr timer, CARD32 time, void* args) { EPHYR_DBG("CHECKING ACCEPTED CONNECTION"); diff --git a/remote.h b/remote.h index a92c20f..83e118b 100644 --- a/remote.h +++ b/remote.h @@ -87,6 +87,8 @@ #include #include #include +#include + @@ -330,6 +332,8 @@ struct RemoteHostVars typedef struct RemoteHostVars RemoteHostVars; +void clientReadNotify(int fd, int ready, void *data); +void pollEvents(void); void clear_cache_data(uint32_t maxsize); void clear_frame_cache(uint32_t max_elements); diff --git a/x2gokdrive.c b/x2gokdrive.c index 08c4616..ff0fff8 100644 --- a/x2gokdrive.c +++ b/x2gokdrive.c @@ -231,7 +231,7 @@ ephyrMapFramebuffer(KdScreenInfo * screen) buffer_height = ephyrBufferHeight(screen); priv->base = - remote_screen_init(screen, screen->x, screen->y, + remote_screen_init(screen, 0, 0, screen->width, screen->height, buffer_height, &priv->bytes_per_line, &screen->fb.bitsPerPixel); @@ -350,7 +350,7 @@ ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout) EphyrScrPriv *scrpriv = screen->driver; pScreen->BlockHandler = scrpriv->BlockHandler; - (*pScreen->BlockHandler)(pScreen, timeout); + (*pScreen->BlockHandler)(pScreen, timeout,NULL); scrpriv->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = ephyrScreenBlockHandler; @@ -1095,11 +1095,11 @@ ScreenPtr ephyrCursorScreen; /* screen containing the cursor */ static void ephyrWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) { - input_lock(); + //input_lock(); ephyrCursorScreen = pScreen; miPointerWarpCursor(inputInfo.pointer, pScreen, x, y); - input_unlock(); + //input_unlock(); } miPointerScreenFuncRec ephyrPointerScreenFuncs = { diff --git a/x2gokdriveinit.c b/x2gokdriveinit.c index 3b4bfce..390ee41 100644 --- a/x2gokdriveinit.c +++ b/x2gokdriveinit.c @@ -51,6 +51,9 @@ void processScreenOrOutputArg(const char *screen_size, const char *output, char void processOutputArg(const char *output, char *parent_id); void processScreenArg(const char *screen_size, char *parent_id); +int dix_main(int argc, char *argv[], char *envp[]); + + int main(int argc, char *argv[], char *envp[]) { @@ -75,9 +78,19 @@ static const ExtensionModule ephyrExtensions[] = { static void ephyrExtensionInit(void) { - LoadExtensionList(ephyrExtensions, ARRAY_SIZE(ephyrExtensions), TRUE); + int i; + + for (i = 0; i < ARRAY_SIZE(ephyrExtensions); i++) + LoadExtension(&ephyrExtensions[i], TRUE); } +/* +static +void ephyrExtensionInit(void) +{ + LoadExtensionList(ephyrExtensions, ARRAY_SIZE(ephyrExtensions), TRUE); +} +*/ void InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv) x2gokdrive-0.0.0.2/patches.xorg/1.18.4/series0000644000000000000000000000010714500121262015163 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.18.4/xorg-server-configure-ac.patch0000644000000000000000000001111714500121262021615 0ustar --- a/configure.ac 2020-01-20 20:06:03.642526897 +0100 +++ b/configure.ac 2020-01-20 20:10:26.746419200 +0100 @@ -31,7 +31,7 @@ RELEASE_DATE="2016-07-19" RELEASE_NAME="Skordalia" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -644,6 +644,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) AC_ARG_ENABLE(xfake, AS_HELP_STRING([--enable-xfake], [Build the kdrive 'fake' server (default: auto)]), [XFAKE=$enableval], [XFAKE=auto]) AC_ARG_ENABLE(xfbdev, AS_HELP_STRING([--enable-xfbdev], [Build the kdrive framebuffer device server (default: auto)]), [XFBDEV=$enableval], [XFBDEV=auto]) dnl kdrive options @@ -2332,9 +2333,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + AC_DEFINE(KDRIVESERVER,1,[Build Kdrive X server]) AC_DEFINE(KDRIVEDDXACTIONS,,[Build kdrive ddx]) @@ -2445,6 +2452,48 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng " + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # Add missing pthread references to x2gokdrive binary linking. + X2GOKDRIVE_CFLAGS="${X2GOKDRIVE_CFLAGS} -pthread" + X2GOKDRIVE_LIBS="${X2GOKDRIVE_LIBS} -lpthread" + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_CFLAGS]) + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2460,6 +2509,7 @@ AM_CONDITIONAL(KDRIVE_MOUSE, [test "x$KD AM_CONDITIONAL(TSLIB, [test "x$HAVE_TSLIB" = xyes]) AM_CONDITIONAL(KDRIVEFBDEV, [test "x$XFBDEV" = xyes]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) AM_CONDITIONAL(BUILD_KDRIVEFBDEVLIB, [test "x$KDRIVE" = xyes && test "x$KDRIVEFBDEVLIB" = xyes]) AM_CONDITIONAL(XFAKESERVER, [test "x$KDRIVE" = xyes && test "x$XFAKE" = xyes]) @@ -2635,6 +2685,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/fake/Makefile hw/kdrive/fbdev/Makefile hw/kdrive/linux/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.18.4/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000131114500121262023254 0ustar --- a/hw/kdrive/Makefile.am 2020-01-20 12:22:40.859250080 +0100 +++ b/hw/kdrive/Makefile.am 2020-01-20 12:22:47.528277800 +0100 @@ -6,6 +6,10 @@ if XFAKESERVER XFAKE_SUBDIRS = fake endif +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif @@ -17,6 +21,7 @@ endif SERVER_SUBDIRS = \ $(FBDEV_SUBDIRS) \ $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) \ $(XFAKE_SUBDIRS) SUBDIRS = \ @@ -24,7 +29,7 @@ SUBDIRS = \ $(LINUX_SUBDIRS) \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = fbdev ephyr src linux fake +DIST_SUBDIRS = fbdev ephyr x2gokdrive src linux fake relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.19.2/series0000644000000000000000000000010714500121262015162 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.19.2/xorg-server-configure-ac.patch0000644000000000000000000001231014500121262021610 0ustar --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ RELEASE_DATE="2017-03-02" RELEASE_NAME="Clam Chowder" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -659,6 +659,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) AC_ARG_ENABLE(xfake, AS_HELP_STRING([--enable-xfake], [Build the kdrive 'fake' server (default: auto)]), [XFAKE=$enableval], [XFAKE=auto]) AC_ARG_ENABLE(xfbdev, AS_HELP_STRING([--enable-xfbdev], [Build the kdrive framebuffer device server (default: auto)]), [XFBDEV=$enableval], [XFBDEV=auto]) dnl kdrive options @@ -1868,6 +1869,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -2086,7 +2089,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2370,9 +2372,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + AC_DEFINE(KDRIVESERVER,1,[Build Kdrive X server]) AC_DEFINE(KDRIVEDDXACTIONS,,[Build kdrive ddx]) @@ -2483,6 +2491,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2498,6 +2543,7 @@ AM_CONDITIONAL(KDRIVE_MOUSE, [test "x$KD AM_CONDITIONAL(TSLIB, [test "x$HAVE_TSLIB" = xyes]) AM_CONDITIONAL(KDRIVEFBDEV, [test "x$XFBDEV" = xyes]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) AM_CONDITIONAL(BUILD_KDRIVEFBDEVLIB, [test "x$KDRIVE" = xyes && test "x$KDRIVEFBDEVLIB" = xyes]) AM_CONDITIONAL(XFAKESERVER, [test "x$KDRIVE" = xyes && test "x$XFAKE" = xyes]) @@ -2680,6 +2726,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/fake/Makefile hw/kdrive/fbdev/Makefile hw/kdrive/linux/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.19.2/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000140714500121262023261 0ustar Index: xorg-server/hw/kdrive/Makefile.am =================================================================== --- xorg-server.orig/hw/kdrive/Makefile.am +++ xorg-server/hw/kdrive/Makefile.am @@ -6,6 +6,10 @@ if XFAKESERVER XFAKE_SUBDIRS = fake endif +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif @@ -17,6 +21,7 @@ endif SERVER_SUBDIRS = \ $(FBDEV_SUBDIRS) \ $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) \ $(XFAKE_SUBDIRS) SUBDIRS = \ @@ -24,7 +29,7 @@ SUBDIRS = \ $(LINUX_SUBDIRS) \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = fbdev ephyr src linux fake +DIST_SUBDIRS = fbdev ephyr x2gokdrive src linux fake relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.19.6/series0000644000000000000000000000010714500121262015166 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.19.6/xorg-server-configure-ac.patch0000644000000000000000000001242214500121262021620 0ustar --- a/configure.ac 2017-12-20 21:32:33.000000000 +0100 +++ b/configure.ac 2020-01-20 17:51:18.248317548 +0100 @@ -31,7 +31,7 @@ RELEASE_DATE="2017-12-20" RELEASE_NAME="Lousiana Gumbo" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -659,6 +659,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) AC_ARG_ENABLE(xfake, AS_HELP_STRING([--enable-xfake], [Build the kdrive 'fake' server (default: auto)]), [XFAKE=$enableval], [XFAKE=auto]) AC_ARG_ENABLE(xfbdev, AS_HELP_STRING([--enable-xfbdev], [Build the kdrive framebuffer device server (default: auto)]), [XFBDEV=$enableval], [XFBDEV=auto]) dnl kdrive options @@ -1868,6 +1869,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -2086,7 +2089,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2370,9 +2372,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + AC_DEFINE(KDRIVESERVER,1,[Build Kdrive X server]) AC_DEFINE(KDRIVEDDXACTIONS,,[Build kdrive ddx]) @@ -2483,6 +2491,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2498,6 +2543,7 @@ AM_CONDITIONAL(KDRIVE_MOUSE, [test "x$KD AM_CONDITIONAL(TSLIB, [test "x$HAVE_TSLIB" = xyes]) AM_CONDITIONAL(KDRIVEFBDEV, [test "x$XFBDEV" = xyes]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) AM_CONDITIONAL(BUILD_KDRIVEFBDEVLIB, [test "x$KDRIVE" = xyes && test "x$KDRIVEFBDEVLIB" = xyes]) AM_CONDITIONAL(XFAKESERVER, [test "x$KDRIVE" = xyes && test "x$XFAKE" = xyes]) @@ -2681,6 +2727,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/fake/Makefile hw/kdrive/fbdev/Makefile hw/kdrive/linux/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.19.6/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000131114500121262023257 0ustar --- a/hw/kdrive/Makefile.am 2017-12-20 21:32:33.000000000 +0100 +++ b/hw/kdrive/Makefile.am 2020-01-20 17:51:45.597430805 +0100 @@ -6,6 +6,10 @@ if XFAKESERVER XFAKE_SUBDIRS = fake endif +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif @@ -17,6 +21,7 @@ endif SERVER_SUBDIRS = \ $(FBDEV_SUBDIRS) \ $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) \ $(XFAKE_SUBDIRS) SUBDIRS = \ @@ -24,7 +29,7 @@ SUBDIRS = \ $(LINUX_SUBDIRS) \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = fbdev ephyr src linux fake +DIST_SUBDIRS = fbdev ephyr x2gokdrive src linux fake relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.20.11/missing/hw/xfree86/common/modeline2c.awk0000644000000000000000000000656714500121262023430 0ustar #!/usr/bin/awk -f # # Copyright (c) 2007 Joerg Sonnenberger . # All rights reserved. # # Based on Perl script by Dirk Hohndel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Usage: modeline2c.awk < modefile > xf86DefModeSet.c # BEGIN { flagsdict[""] = "0" flagsdict["+hsync +vsync"] = "V_PHSYNC | V_PVSYNC" flagsdict["+hsync -vsync"] = "V_PHSYNC | V_NVSYNC" flagsdict["-hsync +vsync"] = "V_NHSYNC | V_PVSYNC" flagsdict["-hsync -vsync"] = "V_NHSYNC | V_NVSYNC" flagsdict["+hsync +vsync interlace"] = "V_PHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["+hsync -vsync interlace"] = "V_PHSYNC | V_NVSYNC | V_INTERLACE" flagsdict["-hsync +vsync interlace"] = "V_NHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["-hsync -vsync interlace"] = "V_NHSYNC | V_NVSYNC | V_INTERLACE" print "/* THIS FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT -- LOOK at" print " * modeline2c.awk */" print "" print "/*" print " * Author: Joerg Sonnenberger " print " * Based on Perl script from Dirk Hohndel " print " */" print "" print "#ifdef HAVE_XORG_CONFIG_H" print "#include " print "#endif" print "" print "#include \"xf86.h\"" print "#include \"xf86Config.h\"" print "#include \"xf86Priv.h\"" print "#include \"xf86_OSlib.h\"" print "" print "#include \"globals.h\"" print "" print "#define MODEPREFIX NULL, NULL, NULL, MODE_OK, M_T_DEFAULT" print "#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0" print "" print "const DisplayModeRec xf86DefaultModes [] = {" modeline = "\t{MODEPREFIX,%d, %d,%d,%d,%d,0, %d,%d,%d,%d,0, %s, MODESUFFIX},\n" modeline_data = "^[a-zA-Z]+[ \t]+[^ \t]+[ \t0-9.]+" } /^[mM][oO][dD][eE][lL][iI][nN][eE]/ { flags = $0 gsub(modeline_data, "", flags) flags = tolower(flags) printf(modeline, $3 * 1000, $4, $5, $6, $7, $8, $9, $10, $11, flagsdict[flags]) # Half-width double scanned modes printf(modeline, $3 * 500, $4/2, $5/2, $6/2, $7/2, $8/2, $9/2, $10/2, $11/2, flagsdict[flags] " | V_DBLSCAN") } /^#/ { print "/*" substr($0, 2) " */" } END { print "};" printf "const int xf86NumDefaultModes = ARRAY_SIZE(xf86DefaultModes);" } x2gokdrive-0.0.0.2/patches.xorg/1.20.11/series0000644000000000000000000000010714500121262015232 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.20.11/xorg-server-configure-ac.patch0000644000000000000000000001226114500121262021665 0ustar --- a/configure.ac 2021-06-13 22:26:02.644694476 +0200 +++ b/configure.ac 2021-06-13 22:26:02.640694461 +0200 @@ -31,7 +31,7 @@ RELEASE_DATE="2021-04-13" RELEASE_NAME="Arroz con Pollo" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -598,6 +598,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1786,6 +1787,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -2000,7 +2003,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2284,9 +2286,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2326,6 +2334,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2335,6 +2380,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl Xwayland DDX @@ -2556,6 +2602,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile hw/xwayland/Makefile test/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.20.11/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023326 0ustar --- a/hw/kdrive/Makefile.am 2020-01-13 23:57:05.000000000 +0100 +++ b/hw/kdrive/Makefile.am 2020-01-20 14:31:17.113943624 +0100 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.20.13/series0000644000000000000000000000010714500121262015234 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.20.13/xorg-server-configure-ac.patch0000644000000000000000000001226014500121262021666 0ustar --- a/configure.ac 2021-07-29 20:48:13.000000000 +0200 +++ b/configure.ac 2022-10-03 16:22:14.217919937 +0200 @@ -31,7 +31,7 @@ RELEASE_DATE="2021-07-29" RELEASE_NAME="Lemon Pepper Chicken" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-xz]) +AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -597,6 +597,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1770,6 +1771,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -1984,7 +1987,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2268,9 +2270,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2310,6 +2318,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2319,6 +2364,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl Xwayland DDX @@ -2540,6 +2586,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile hw/xwayland/Makefile test/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.20.13/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023330 0ustar --- a/hw/kdrive/Makefile.am 2021-07-29 20:48:14.000000000 +0200 +++ b/hw/kdrive/Makefile.am 2022-10-03 16:23:28.860229190 +0200 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.20.1/series0000644000000000000000000000010714500121262015151 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.20.1/xorg-server-configure-ac.patch0000644000000000000000000001006114500121262021600 0ustar --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ RELEASE_NAME="Kale Salad" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -597,6 +597,7 @@ dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -2306,9 +2307,15 @@ XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2348,6 +2355,43 @@ AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2357,6 +2401,7 @@ AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl Xwayland DDX @@ -2578,6 +2623,8 @@ hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile hw/xwayland/Makefile test/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.20.1/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000072514500121262023252 0ustar --- a/hw/kdrive/Makefile.am +++ b/hw/kdrive/Makefile.am @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.20.3/missing/hw/xfree86/common/modeline2c.awk0000644000000000000000000000656714500121262023351 0ustar #!/usr/bin/awk -f # # Copyright (c) 2007 Joerg Sonnenberger . # All rights reserved. # # Based on Perl script by Dirk Hohndel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Usage: modeline2c.awk < modefile > xf86DefModeSet.c # BEGIN { flagsdict[""] = "0" flagsdict["+hsync +vsync"] = "V_PHSYNC | V_PVSYNC" flagsdict["+hsync -vsync"] = "V_PHSYNC | V_NVSYNC" flagsdict["-hsync +vsync"] = "V_NHSYNC | V_PVSYNC" flagsdict["-hsync -vsync"] = "V_NHSYNC | V_NVSYNC" flagsdict["+hsync +vsync interlace"] = "V_PHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["+hsync -vsync interlace"] = "V_PHSYNC | V_NVSYNC | V_INTERLACE" flagsdict["-hsync +vsync interlace"] = "V_NHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["-hsync -vsync interlace"] = "V_NHSYNC | V_NVSYNC | V_INTERLACE" print "/* THIS FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT -- LOOK at" print " * modeline2c.awk */" print "" print "/*" print " * Author: Joerg Sonnenberger " print " * Based on Perl script from Dirk Hohndel " print " */" print "" print "#ifdef HAVE_XORG_CONFIG_H" print "#include " print "#endif" print "" print "#include \"xf86.h\"" print "#include \"xf86Config.h\"" print "#include \"xf86Priv.h\"" print "#include \"xf86_OSlib.h\"" print "" print "#include \"globals.h\"" print "" print "#define MODEPREFIX NULL, NULL, NULL, MODE_OK, M_T_DEFAULT" print "#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0" print "" print "const DisplayModeRec xf86DefaultModes [] = {" modeline = "\t{MODEPREFIX,%d, %d,%d,%d,%d,0, %d,%d,%d,%d,0, %s, MODESUFFIX},\n" modeline_data = "^[a-zA-Z]+[ \t]+[^ \t]+[ \t0-9.]+" } /^[mM][oO][dD][eE][lL][iI][nN][eE]/ { flags = $0 gsub(modeline_data, "", flags) flags = tolower(flags) printf(modeline, $3 * 1000, $4, $5, $6, $7, $8, $9, $10, $11, flagsdict[flags]) # Half-width double scanned modes printf(modeline, $3 * 500, $4/2, $5/2, $6/2, $7/2, $8/2, $9/2, $10/2, $11/2, flagsdict[flags] " | V_DBLSCAN") } /^#/ { print "/*" substr($0, 2) " */" } END { print "};" printf "const int xf86NumDefaultModes = ARRAY_SIZE(xf86DefaultModes);" } x2gokdrive-0.0.0.2/patches.xorg/1.20.3/series0000644000000000000000000000010714500121262015153 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.20.3/xorg-server-configure-ac.patch0000644000000000000000000001227114500121262021607 0ustar --- a/configure.ac 2019-11-13 10:55:52.806126410 +0100 +++ b/configure.ac 2019-11-13 10:58:27.147486941 +0100 @@ -31,7 +31,7 @@ RELEASE_DATE="2018-10-25" RELEASE_NAME="Harissa Roasted Carrots" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -597,6 +597,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1812,6 +1813,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -2026,7 +2029,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2306,9 +2308,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2348,6 +2356,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2357,6 +2402,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl Xwayland DDX @@ -2578,6 +2624,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile hw/xwayland/Makefile test/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.20.3/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023247 0ustar --- a/hw/kdrive/Makefile.am 2019-11-13 10:55:52.869126557 +0100 +++ b/hw/kdrive/Makefile.am 2019-11-13 10:58:32.697499905 +0100 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.20.4/missing/hw/xfree86/common/modeline2c.awk0000644000000000000000000000656714500121262023352 0ustar #!/usr/bin/awk -f # # Copyright (c) 2007 Joerg Sonnenberger . # All rights reserved. # # Based on Perl script by Dirk Hohndel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Usage: modeline2c.awk < modefile > xf86DefModeSet.c # BEGIN { flagsdict[""] = "0" flagsdict["+hsync +vsync"] = "V_PHSYNC | V_PVSYNC" flagsdict["+hsync -vsync"] = "V_PHSYNC | V_NVSYNC" flagsdict["-hsync +vsync"] = "V_NHSYNC | V_PVSYNC" flagsdict["-hsync -vsync"] = "V_NHSYNC | V_NVSYNC" flagsdict["+hsync +vsync interlace"] = "V_PHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["+hsync -vsync interlace"] = "V_PHSYNC | V_NVSYNC | V_INTERLACE" flagsdict["-hsync +vsync interlace"] = "V_NHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["-hsync -vsync interlace"] = "V_NHSYNC | V_NVSYNC | V_INTERLACE" print "/* THIS FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT -- LOOK at" print " * modeline2c.awk */" print "" print "/*" print " * Author: Joerg Sonnenberger " print " * Based on Perl script from Dirk Hohndel " print " */" print "" print "#ifdef HAVE_XORG_CONFIG_H" print "#include " print "#endif" print "" print "#include \"xf86.h\"" print "#include \"xf86Config.h\"" print "#include \"xf86Priv.h\"" print "#include \"xf86_OSlib.h\"" print "" print "#include \"globals.h\"" print "" print "#define MODEPREFIX NULL, NULL, NULL, MODE_OK, M_T_DEFAULT" print "#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0" print "" print "const DisplayModeRec xf86DefaultModes [] = {" modeline = "\t{MODEPREFIX,%d, %d,%d,%d,%d,0, %d,%d,%d,%d,0, %s, MODESUFFIX},\n" modeline_data = "^[a-zA-Z]+[ \t]+[^ \t]+[ \t0-9.]+" } /^[mM][oO][dD][eE][lL][iI][nN][eE]/ { flags = $0 gsub(modeline_data, "", flags) flags = tolower(flags) printf(modeline, $3 * 1000, $4, $5, $6, $7, $8, $9, $10, $11, flagsdict[flags]) # Half-width double scanned modes printf(modeline, $3 * 500, $4/2, $5/2, $6/2, $7/2, $8/2, $9/2, $10/2, $11/2, flagsdict[flags] " | V_DBLSCAN") } /^#/ { print "/*" substr($0, 2) " */" } END { print "};" printf "const int xf86NumDefaultModes = ARRAY_SIZE(xf86DefaultModes);" } x2gokdrive-0.0.0.2/patches.xorg/1.20.4/series0000644000000000000000000000010714500121262015154 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.20.4/xorg-server-configure-ac.patch0000644000000000000000000001215514500121262021611 0ustar --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ RELEASE_DATE="2019-02-25" RELEASE_NAME="Chestnut Tortelloni" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -599,6 +599,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1814,6 +1815,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -2028,7 +2031,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2308,9 +2310,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2350,6 +2358,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2359,6 +2404,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl Xwayland DDX @@ -2580,6 +2626,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile hw/xwayland/Makefile test/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.20.4/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023250 0ustar --- a/hw/kdrive/Makefile.am 2018-10-25 16:13:21.000000000 +0200 +++ b/hw/kdrive/Makefile.am 2019-06-11 14:24:53.626300847 +0200 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.20.5/missing/hw/xfree86/common/modeline2c.awk0000644000000000000000000000656714500121262023353 0ustar #!/usr/bin/awk -f # # Copyright (c) 2007 Joerg Sonnenberger . # All rights reserved. # # Based on Perl script by Dirk Hohndel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Usage: modeline2c.awk < modefile > xf86DefModeSet.c # BEGIN { flagsdict[""] = "0" flagsdict["+hsync +vsync"] = "V_PHSYNC | V_PVSYNC" flagsdict["+hsync -vsync"] = "V_PHSYNC | V_NVSYNC" flagsdict["-hsync +vsync"] = "V_NHSYNC | V_PVSYNC" flagsdict["-hsync -vsync"] = "V_NHSYNC | V_NVSYNC" flagsdict["+hsync +vsync interlace"] = "V_PHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["+hsync -vsync interlace"] = "V_PHSYNC | V_NVSYNC | V_INTERLACE" flagsdict["-hsync +vsync interlace"] = "V_NHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["-hsync -vsync interlace"] = "V_NHSYNC | V_NVSYNC | V_INTERLACE" print "/* THIS FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT -- LOOK at" print " * modeline2c.awk */" print "" print "/*" print " * Author: Joerg Sonnenberger " print " * Based on Perl script from Dirk Hohndel " print " */" print "" print "#ifdef HAVE_XORG_CONFIG_H" print "#include " print "#endif" print "" print "#include \"xf86.h\"" print "#include \"xf86Config.h\"" print "#include \"xf86Priv.h\"" print "#include \"xf86_OSlib.h\"" print "" print "#include \"globals.h\"" print "" print "#define MODEPREFIX NULL, NULL, NULL, MODE_OK, M_T_DEFAULT" print "#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0" print "" print "const DisplayModeRec xf86DefaultModes [] = {" modeline = "\t{MODEPREFIX,%d, %d,%d,%d,%d,0, %d,%d,%d,%d,0, %s, MODESUFFIX},\n" modeline_data = "^[a-zA-Z]+[ \t]+[^ \t]+[ \t0-9.]+" } /^[mM][oO][dD][eE][lL][iI][nN][eE]/ { flags = $0 gsub(modeline_data, "", flags) flags = tolower(flags) printf(modeline, $3 * 1000, $4, $5, $6, $7, $8, $9, $10, $11, flagsdict[flags]) # Half-width double scanned modes printf(modeline, $3 * 500, $4/2, $5/2, $6/2, $7/2, $8/2, $9/2, $10/2, $11/2, flagsdict[flags] " | V_DBLSCAN") } /^#/ { print "/*" substr($0, 2) " */" } END { print "};" printf "const int xf86NumDefaultModes = ARRAY_SIZE(xf86DefaultModes);" } x2gokdrive-0.0.0.2/patches.xorg/1.20.5/series0000644000000000000000000000010714500121262015155 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.20.5/xorg-server-configure-ac.patch0000644000000000000000000001232714500121262021613 0ustar diff --git a/configure.ac b/configure.ac index af16b0a..e4c71a7 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ RELEASE_DATE="2019-05-30" RELEASE_NAME="Red Lentil Dal" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -597,6 +597,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_STRING([--enable-glamor], [Build glamor di dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1812,6 +1813,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -2026,7 +2029,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2306,9 +2308,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2348,6 +2356,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2357,6 +2402,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl Xwayland DDX @@ -2578,6 +2624,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile hw/xwayland/Makefile test/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.20.5/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000105614500121262023254 0ustar diff --git a/hw/kdrive/Makefile.am b/hw/kdrive/Makefile.am index dc71dbd..0f83fc9 100644 --- a/hw/kdrive/Makefile.am +++ b/hw/kdrive/Makefile.am @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.20.6/missing/hw/xfree86/common/modeline2c.awk0000644000000000000000000000656714500121262023354 0ustar #!/usr/bin/awk -f # # Copyright (c) 2007 Joerg Sonnenberger . # All rights reserved. # # Based on Perl script by Dirk Hohndel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Usage: modeline2c.awk < modefile > xf86DefModeSet.c # BEGIN { flagsdict[""] = "0" flagsdict["+hsync +vsync"] = "V_PHSYNC | V_PVSYNC" flagsdict["+hsync -vsync"] = "V_PHSYNC | V_NVSYNC" flagsdict["-hsync +vsync"] = "V_NHSYNC | V_PVSYNC" flagsdict["-hsync -vsync"] = "V_NHSYNC | V_NVSYNC" flagsdict["+hsync +vsync interlace"] = "V_PHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["+hsync -vsync interlace"] = "V_PHSYNC | V_NVSYNC | V_INTERLACE" flagsdict["-hsync +vsync interlace"] = "V_NHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["-hsync -vsync interlace"] = "V_NHSYNC | V_NVSYNC | V_INTERLACE" print "/* THIS FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT -- LOOK at" print " * modeline2c.awk */" print "" print "/*" print " * Author: Joerg Sonnenberger " print " * Based on Perl script from Dirk Hohndel " print " */" print "" print "#ifdef HAVE_XORG_CONFIG_H" print "#include " print "#endif" print "" print "#include \"xf86.h\"" print "#include \"xf86Config.h\"" print "#include \"xf86Priv.h\"" print "#include \"xf86_OSlib.h\"" print "" print "#include \"globals.h\"" print "" print "#define MODEPREFIX NULL, NULL, NULL, MODE_OK, M_T_DEFAULT" print "#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0" print "" print "const DisplayModeRec xf86DefaultModes [] = {" modeline = "\t{MODEPREFIX,%d, %d,%d,%d,%d,0, %d,%d,%d,%d,0, %s, MODESUFFIX},\n" modeline_data = "^[a-zA-Z]+[ \t]+[^ \t]+[ \t0-9.]+" } /^[mM][oO][dD][eE][lL][iI][nN][eE]/ { flags = $0 gsub(modeline_data, "", flags) flags = tolower(flags) printf(modeline, $3 * 1000, $4, $5, $6, $7, $8, $9, $10, $11, flagsdict[flags]) # Half-width double scanned modes printf(modeline, $3 * 500, $4/2, $5/2, $6/2, $7/2, $8/2, $9/2, $10/2, $11/2, flagsdict[flags] " | V_DBLSCAN") } /^#/ { print "/*" substr($0, 2) " */" } END { print "};" printf "const int xf86NumDefaultModes = ARRAY_SIZE(xf86DefaultModes);" } x2gokdrive-0.0.0.2/patches.xorg/1.20.6/series0000644000000000000000000000010714500121262015156 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.20.6/xorg-server-configure-ac.patch0000644000000000000000000001226514500121262021615 0ustar --- a/configure.ac 2019-11-23 00:44:19.000000000 +0100 +++ b/configure.ac 2020-01-20 14:14:41.883851697 +0100 @@ -31,7 +31,7 @@ RELEASE_DATE="2019-11-22" RELEASE_NAME="Enchiladas de Queso" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -597,6 +597,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1769,6 +1770,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -1983,7 +1986,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2263,9 +2265,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2305,6 +2313,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2314,6 +2359,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl Xwayland DDX @@ -2535,6 +2581,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile hw/xwayland/Makefile test/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.20.6/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023252 0ustar --- a/hw/kdrive/Makefile.am 2019-11-23 00:44:19.000000000 +0100 +++ b/hw/kdrive/Makefile.am 2020-01-20 14:14:46.857872079 +0100 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/1.20.7/missing/hw/xfree86/common/modeline2c.awk0000644000000000000000000000656714500121262023355 0ustar #!/usr/bin/awk -f # # Copyright (c) 2007 Joerg Sonnenberger . # All rights reserved. # # Based on Perl script by Dirk Hohndel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Usage: modeline2c.awk < modefile > xf86DefModeSet.c # BEGIN { flagsdict[""] = "0" flagsdict["+hsync +vsync"] = "V_PHSYNC | V_PVSYNC" flagsdict["+hsync -vsync"] = "V_PHSYNC | V_NVSYNC" flagsdict["-hsync +vsync"] = "V_NHSYNC | V_PVSYNC" flagsdict["-hsync -vsync"] = "V_NHSYNC | V_NVSYNC" flagsdict["+hsync +vsync interlace"] = "V_PHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["+hsync -vsync interlace"] = "V_PHSYNC | V_NVSYNC | V_INTERLACE" flagsdict["-hsync +vsync interlace"] = "V_NHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["-hsync -vsync interlace"] = "V_NHSYNC | V_NVSYNC | V_INTERLACE" print "/* THIS FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT -- LOOK at" print " * modeline2c.awk */" print "" print "/*" print " * Author: Joerg Sonnenberger " print " * Based on Perl script from Dirk Hohndel " print " */" print "" print "#ifdef HAVE_XORG_CONFIG_H" print "#include " print "#endif" print "" print "#include \"xf86.h\"" print "#include \"xf86Config.h\"" print "#include \"xf86Priv.h\"" print "#include \"xf86_OSlib.h\"" print "" print "#include \"globals.h\"" print "" print "#define MODEPREFIX NULL, NULL, NULL, MODE_OK, M_T_DEFAULT" print "#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0" print "" print "const DisplayModeRec xf86DefaultModes [] = {" modeline = "\t{MODEPREFIX,%d, %d,%d,%d,%d,0, %d,%d,%d,%d,0, %s, MODESUFFIX},\n" modeline_data = "^[a-zA-Z]+[ \t]+[^ \t]+[ \t0-9.]+" } /^[mM][oO][dD][eE][lL][iI][nN][eE]/ { flags = $0 gsub(modeline_data, "", flags) flags = tolower(flags) printf(modeline, $3 * 1000, $4, $5, $6, $7, $8, $9, $10, $11, flagsdict[flags]) # Half-width double scanned modes printf(modeline, $3 * 500, $4/2, $5/2, $6/2, $7/2, $8/2, $9/2, $10/2, $11/2, flagsdict[flags] " | V_DBLSCAN") } /^#/ { print "/*" substr($0, 2) " */" } END { print "};" printf "const int xf86NumDefaultModes = ARRAY_SIZE(xf86DefaultModes);" } x2gokdrive-0.0.0.2/patches.xorg/1.20.7/series0000644000000000000000000000010714500121262015157 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/1.20.7/xorg-server-configure-ac.patch0000644000000000000000000001226614500121262021617 0ustar --- a/configure.ac 2020-01-13 23:57:05.000000000 +0100 +++ b/configure.ac 2020-01-20 14:31:12.970926474 +0100 @@ -31,7 +31,7 @@ RELEASE_DATE="2020-01-13" RELEASE_NAME="Stuffed French Toast" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -597,6 +597,7 @@ AC_ARG_ENABLE(glamor, AS_HELP_ST dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1769,6 +1770,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' @@ -1983,7 +1986,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2263,9 +2265,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2305,6 +2313,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2314,6 +2359,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl Xwayland DDX @@ -2535,6 +2581,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile hw/xwayland/Makefile test/Makefile x2gokdrive-0.0.0.2/patches.xorg/1.20.7/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023253 0ustar --- a/hw/kdrive/Makefile.am 2020-01-13 23:57:05.000000000 +0100 +++ b/hw/kdrive/Makefile.am 2020-01-20 14:31:17.113943624 +0100 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/21.1.3/missing/hw/xfree86/common/modeline2c.awk0000644000000000000000000000656714500121262023352 0ustar #!/usr/bin/awk -f # # Copyright (c) 2007 Joerg Sonnenberger . # All rights reserved. # # Based on Perl script by Dirk Hohndel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Usage: modeline2c.awk < modefile > xf86DefModeSet.c # BEGIN { flagsdict[""] = "0" flagsdict["+hsync +vsync"] = "V_PHSYNC | V_PVSYNC" flagsdict["+hsync -vsync"] = "V_PHSYNC | V_NVSYNC" flagsdict["-hsync +vsync"] = "V_NHSYNC | V_PVSYNC" flagsdict["-hsync -vsync"] = "V_NHSYNC | V_NVSYNC" flagsdict["+hsync +vsync interlace"] = "V_PHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["+hsync -vsync interlace"] = "V_PHSYNC | V_NVSYNC | V_INTERLACE" flagsdict["-hsync +vsync interlace"] = "V_NHSYNC | V_PVSYNC | V_INTERLACE" flagsdict["-hsync -vsync interlace"] = "V_NHSYNC | V_NVSYNC | V_INTERLACE" print "/* THIS FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT -- LOOK at" print " * modeline2c.awk */" print "" print "/*" print " * Author: Joerg Sonnenberger " print " * Based on Perl script from Dirk Hohndel " print " */" print "" print "#ifdef HAVE_XORG_CONFIG_H" print "#include " print "#endif" print "" print "#include \"xf86.h\"" print "#include \"xf86Config.h\"" print "#include \"xf86Priv.h\"" print "#include \"xf86_OSlib.h\"" print "" print "#include \"globals.h\"" print "" print "#define MODEPREFIX NULL, NULL, NULL, MODE_OK, M_T_DEFAULT" print "#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0" print "" print "const DisplayModeRec xf86DefaultModes [] = {" modeline = "\t{MODEPREFIX,%d, %d,%d,%d,%d,0, %d,%d,%d,%d,0, %s, MODESUFFIX},\n" modeline_data = "^[a-zA-Z]+[ \t]+[^ \t]+[ \t0-9.]+" } /^[mM][oO][dD][eE][lL][iI][nN][eE]/ { flags = $0 gsub(modeline_data, "", flags) flags = tolower(flags) printf(modeline, $3 * 1000, $4, $5, $6, $7, $8, $9, $10, $11, flagsdict[flags]) # Half-width double scanned modes printf(modeline, $3 * 500, $4/2, $5/2, $6/2, $7/2, $8/2, $9/2, $10/2, $11/2, flagsdict[flags] " | V_DBLSCAN") } /^#/ { print "/*" substr($0, 2) " */" } END { print "};" printf "const int xf86NumDefaultModes = ARRAY_SIZE(xf86DefaultModes);" } x2gokdrive-0.0.0.2/patches.xorg/21.1.3/series0000644000000000000000000000010714500121262015154 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/21.1.3/xorg-server-configure-ac.patch0000644000000000000000000001135714500121262021614 0ustar --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ RELEASE_NAME="Caramel Ice Cream" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-xz]) +AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -581,6 +581,7 @@ dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1764,6 +1765,8 @@ fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then PKG_CHECK_MODULES([LIBXCVT], $LIBXCVT) @@ -1972,7 +1975,6 @@ AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2191,9 +2193,15 @@ XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2233,6 +2241,43 @@ AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2242,6 +2287,7 @@ AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl and the rest of these are generic, so they're in config.h @@ -2372,6 +2418,8 @@ hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile test/Makefile xserver.ent x2gokdrive-0.0.0.2/patches.xorg/21.1.3/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023250 0ustar --- a/hw/kdrive/Makefile.am 2020-01-13 23:57:05.000000000 +0100 +++ b/hw/kdrive/Makefile.am 2020-01-20 14:31:17.113943624 +0100 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/21.1.4/series0000644000000000000000000000010714500121262015155 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/21.1.4/xorg-server-configure-ac.patch0000644000000000000000000001203014500121262021602 0ustar --- a/configure.ac 2022-07-12 15:27:57.000000000 +0200 +++ b/configure.ac 2022-10-03 16:54:44.247819939 +0200 @@ -31,7 +31,7 @@ RELEASE_DATE="2022-07-12" RELEASE_NAME="Caramel Ice Cream" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-xz]) +AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -580,6 +580,7 @@ AC_ARG_ENABLE(xf86-input-inputtest, AS_H dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1748,6 +1749,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then PKG_CHECK_MODULES([LIBXCVT], $LIBXCVT) @@ -1956,7 +1959,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2175,9 +2177,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2217,6 +2225,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2226,6 +2271,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl and the rest of these are generic, so they're in config.h @@ -2356,6 +2402,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile test/Makefile xserver.ent x2gokdrive-0.0.0.2/patches.xorg/21.1.4/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023251 0ustar --- a/hw/kdrive/Makefile.am 2022-07-12 15:27:57.000000000 +0200 +++ b/hw/kdrive/Makefile.am 2022-10-03 16:45:32.033221889 +0200 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/21.1.7/series0000644000000000000000000000010714500121262015160 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/21.1.7/xorg-server-configure-ac.patch0000644000000000000000000001203014500121262021605 0ustar --- a/configure.ac 2023-02-07 02:16:51.000000000 +0100 +++ b/configure.ac 2023-03-03 20:24:26.658268981 +0100 @@ -31,7 +31,7 @@ RELEASE_DATE="2023-02-07" RELEASE_NAME="Caramel Ice Cream" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-xz]) +AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -580,6 +580,7 @@ AC_ARG_ENABLE(xf86-input-inputtest, AS_H dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1747,6 +1748,8 @@ if test "x$XORG" = xauto; then fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then PKG_CHECK_MODULES([LIBXCVT], $LIBXCVT) @@ -1955,7 +1958,6 @@ if test "x$XORG" = xyes; then AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2174,9 +2176,15 @@ dnl kdrive DDX XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2216,6 +2224,43 @@ if test "$KDRIVE" = yes; then AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2225,6 +2270,7 @@ AC_SUBST([KDRIVE_MAIN_LIB]) AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl and the rest of these are generic, so they're in config.h @@ -2355,6 +2401,8 @@ hw/xquartz/xpr/Makefile hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile test/Makefile xserver.ent x2gokdrive-0.0.0.2/patches.xorg/21.1.7/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023254 0ustar --- a/hw/kdrive/Makefile.am 2023-02-07 02:16:51.000000000 +0100 +++ b/hw/kdrive/Makefile.am 2023-03-03 20:24:26.669269030 +0100 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/21.1.8/series0000644000000000000000000000010714500121262015161 0ustar xorg-server-configure-ac.patch xorg-server-hw-kdrive-Makefile-am.patch x2gokdrive-0.0.0.2/patches.xorg/21.1.8/xorg-server-configure-ac.patch0000644000000000000000000001166414500121262021622 0ustar Index: xorg-server/configure.ac =================================================================== --- xorg-server.orig/configure.ac 2023-08-29 00:16:39.747003728 +0000 +++ xorg-server/configure.ac 2023-08-29 00:16:39.739003719 +0000 @@ -31,7 +31,7 @@ RELEASE_NAME="Caramel Ice Cream" AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign dist-xz]) +AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects]) AC_USE_SYSTEM_EXTENSIONS # Require xorg-macros minimum of 1.14 for XORG_COMPILER_BRAND in XORG_DEFAULT_OPTIONS @@ -581,6 +581,7 @@ dnl kdrive and its subsystems AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(x2gokdrive, AS_HELP_STRING([--enable-x2gokdrive], [Build the kdrive x2gokdrive server (default: auto)]), [X2GOKDRIVE=$enableval], [X2GOKDRIVE=auto]) dnl kdrive options AC_ARG_ENABLE(libunwind, AS_HELP_STRING([--enable-libunwind], [Use libunwind for backtracing (default: auto)]), [LIBUNWIND="$enableval"], [LIBUNWIND="auto"]) AC_ARG_ENABLE(xshmfence, AS_HELP_STRING([--disable-xshmfence], [Disable xshmfence (default: auto)]), [XSHMFENCE="$enableval"], [XSHMFENCE="auto"]) @@ -1763,6 +1764,8 @@ fi AC_MSG_RESULT([$XORG]) +AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + if test "x$XORG" = xyes; then PKG_CHECK_MODULES([LIBXCVT], $LIBXCVT) @@ -1971,7 +1974,6 @@ AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) @@ -2190,9 +2192,15 @@ XEPHYR_LIBS= XEPHYR_INCS= +X2GOKDRIVE_LIBS= +X2GOKDRIVE_INCS= + AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) if test "$KDRIVE" = yes; then + + ### XEPHYR + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" @@ -2232,6 +2240,43 @@ AC_SUBST([XEPHYR_LIBS]) AC_SUBST([XEPHYR_INCS]) + + ### X2GOKDRIVE + + X2GOKDRIVE_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9.3 xcb-keysyms xcb-randr xcb-xkb xcb-xfixes zlib libjpeg libpng" + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + X2GOKDRIVE_REQUIRED_LIBS="$X2GOKDRIVE_REQUIRED_LIBS $LIBDRM xcb-glx xcb-xf86dri > 1.6" + fi + + if test "x$X2GOKDRIVE" = xauto; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS, [X2GOKDRIVE="yes"], [X2GOKDRIVE="no"]) + elif test "x$X2GOKDRIVE" = xyes ; then + PKG_CHECK_MODULES(X2GOKDRIVE, $X2GOKDRIVE_REQUIRED_LIBS) + fi + + # X2GOKDRIVE needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], X2GOKDRIVE_LIBS="$X2GOKDRIVE_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_SYNC_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + KDRIVE_MAIN_LIB="$MAIN_LIB" + KDRIVE_LOCAL_LIBS="$DIX_LIB $KDRIVE_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB" + KDRIVE_LIBS="$KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([X2GOKDRIVE_LIBS]) + AC_SUBST([X2GOKDRIVE_INCS]) + fi AC_SUBST([KDRIVE_INCS]) AC_SUBST([KDRIVE_PURE_INCS]) @@ -2241,6 +2286,7 @@ AC_SUBST([KDRIVE_LOCAL_LIBS]) AC_SUBST([KDRIVE_LIBS]) AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(X2GOKDRIVE, [test "x$KDRIVE" = xyes && test "x$X2GOKDRIVE" = xyes]) dnl and the rest of these are generic, so they're in config.h @@ -2371,6 +2417,8 @@ hw/kdrive/Makefile hw/kdrive/ephyr/Makefile hw/kdrive/ephyr/man/Makefile +hw/kdrive/x2gokdrive/Makefile +hw/kdrive/x2gokdrive/man/Makefile hw/kdrive/src/Makefile test/Makefile xserver.ent x2gokdrive-0.0.0.2/patches.xorg/21.1.8/xorg-server-hw-kdrive-Makefile-am.patch0000644000000000000000000000103514500121262023255 0ustar --- a/hw/kdrive/Makefile.am 2023-02-07 02:16:51.000000000 +0100 +++ b/hw/kdrive/Makefile.am 2023-03-03 20:24:26.669269030 +0100 @@ -1,15 +1,20 @@ +if X2GOKDRIVE +X2GOKDRIVE_SUBDIRS = x2gokdrive +endif + if XEPHYR XEPHYR_SUBDIRS = ephyr endif SERVER_SUBDIRS = \ - $(XEPHYR_SUBDIRS) + $(XEPHYR_SUBDIRS) \ + $(X2GOKDRIVE_SUBDIRS) SUBDIRS = \ src \ $(SERVER_SUBDIRS) -DIST_SUBDIRS = ephyr src +DIST_SUBDIRS = ephyr x2gokdrive src relink: $(AM_V_at)for i in $(SERVER_SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done x2gokdrive-0.0.0.2/patches.xorg/common/quilt.env0000644000000000000000000000130514500121262016356 0ustar typeset this_fake='' typeset -i cont='1' if [[ -n "${ZSH_VERSION}" ]]; then this_fake="${(%):-%x}" elif [[ -n "${BASH_VERSION}" ]]; then this_fake="${BASH_SOURCE[0]}" else printf 'Sorry, unsupported shell.\nThis helper will not work for you.\n' >&2 cont='0' fi if [[ '0' -ne "${cont}" ]]; then typeset this_real="$(readlink -ne "${this_fake}")" typeset this_dir="$(dirname "${this_fake}")" typeset this_version="$(basename "${this_dir}")" typeset this_patchesdir="$(basename "$(dirname "${this_dir}")")" this_dir="${this_patchesdir}/${this_version}" typeset top="$(dirname "$(dirname "$(dirname "${this_real}")")")" export QUILT_PATCHES="${top}/${this_dir}/" . "${top}/quilt.env" fi x2gokdrive-0.0.0.2/quilt.env0000644000000000000000000000101714500121262012461 0ustar # Maintainer helper for working with quilt. # If needed, adjust to your needs. # This file will not export QUILT_PATCHES directly. # If you use this, do it manually. # Alternatively, SOURCE(!) the quilt.env files within the versioned # sub-directories from the TOP directory(!) and everything should be set up # automagically. # Example, when in top source dir: source xorg.patches/1.20.13/quilt.env export QUILT_DIFF_ARGS='--no-index -pab --color=auto' export QUILT_DIFF_OPTS='-p' export QUILT_REFRESH_ARGS='-p ab --no-index' x2gokdrive-0.0.0.2/testscripts/run-x2gokdriveclient-to-x2gokdrive-on-localhost0000755000000000000000000001125314500121262024320 0ustar #!/bin/bash #/**************************************************************************/ #/* */ #/* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/. */ #/* Copyright (c) 2015-2023 Mike Gabriel */ #/* */ #/* The X2Go KDrive test scripts have been derived from test scripts */ #/* shipped with nx-libs (formerly known as nx-X11 / nxagent by NoMachine. */ #/* */ #/* Redistribution and use of the present software is allowed according */ #/* to terms specified by the GPL-2 (strictly version 2 only). */ #/* */ #/* All rights reserved. */ #/* */ #/* NOTE: This software has received contributions from various other */ #/* contributors, only the core maintainers and supporters are listed as */ #/* copyright holders. Please contact us, if you feel you should be listed */ #/* as copyright holder, as well. */ #/* */ #/**************************************************************************/ # # Uncomment this to enable echo. # #set -x # ulimit -c "unlimited" X2GOKDRIVECLIENTBIN="x2gokdriveclient" X2GOKDRIVEAGENTBIN="x2gokdrive" X2GO_PORT="9" X2GO_SYSTEM="${HOME}/.x2go" X2GO_ROOT="${HOME}/.x2go" # # This should be randomly generated. # #X2GO_COOKIE="$(xauth list |grep "${HOSTNAME}/unix:\<${X2GO_PORT}\>" | grep 'MIT' | cut -f '5' -d ' ')" X2GO_COOKIE="123efa980d2cba234ef6f73deac810ff" # # Create the directories for the X2Go KDrive session. # rm -rf "${X2GO_ROOT}/C-${X2GO_PORT}" || exit mkdir -p "${X2GO_ROOT}/C-${X2GO_PORT}" || exit rm -rf "${X2GO_ROOT}/S-${X2GO_PORT}" || exit mkdir -p "${X2GO_ROOT}/S-${X2GO_PORT}" || exit # # Create the fake cookie for this display. # echo "Creating the X authorization cookie." xauth add "${HOSTNAME}/unix:${X2GO_PORT}" "MIT-MAGIC-COOKIE-1" "${X2GO_COOKIE}" xauth add "${HOSTNAME}:${X2GO_PORT}" "MIT-MAGIC-COOKIE-1" "${X2GO_COOKIE}" # # Options are written in a file 'options' in the session # directory. The agent will use the DISPLAY settings, so # we pass in the DISPLAY the name of the options file. # # cache=8M,images=32M,link=modem,type=unix-kde,cleanup=0, # accept=62.98.198.1,cookie=$X2GO_COOKIE, # id=giulietta.nomachine.com-1098-6A4649FD0FCA57FAC275AF3F1C45B10F, # media=1:1098 # X2GO_HOST="nx/nx,cache=8192k,link=modem,menu=1,keybd=1,samba=0,cups=0,limit=0,\ accept=127.0.0.1,cookie=$X2GO_COOKIE,errors=${X2GO_ROOT}/C-${X2GO_PORT}/session" echo "${X2GO_HOST}:${X2GO_PORT}" >"${X2GO_ROOT}/C-${X2GO_PORT}/options" # # Run the agent. if you don't have a font server running, # remove the argument "-fp unix/:7100" # X2GO_AGENT=":${X2GO_PORT}" echo "Running the X client side X2Go KDrive agent." SAVED_DISPLAY="${DISPLAY}" DISPLAY="nx/nx,options=${X2GO_ROOT}/C-${X2GO_PORT}/options:${X2GO_PORT}" export DISPLAY #valgrind -v --num-callers=8 --error-limit=no --trace-children=no \ #valgrind --num-callers=8 --tool=memcheck --leak-check=yes --show-reachable=yes --track-fds=yes \ #ldd "${X2GOKDRIVEAGENTBIN}" "${X2GOKDRIVEAGENTBIN}" -name 'X2Go' -geometry "800x600+100+100" "${@}" \ "${X2GO_AGENT}" 2>>"${X2GO_ROOT}/C-${X2GO_PORT}/session" & # # The X server side proxy will forward the connection # to the original DISPLAY. # DISPLAY="${SAVED_DISPLAY}" export DISPLAY # # These are the x2gokdriveclient options used to run a typical session. # # cookie=$X2GO_COOKIE,root=/home/pinzari/.nx,media=32824, # session=kde_on_giulietta,id=giulietta.nomachine.com-1098-6A4649FD0FCA57FAC275AF3F1C45B10F, # connect=giulietta.nomachine.com:1098 # #X2GO_HOST="nx/nx,keybd=1,samba=1,cups=1,connect=localhost,cookie=${X2GO_COOKIE},errors=${X2GO_ROOT}/S-${X2GO_PORT}/session" X2GO_HOST="nx/nx,keybd=1,samba=0,cups=0,connect=localhost,cookie=${X2GO_COOKIE},errors=${X2GO_ROOT}/S-${X2GO_PORT}/session" echo "${X2GO_HOST}:${X2GO_PORT}" >"${X2GO_ROOT}/S-${X2GO_PORT}/options" echo "Running the X server side X2Go KDrive Client." #valgrind -v --num-callers=8 --error-limit=no --trace-children=no \ #valgrind --num-callers=8 --tool=memcheck --leak-check=yes --show-reachable=yes --track-fds=yes \ #ldd "${X2GOKDRIVECLIENTBIN}" "${X2GOKDRIVECLIENTBIN}" -S "nx/nx,options=${X2GO_ROOT}/S-${X2GO_PORT}/options:${X2GO_PORT}" \ 2>>"${X2GO_ROOT}/S-${X2GO_PORT}/session" & echo "Session running on display :$X2GO_PORT." x2gokdrive-0.0.0.2/testscripts/run-x2gokdriveclient-to-x2gokdrive-over-network0000755000000000000000000001243514500121262024363 0ustar #!/bin/bash #/**************************************************************************/ #/* */ #/* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/. */ #/* Copyright (c) 2015-2023 Mike Gabriel */ #/* */ #/* The X2Go KDrive test scripts have been derived from test scripts */ #/* shipped with nx-libs (formerly known as nx-X11 / nxagent by NoMachine. */ #/* */ #/* Redistribution and use of the present software is allowed according */ #/* to terms specified by the GPL-2 (strictly version 2 only). */ #/* */ #/* All rights reserved. */ #/* */ #/* NOTE: This software has received contributions from various other */ #/* contributors, only the core maintainers and supporters are listed as */ #/* copyright holders. Please contact us, if you feel you should be listed */ #/* as copyright holder, as well. */ #/* */ #/**************************************************************************/ # # Uncomment this to enable echo. # #set -x # ulimit -c "unlimited" X2GOKDRIVECLIENTBIN="x2gokdriveclient" X2GOKDRIVEAGENTBIN="x2gokdrive" ### ### Adapt to your needs: X2GOKDRIVEAGENT_HOST, X2GOKDRIVECLIENT_HOST ### ### This script launches x2gokdrive and has to be executed on the X2GOKDRIVEAGENT_HOST. ### On the X2GOKDRIVECLIENT_HOST you will have to execute x2gokdriveclient by copy+pasting ### some command lines... ### ### (Instructions for copy+pasting are given when this script has been launched). ### X2GOKDRIVEAGENT_HOST="127.0.0.1" # (e.g., 192.168.1.1, this scripts is launched on the X2GOKDRIVEAGENT_HOST machine) X2GOKDRIVECLIENT_HOST="127.0.0.1" # (e.g., 192.168.1.2, you want to connect x2gokdriveclient -> x2gokdrive from the X2GOKDRIVECLIENT_HOST machine) X2GO_PORT="9" X2GO_SYSTEM="${HOME}/.x2go" X2GO_ROOT="${HOME}/.x2go" # # This should be randomly generated. # #X2GO_COOKIE="$(xauth list |grep "${HOSTNAME}/unix:\<${X2GO_PORT}\>" | grep 'MIT' | cut -f '5' -d ' ')" X2GO_COOKIE="123efa980d2cba234ef6f73deac810ff" # # Create the directories for the X2Go KDrive session. # rm -rf "${X2GO_ROOT}/C-${X2GO_PORT}" || exit mkdir -p "${X2GO_ROOT}/C-${X2GO_PORT}" || exit rm -rf "${X2GO_ROOT}/S-${X2GO_PORT}" || exit mkdir -p "${X2GO_ROOT}/S-${X2GO_PORT}" || exit # # Create the fake cookie for this display. # echo "Creating the X authorization cookie." xauth add "${X2GOKDRIVECLIENT_HOST}/unix:${X2GO_PORT}" "MIT-MAGIC-COOKIE-1" "${X2GO_COOKIE}" xauth add "${X2GOKDRIVECLIENT_HOST}:${X2GO_PORT}" "MIT-MAGIC-COOKIE-1" "${X2GO_COOKIE}" # # Options are written in a file 'options' in the session # directory. The agent will use the DISPLAY settings, so # we pass in the DISPLAY the name of the options file. # # cache=8M,images=32M,link=modem,type=unix-kde,cleanup=0, # accept=62.98.198.1,cookie=${X2GO_COOKIE}, # id=giulietta.nomachine.com-1098-6A4649FD0FCA57FAC275AF3F1C45B10F, # media=1:1098 # X2GO_HOST="nx/nx,cache=8192k,link=modem,menu=1,keybd=1,samba=0,cups=0,limit=0,\ accept=${X2GOKDRIVECLIENT_HOST},cookie=${X2GO_COOKIE},errors=${X2GO_ROOT}/C-${X2GO_PORT}/session" echo "${X2GO_HOST}:${X2GO_PORT}" >"${X2GO_ROOT}/C-${X2GO_PORT}/options" # # Run the agent. if you don't have a font server running, # remove the argument "-fp unix/:7100" # X2GO_AGENT=":${X2GO_PORT}" echo "Running the X client side X2Go KDrive agent." SAVED_DISPLAY="${DISPLAY}" DISPLAY="nx/nx,options=${X2GO_ROOT}/C-${X2GO_PORT}/options:${X2GO_PORT}" export DISPLAY #valgrind -v --num-callers=8 --error-limit=no --trace-children=no \ #valgrind --num-callers=8 --tool=memcheck --leak-check=yes --show-reachable=yes --track-fds=yes \ #ldd "${X2GOKDRIVEAGENTBIN}" "${X2GOKDRIVEAGENTBIN}" -name 'X2Go' -geometry "800x600+100+100" "${@}" \ "${X2GO_AGENT}" 2>>"${X2GO_ROOT}/C-${X2GO_PORT}/session" & # # The X server side proxy will forward the connection # to the original DISPLAY. # DISPLAY="${SAVED_DISPLAY}" export DISPLAY # # These are the x2gokdriveclient options used to run a typical session. # # cookie=${X2GO_COOKIE},root=/home/pinzari/.x2go,media=32824, # session=kde_on_giulietta,id=giulietta.nomachine.com-1098-6A4649FD0FCA57FAC275AF3F1C45B10F, # connect=giulietta.nomachine.com:1098 # printf '\n%s\n\n' 'Now... COPY+PASTE the below lines to your local system' echo '--------------8<---------' #X2GO_HOST="nx/nx,keybd=1,samba=1,cups=1,connect=${X2GOKDRIVEAGENT_HOST},cookie=${X2GO_COOKIE},errors=${X2GO_ROOT}/S-${X2GO_PORT}/session" X2GO_HOST="nx/nx,keybd=1,samba=0,cups=0,connect=tcp:${X2GOKDRIVEAGENT_HOST}:4009,cookie=${X2GO_COOKIE},errors=${X2GO_ROOT}/S-${X2GO_PORT}/session" echo "X2GO_HOST=${X2GO_HOST}" echo "echo \"${X2GO_HOST}:${X2GO_PORT}\" >\"${X2GO_ROOT}/S-${X2GO_PORT}/options\"" echo "\"${X2GOKDRIVECLIENTBIN}\" -S \"nx/nx,options=${X2GO_ROOT}/S-${X2GO_PORT}/options:${X2GO_PORT}\" 2>>\"${X2GO_ROOT}/S-${X2GO_PORT}/session\"" printf '%s\n\n' '-------------->8---------' x2gokdrive-0.0.0.2/VERSION.x2gokdrive0000644000000000000000000000001014500121262013734 0ustar 0.0.0.2 x2gokdrive-0.0.0.2/x2gokdrive.c0000644000000000000000000011707214500121262013052 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Authored by Matthew Allum * * Copyright © 2007 OpenedHand Ltd * * 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 OpenedHand Ltd not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. OpenedHand Ltd makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL OpenedHand Ltd 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. * * Authors: * Dodji Seketeli */ #ifdef HAVE_CONFIG_H #include #if XORG_VERSION_CURRENT < 11999901 #include #endif /* XORG_VERSION_CURRENT */ #endif #include #include #include "x2gokdrive.h" #include "inputstr.h" #include "scrnintstr.h" #include "x2gokdrivelog.h" #include "xkbsrv.h" #ifdef EPHYR_WANT_DEBUG unsigned long long int debug_sendThreadId; unsigned long long int debug_selectThreadId; #endif /* EPHYR_WANT_DEBUG */ KdKeyboardInfo *ephyrKbd; KdPointerInfo *ephyrMouse; Bool ephyrNoDRI = FALSE; static int mouseState = 0; static Rotation ephyrRandr = RR_Rotate_0; typedef struct _EphyrInputPrivate { Bool enabled; } EphyrKbdPrivate, EphyrPointerPrivate; Bool EphyrWantGrayScale = 0; Bool EphyrWantResize = 0; Bool EphyrWantNoHostGrab = 0; Bool ephyrInitialize(KdCardInfo * card, EphyrPriv * priv) { OsSignal(SIGHUP, remote_handle_signal); OsSignal(SIGTERM, remote_handle_signal); priv->base = 0; priv->bytes_per_line = 0; return TRUE; } Bool ephyrCardInit(KdCardInfo * card) { EphyrPriv *priv; priv = (EphyrPriv *) malloc(sizeof(EphyrPriv)); if (!priv) return FALSE; if (!ephyrInitialize(card, priv)) { free(priv); return FALSE; } card->driver = priv; return TRUE; } Bool ephyrScreenInitialize(KdScreenInfo *screen) { EphyrScrPriv *scrpriv = screen->driver; CARD32 redMask, greenMask, blueMask; EPHYR_DBG("Init screen"); // if (EphyrWantGrayScale) // screen->fb.depth = 8; // // if (screen->fb.depth && screen->fb.depth != 0) { // if (screen->fb.depth < 0 // && (screen->fb.depth == 24 || screen->fb.depth == 16 // || screen->fb.depth == 8)) { // scrpriv->server_depth = screen->fb.depth; // } // else // ErrorF // ("\nXephyr: requested screen depth not supported, setting to match hosts.\n"); // } screen->fb.depth = 24; screen->rate = 72; if (screen->fb.depth <= 8) { if (EphyrWantGrayScale) screen->fb.visuals = ((1 << StaticGray) | (1 << GrayScale)); else screen->fb.visuals = ((1 << StaticGray) | (1 << GrayScale) | (1 << StaticColor) | (1 << PseudoColor) | (1 << TrueColor) | (1 << DirectColor)); screen->fb.redMask = 0x00; screen->fb.greenMask = 0x00; screen->fb.blueMask = 0x00; screen->fb.depth = 8; screen->fb.bitsPerPixel = 8; } else { screen->fb.visuals = (1 << TrueColor); if (screen->fb.depth <= 15) { screen->fb.depth = 15; screen->fb.bitsPerPixel = 16; } else if (screen->fb.depth <= 16) { screen->fb.depth = 16; screen->fb.bitsPerPixel = 16; } else if (screen->fb.depth <= 24) { screen->fb.depth = 24; screen->fb.bitsPerPixel = 32; } else if (screen->fb.depth <= 30) { screen->fb.depth = 30; screen->fb.bitsPerPixel = 32; } else { ErrorF("\nXephyr: Unsupported screen depth %d\n", screen->fb.depth); return FALSE; } redMask = 16711680; greenMask = 65280; blueMask = 255; screen->fb.redMask = (Pixel) redMask; screen->fb.greenMask = (Pixel) greenMask; screen->fb.blueMask = (Pixel) blueMask; } scrpriv->randr = screen->randr; return ephyrMapFramebuffer(screen); } void * ephyrWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, CARD32 *size, void *closure) { KdScreenPriv(pScreen); EphyrPriv *priv = pScreenPriv->card->driver; if (!pScreenPriv->enabled) return 0; *size = priv->bytes_per_line; return priv->base + row * priv->bytes_per_line + offset; } /** * Figure out display buffer size. If fakexa is enabled, allocate a larger * buffer so that fakexa has space to put offscreen pixmaps. */ int ephyrBufferHeight(KdScreenInfo * screen) { int buffer_height; if (ephyrFuncs.initAccel == NULL) buffer_height = screen->height; else buffer_height = 3 * screen->height; return buffer_height; } Bool ephyrMapFramebuffer(KdScreenInfo * screen) { EphyrScrPriv *scrpriv = screen->driver; EphyrPriv *priv = screen->card->driver; KdPointerMatrix m; int buffer_height; EPHYR_LOG("screen->width: %d, screen->height: %d index=%d", screen->width, screen->height, screen->mynum); /* * Use the rotation last applied to ourselves (in the Xephyr case the fb * coordinate system moves independently of the pointer coordiante system). */ KdComputePointerMatrix(&m, ephyrRandr, screen->width, screen->height); KdSetPointerMatrix(&m); buffer_height = ephyrBufferHeight(screen); priv->base = remote_screen_init(screen, #if XORG_VERSION_CURRENT < 11900000 0, 0, #else /* XORG_VERSION_CURRENT */ screen->x, screen->y, #endif /* XORG_VERSION_CURRENT */ screen->width, screen->height, buffer_height, &priv->bytes_per_line, &screen->fb.bitsPerPixel); if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All)) { scrpriv->shadow = FALSE; screen->fb.byteStride = priv->bytes_per_line; screen->fb.pixelStride = screen->width; screen->fb.frameBuffer = (CARD8 *) (priv->base); EPHYR_DBG("DIRECT FB"); } else { /* Rotated/Reflected so we need to use shadow fb */ scrpriv->shadow = TRUE; EPHYR_LOG("allocing shadow"); KdShadowFbAlloc(screen, scrpriv->randr & (RR_Rotate_90 | RR_Rotate_270)); } return TRUE; } void ephyrSetScreenSizes(ScreenPtr pScreen) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; if (scrpriv->randr & (RR_Rotate_0 | RR_Rotate_180)) { pScreen->width = screen->width; pScreen->height = screen->height; pScreen->mmWidth = screen->width_mm; pScreen->mmHeight = screen->height_mm; } else { pScreen->width = screen->height; pScreen->height = screen->width; pScreen->mmWidth = screen->height_mm; pScreen->mmHeight = screen->width_mm; } } Bool ephyrUnmapFramebuffer(KdScreenInfo * screen) { EphyrScrPriv *scrpriv = screen->driver; if (scrpriv->shadow) KdShadowFbFree(screen); /* Note, priv->base will get freed when XImage recreated */ return TRUE; } void ephyrShadowUpdate(ScreenPtr pScreen, shadowBufPtr pBuf) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EPHYR_LOG("slow paint"); /* FIXME: Slow Rotated/Reflected updates could be much * much faster efficiently updating via tranforming * pBuf->pDamage regions */ shadowUpdateRotatePacked(pScreen, pBuf); remote_paint_rect(screen, 0, 0, 0, 0, screen->width, screen->height); } static void ephyrInternalDamageRedisplay(ScreenPtr pScreen) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; RegionPtr pRegion; if (!scrpriv || !scrpriv->pDamage) return; pRegion = DamageRegion(scrpriv->pDamage); if (RegionNotEmpty(pRegion)) { int nbox; BoxPtr pbox; { nbox = RegionNumRects(pRegion); pbox = RegionRects(pRegion); while (nbox--) { remote_paint_rect(screen, pbox->x1, pbox->y1, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); pbox++; } } DamageEmpty(scrpriv->pDamage); } } static void ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout #if XORG_VERSION_CURRENT < 11900000 , void *pReadMask #endif /* XORG_VERSION_CURRENT */ ) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; pScreen->BlockHandler = scrpriv->BlockHandler; (*pScreen->BlockHandler)(pScreen, timeout #if XORG_VERSION_CURRENT < 11900000 , pReadMask #endif /* XORG_VERSION_CURRENT */ ); scrpriv->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = ephyrScreenBlockHandler; if (scrpriv->pDamage) ephyrInternalDamageRedisplay(pScreen); } Bool ephyrSetInternalDamage(ScreenPtr pScreen) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; PixmapPtr pPixmap = NULL; scrpriv->pDamage = DamageCreate((DamageReportFunc) 0, (DamageDestroyFunc) 0, DamageReportNone, TRUE, pScreen, pScreen); pPixmap = (*pScreen->GetScreenPixmap) (pScreen); DamageRegister(&pPixmap->drawable, scrpriv->pDamage); return TRUE; } void ephyrUnsetInternalDamage(ScreenPtr pScreen) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; DamageDestroy(scrpriv->pDamage); scrpriv->pDamage = NULL; } #ifdef RANDR Bool ephyrRandRGetInfo(ScreenPtr pScreen, Rotation * rotations) { rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen); EPHYR_DBG("GET RANDR INFO START"); *rotations = RR_Rotate_All | RR_Reflect_All; /* remove all sizes. This keep randr from changing our config */ if (pScrPriv->nSizes) { free(pScrPriv->pSizes); } pScrPriv->pSizes = NULL; pScrPriv->nSizes = 0; EPHYR_DBG("GET RANDR INFO END, SENDING SIZE NOTIFY"); // RRScreenSizeNotify(pScreen); return TRUE; } Bool ephyrRandRSetCRTC(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode, int x, int y, Rotation randr, int numOutputs, RROutputPtr * outputs) { EPHYR_DBG("SOMEONE TRYING TO CONFIG OUR CRTC!!!!"); return FALSE; } Bool ephyrRandRSetConfig(ScreenPtr pScreen, Rotation randr, int rate, RRScreenSizePtr pSize) { EphyrScrPriv oldscr = {0}; KdScreenInfo *screen = NULL; EphyrScrPriv *scrpriv = NULL; Bool wasEnabled; struct VirtScreen *virtualScreens = NULL; int oldwidth, oldheight, oldmmwidth, oldmmheight; Bool oldshadow; int newwidth, newheight; KdScreenPriv(pScreen); rrScrPrivPtr pScrPriv = {0}; EPHYR_DBG("SET RANDR CFG"); screen = pScreenPriv->screen; scrpriv = screen->driver; wasEnabled = pScreenPriv->enabled; virtualScreens=scrpriv->virtualScreens; if(!scrpriv->localRandrCall) { EPHYR_DBG("Someone trying to set RANDR config from outside. We do not allow it!"); return FALSE; } scrpriv->localRandrCall=FALSE; EPHYR_DBG("Trying to get virtual screens"); EPHYR_DBG("Virtual Screens: %p", scrpriv->virtualScreens); if (screen->randr & (RR_Rotate_0 | RR_Rotate_180)) { newwidth = pSize->width; newheight = pSize->height; } else { newwidth = pSize->height; newheight = pSize->width; } if (wasEnabled) KdDisableScreen(pScreen); oldscr = *scrpriv; oldwidth = screen->width; oldheight = screen->height; oldmmwidth = pScreen->mmWidth; oldmmheight = pScreen->mmHeight; oldshadow = scrpriv->shadow; /* * Set new configuration */ /* * We need to store the rotation value for pointer coords transformation; * though initially the pointer and fb rotation are identical, when we map * the fb, the screen will be reinitialized and return into an unrotated * state (presumably the HW is taking care of the rotation of the fb), but the * pointer still needs to be transformed. */ ephyrRandr = KdAddRotation(screen->randr, randr); scrpriv->randr = ephyrRandr; ephyrUnmapFramebuffer(screen); screen->width = newwidth; screen->height = newheight; screen->width_mm=(int)((double)screen->width/monitorResolution*25.4); screen->height_mm=(int)((double)screen->height/monitorResolution*25.4); scrpriv->win_width = screen->width; scrpriv->win_height = screen->height; if (!ephyrMapFramebuffer(screen)) goto bail4; /* FIXME below should go in own call */ if (oldshadow) KdShadowUnset(screen->pScreen); else ephyrUnsetInternalDamage(screen->pScreen); ephyrSetScreenSizes(screen->pScreen); if (scrpriv->shadow) { if (!KdShadowSet(screen->pScreen, scrpriv->randr, ephyrShadowUpdate, ephyrWindowLinear)) goto bail4; } else { /* Without shadow fb ( non rotated ) we need * to use damage to efficiently update display * via signal regions what to copy from 'fb'. */ if (!ephyrSetInternalDamage(screen->pScreen)) goto bail4; } /* * Set frame buffer mapping */ (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap(pScreen), pScreen->width, pScreen->height, screen->fb.depth, screen->fb.bitsPerPixel, screen->fb.byteStride, screen->fb.frameBuffer); /* set the subpixel order */ KdSetSubpixelOrder(pScreen, scrpriv->randr); if (wasEnabled) KdEnableScreen(pScreen); pScrPriv = rrGetScrPriv(pScreen); EPHYR_DBG("RANDR SET CONFIG, LET'S CHECK OUR RANDR SETTINGS"); // EPHYR_DBG("OUTPUTS: %d, CRTCS: %d, SIZES: %d, MODES %d" , pScrPriv->numOutputs, // pScrPriv->numCrtcs, pScrPriv->nSizes, pScrPriv->outputs[0]->numModes); if (pScrPriv->nSizes) { free(pScrPriv->pSizes); } pScrPriv->pSizes = NULL; pScrPriv->nSizes = 0; /* do not register any sizes */ // pSize = RRRegisterSize(pScreen, // screen->width, // screen->height, // screen->width_mm, // screen->height_mm); // // EPHYR_DBG("new size registered"); randr = KdSubRotation(scrpriv->randr, screen->randr); EPHYR_DBG("Sub Rotation done"); if(!virtualScreens) { EPHYR_DBG("HAVE NO VIRTUAL SCREENS"); updateOutput(pScreen, pScrPriv->outputs[0],screen->width, screen->height, 0,0, TRUE, TRUE); if( pScrPriv->numOutputs>1) { for(int i=1;inumOutputs;++i) { updateOutput(pScreen, pScrPriv->outputs[i],screen->width, screen->height, 0,0, FALSE, FALSE); } } } else { int i; for(i=0;i<4;++i) { EPHYR_DBG("PROCESS VIRTUAL SCREEN %d %dx%d %d,%d",i,virtualScreens[i].width, virtualScreens[i].height, virtualScreens[i].x, virtualScreens[i].y); if(!virtualScreens[i].width || !virtualScreens[i].height) { break; } if(pScrPriv->numOutputs>i) { EPHYR_DBG("Update output"); updateOutput(pScreen, pScrPriv->outputs[i],virtualScreens[i].width, virtualScreens[i].height, virtualScreens[i].x, virtualScreens[i].y, virtualScreens[i].isPrimary, TRUE); } else { char name[]="X2GoKDrive-x"; sprintf(name, "X2GoKDrive-%d",i); addOutput(pScreen, name,virtualScreens[i].width, virtualScreens[i].height, virtualScreens[i].x, virtualScreens[i].y, virtualScreens[i].isPrimary, TRUE); } } EPHYR_DBG("HAVE VIRTUAl SCREENS: %d, configured: %d",i,pScrPriv->numOutputs); for(;inumOutputs;++i) { EPHYR_DBG("Disconnecting virtual screen %d",i); updateOutput(pScreen, pScrPriv->outputs[i],screen->width, screen->height, 0,0, FALSE, FALSE); } } // RRSetCurrentConfig(pScreen, randr, 0, pSize); RRScreenSetSizeRange(pScreen, screen->width, screen->height, screen->width, screen->height); RRScreenSizeNotify(pScreen); RRSendConfigNotify(pScreen); // EPHYR_DBG("OUTPUTS: %d, CRTCS: %d, SIZES: %d, MODES %d" , pScrPriv->numOutputs, // pScrPriv->numCrtcs, pScrPriv->nSizes, pScrPriv->outputs[0]->numModes); // EPHYR_DBG("Have now sizes: %d",pScrPriv->nSizes); EPHYR_DBG("END RANDR SET CONFIG"); remote_send_main_image(); return TRUE; bail4: EPHYR_LOG("bailed"); ephyrUnmapFramebuffer(screen); *scrpriv = oldscr; (void) ephyrMapFramebuffer(screen); pScreen->width = oldwidth; pScreen->height = oldheight; pScreen->mmWidth = oldmmwidth; pScreen->mmHeight = oldmmheight; if (wasEnabled) KdEnableScreen(pScreen); return FALSE; } static void setOutput(ScreenPtr pScreen, RROutputPtr output, RRCrtcPtr crtc, int width, int height, int x, int y, BOOL primary, BOOL connected) { RRModePtr mode = NULL; xRRModeInfo modeInfo = {0}; RRModePtr *modes = NULL; char modename[56] = {0}; rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen); EPHYR_DBG("Set output %d %d %d %d", width, height, x,y); crtc->x=x; crtc->y=y; if(connected) RROutputSetConnection(output, RR_Connected); else RROutputSetConnection(output, RR_Disconnected); memset(&modeInfo, '\0', sizeof(modeInfo)); snprintf(modename, sizeof(modename), "%dx%d", width, height); modeInfo.width = width; modeInfo.height = height; modeInfo.hTotal =width; modeInfo.vTotal = height; modeInfo.dotClock= ((CARD32) width * (CARD32) height * (CARD32) 60); //+vSync|-hSync modeInfo.modeFlags=0x0004|0x0002; ; modeInfo.nameLength = strlen(modename); mode = RRModeGet(&modeInfo, modename); if (!mode) { EPHYR_DBG("can't create mode %s",modename); terminateServer(-1); } modes = malloc(sizeof(RRModePtr)); if (!modes) { EPHYR_DBG("NO RESOURCES to create MODE"); RRModeDestroy(mode); FreeResource(mode->mode.id, 0); terminateServer(-1); } // modes[output->numUserModes++] = mode; // output->userModes = modes; modes[output->numModes++] = mode; output->modes = modes; output->changed = TRUE; pScrPriv->changed = TRUE; pScrPriv->configChanged = TRUE; // output->numPreferred=0; RROutputSetPhysicalSize(output, width*pScreen->mmWidth/pScreen->width, height*pScreen->mmHeight/pScreen->height); EPHYR_DBG("RANDR SIZES - SCREEN %dx%d - %dx%d, OUTPUT %dx%d - %dx%d", pScreen->width, pScreen->height, pScreen->mmWidth, pScreen->mmHeight, width, height, width*pScreen->mmWidth/pScreen->width, height*pScreen->mmHeight/pScreen->height ); if(primary) { /* clear the old primary */ if (pScrPriv->primaryOutput) { RROutputChanged(pScrPriv->primaryOutput, 0); pScrPriv->primaryOutput = NULL; } /* set the new primary */ if (output) { pScrPriv->primaryOutput = output; RROutputChanged(output, 0); } pScrPriv->layoutChanged = TRUE; } EPHYR_DBG("OUPUT has now modes %d (%s)",output->numModes,modename); RRCrtcNotify(crtc, mode, x, y, pScrPriv->rotation, NULL, 1, &output); RROutputChanged(output, TRUE); } void updateOutput(ScreenPtr pScreen, RROutputPtr output, int width, int height, int x, int y, BOOL primary, BOOL connected) { /* clear old modes */ RROutputSetModes(output, NULL, 0, 0); if(!output->numCrtcs) { EPHYR_DBG("ERROR: output has no CRTCs"); terminateServer(-1); } setOutput(pScreen, output, output->crtcs[0], width, height, x, y, primary, connected); } void addOutput(ScreenPtr pScreen, char* name, int width, int height, int x, int y, BOOL primary, BOOL connected) { RROutputPtr output = {0}; RRCrtcPtr crtc = {0}; /* add new Output */ EPHYR_DBG("CREATE OUTPUT %s",name); output = RROutputCreate(pScreen, name, strlen(name), NULL); if (!output) { EPHYR_DBG("Can't create output %s", name); terminateServer(-1); } crtc = RRCrtcCreate(pScreen, NULL); if (!crtc) { EPHYR_DBG("Can't create CRTC for %s",name); terminateServer(-1); } RROutputSetCrtcs(output, &crtc, 1); RROutputSetSubpixelOrder(output, PictureGetSubpixelOrder(pScreen)); setOutput(pScreen, output, crtc, width, height, x, y, primary, connected); } Bool ephyrRandRInit(ScreenPtr pScreen) { rrScrPrivPtr pScrPriv; RRScreenSizePtr pSize; KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; Rotation randr; EphyrScrPriv *scrpriv = screen->driver; char output_name[]="X2GoKDrive-0"; scrpriv->virtualScreens=NULL; scrpriv->localRandrCall=FALSE; if (!RRScreenInit(pScreen)) return FALSE; pScrPriv = rrGetScrPriv(pScreen); pScrPriv->rrGetInfo = ephyrRandRGetInfo; pScrPriv->rrSetConfig = ephyrRandRSetConfig; pScrPriv->rrCrtcSet = ephyrRandRSetCRTC; EPHYR_DBG("RANDR INIT, HERE WE ARE DOING OUR RANDR INITIALIZATION"); EPHYR_DBG("OUTPUTS: %d, CRTCS: %d, SIZES: %d", pScrPriv->numOutputs, pScrPriv->numCrtcs, pScrPriv->nSizes); pSize = RRRegisterSize(pScreen, screen->width, screen->height, screen->width_mm, screen->height_mm); randr = KdSubRotation(scrpriv->randr, screen->randr); RRSetCurrentConfig(pScreen, randr, 0, pSize); addOutput(pScreen, output_name, screen->width, screen->height, 0,0, TRUE, TRUE); return TRUE; } Bool ephyrResizeScreen (ScreenPtr pScreen, int newwidth, int newheight, struct VirtScreen* virtualScreens) { KdScreenInfo *screen = NULL; EphyrScrPriv *scrpriv = NULL; KdScreenPriv(pScreen); RRScreenSize size = {0}; Bool ret; int t; EPHYR_DBG("EPHYR RESIZE SCREEN!!! %p %d %d",pScreen, newwidth, newheight); EPHYR_DBG("EPHYR RESIZE SCREEN 2"); screen = pScreenPriv->screen; scrpriv = screen->driver; scrpriv->virtualScreens=virtualScreens; EPHYR_DBG("Virtual Screens: %p", scrpriv->virtualScreens); if (screen->randr & (RR_Rotate_90|RR_Rotate_270)) { t = newwidth; newwidth = newheight; newheight = t; } if (newwidth == screen->width && newheight == screen->height) { // return FALSE; } size.width = newwidth; size.height = newheight; scrpriv->localRandrCall=TRUE; ret = ephyrRandRSetConfig (pScreen, screen->randr, 0, &size ); // if (ret) { // RROutputPtr output; // // output = RRFirstOutput(pScreen); // if (!output) // return FALSE; // RROutputSetModes(output, NULL, 0, 0); // } EPHYR_DBG("END EPHYR RESIZE SCREEN!!!"); return ret; } #endif Bool ephyrCreateColormap(ColormapPtr pmap) { return fbInitializeColormap(pmap); } Bool ephyrInitScreen(ScreenPtr pScreen) { EPHYR_LOG("pScreen->myNum:%d\n", pScreen->myNum); pScreen->CreateColormap = ephyrCreateColormap; return TRUE; } Bool ephyrFinishInitScreen(ScreenPtr pScreen) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; /* FIXME: Calling this even if not using shadow. * Seems harmless enough. But may be safer elsewhere. */ if (!shadowSetup(pScreen)) return FALSE; #ifdef RANDR if (!ephyrRandRInit(pScreen)) return FALSE; #endif scrpriv->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = ephyrScreenBlockHandler; return TRUE; } /* * Called by kdrive after calling down the * pScreen->CreateScreenResources() chain, this gives us a chance to * make any pixmaps after the screen and all extensions have been * initialized. */ Bool ephyrCreateResources(ScreenPtr pScreen) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; EPHYR_LOG("mark pScreen=%p mynum=%d shadow=%d", pScreen, pScreen->myNum, scrpriv->shadow); if (scrpriv->shadow) return KdShadowSet(pScreen, scrpriv->randr, ephyrShadowUpdate, ephyrWindowLinear); else { return ephyrSetInternalDamage(pScreen); } } #if XORG_VERSION_CURRENT < 11999901 void ephyrPreserve(KdCardInfo * card) { } Bool ephyrEnable(ScreenPtr pScreen) { return TRUE; } Bool ephyrDPMS(ScreenPtr pScreen, int mode) { return TRUE; } void ephyrDisable(ScreenPtr pScreen) { } void ephyrRestore(KdCardInfo * card) { } #endif /* XORG_VERSION_CURRENT */ void ephyrScreenFini(KdScreenInfo * screen) { EphyrScrPriv *scrpriv = screen->driver; if (scrpriv->shadow) { KdShadowFbFree(screen); } scrpriv->BlockHandler = NULL; } void ephyrCloseScreen(ScreenPtr pScreen) { ephyrUnsetInternalDamage(pScreen); } /* * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug. * See https://bugs.freedesktop.org/show_bug.cgi?id=3030 */ void ephyrUpdateModifierState(unsigned int state) { DeviceIntPtr pDev = inputInfo.keyboard; KeyClassPtr keyc = pDev->key; int i; CARD8 mask; int xkb_state; if (!pDev) return; xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state); state = state & 0xff; if (xkb_state == state) return; for (i = 0, mask = 1; i < 8; i++, mask <<= 1) { int key; /* Modifier is down, but shouldn't be */ if ((xkb_state & mask) && !(state & mask)) { int count = keyc->modifierKeyCount[i]; for (key = 0; key < MAP_LENGTH; key++) if (keyc->xkbInfo->desc->map->modmap[key] & mask) { if (mask == XCB_MOD_MASK_LOCK) { KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE); KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE); } else if (key_is_down(pDev, key, KEY_PROCESSED)) KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE); if (--count == 0) break; } } /* Modifier shoud be down, but isn't */ if (!(xkb_state & mask) && (state & mask)) for (key = 0; key < MAP_LENGTH; key++) if (keyc->xkbInfo->desc->map->modmap[key] & mask) { KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE); if (mask == XCB_MOD_MASK_LOCK) KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE); break; } } } static Bool ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) { return FALSE; } static void ephyrCrossScreen(ScreenPtr pScreen, Bool entering) { } ScreenPtr ephyrCursorScreen; /* screen containing the cursor */ static void ephyrWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) { #if XORG_VERSION_CURRENT >= 11900000 input_lock(); #endif /* XORG_VERSION_CURRENT */ ephyrCursorScreen = pScreen; miPointerWarpCursor(inputInfo.pointer, pScreen, x, y); #if XORG_VERSION_CURRENT >= 11900000 input_unlock(); #endif /* XORG_VERSION_CURRENT */ } miPointerScreenFuncRec ephyrPointerScreenFuncs = { ephyrCursorOffScreen, ephyrCrossScreen, ephyrWarpCursor, }; //static KdScreenInfo * //screen_from_window(Window w) //{ // int i = 0; // // for (i = 0; i < screenInfo.numScreens; i++) { // ScreenPtr pScreen = screenInfo.screens[i]; // KdPrivScreenPtr kdscrpriv = KdGetScreenPriv(pScreen); // KdScreenInfo *screen = kdscrpriv->screen; // EphyrScrPriv *scrpriv = screen->driver; // // } // // return NULL; //} //static void //ephyrProcessErrorEvent(xcb_generic_event_t *xev) //{ // xcb_generic_error_t *e = (xcb_generic_error_t *)xev; // // FatalError("X11 error\n" // "Error code: %hhu\n" // "Sequence number: %hu\n" // "Major code: %hhu\tMinor code: %hu\n" // "Error value: %u\n", // e->error_code, // e->sequence, // e->major_code, e->minor_code, // e->resource_id); //} //static void //ephyrProcessExpose(xcb_generic_event_t *xev) //{ // xcb_expose_event_t *expose = (xcb_expose_event_t *)xev; // KdScreenInfo *screen = screen_from_window(expose->window); // EphyrScrPriv *scrpriv = screen->driver; // // /* Wait for the last expose event in a series of cliprects // * to actually paint our screen. // */ // if (expose->count != 0) // return; // // // if (scrpriv) { // remote_paint_rect(scrpriv->screen, 0, 0, 0, 0, // scrpriv->win_width, // scrpriv->win_height); // } else { // EPHYR_LOG_ERROR("failed to get host screen\n"); // } //} void ephyrClientMouseMotion(int x,int y) { KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_POINTER_DESKTOP, x, y, 0); } void ephyrClientKey(int event_type, int state, int key) { ephyrUpdateModifierState(state); KdEnqueueKeyboardEvent(ephyrKbd, key, (event_type==KeyRelease)); } void ephyrClientButton(int event_type, int state, int button) { ephyrUpdateModifierState(state); /* This is a bit hacky. will break for button 5 ( defined as 0x10 ) * Check KD_BUTTON defines in kdrive.h */ if(event_type==ButtonPress) mouseState |= 1 << (button - 1); else mouseState &= ~(1 << (button - 1)); KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0); } //static void //ephyrProcessMouseMotion(xcb_generic_event_t *xev) //{ // xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xev; // KdScreenInfo *screen = screen_from_window(motion->event); // // if (!ephyrMouse || // !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) { // EPHYR_LOG("skipping mouse motion:%d\n", screen->pScreen->myNum); // return; // } // // if (ephyrCursorScreen != screen->pScreen) { // EPHYR_LOG("warping mouse cursor. " // "cur_screen:%d, motion_screen:%d\n", // ephyrCursorScreen->myNum, screen->pScreen->myNum); // ephyrWarpCursor(inputInfo.pointer, screen->pScreen, // motion->event_x, motion->event_y); // } // else { // int x = 0, y = 0; // // EPHYR_LOG("enqueuing mouse motion:%d\n", screen->pScreen->myNum); // x = motion->event_x; // y = motion->event_y; // EPHYR_LOG("initial (x,y):(%d,%d)\n", x, y); // EPHYR_DBG("initial (x,y):(%d,%d)\n", x, y); // // /* convert coords into desktop-wide coordinates. // * fill_pointer_events will convert that back to // * per-screen coordinates where needed */ // x += screen->pScreen->x; // y += screen->pScreen->y; // // KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_POINTER_DESKTOP, x, y, 0); // } //} //static void //ephyrProcessButtonPress(xcb_generic_event_t *xev) //{ // xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev; // // if (!ephyrMouse || // !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) { // EPHYR_LOG("skipping mouse press:%d\n", screen_from_window(button->event)->pScreen->myNum); // return; // } // // ephyrUpdateModifierState(button->state); // /* This is a bit hacky. will break for button 5 ( defined as 0x10 ) // * Check KD_BUTTON defines in kdrive.h // */ // mouseState |= 1 << (button->detail - 1); // // EPHYR_LOG("enqueuing mouse press:%d\n", screen_from_window(button->event)->pScreen->myNum); // KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0); //} //static void //ephyrProcessButtonRelease(xcb_generic_event_t *xev) //{ // xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev; // // if (!ephyrMouse || // !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) { // return; // } // // ephyrUpdateModifierState(button->state); // mouseState &= ~(1 << (button->detail - 1)); // // EPHYR_LOG("enqueuing mouse release:%d\n", screen_from_window(button->event)->pScreen->myNum); // KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0); //} ///* Xephyr wants ctrl+shift to grab the window, but that conflicts with // ctrl+alt+shift key combos. Remember the modifier state on key presses and // releases, if mod1 is pressed, we need ctrl, shift and mod1 released // before we allow a shift-ctrl grab activation. // // note: a key event contains the mask _before_ the current key takes // effect, so mod1_was_down will be reset on the first key press after all // three were released, not on the last release. That'd require some more // effort. // */ //static int //ephyrUpdateGrabModifierState(int state) //{ // static int mod1_was_down = 0; // // if ((state & (XCB_MOD_MASK_CONTROL|XCB_MOD_MASK_SHIFT|XCB_MOD_MASK_1)) == 0) // mod1_was_down = 0; // else if (state & XCB_MOD_MASK_1) // mod1_was_down = 1; // // return mod1_was_down; //} //static void //ephyrProcessKeyPress(xcb_generic_event_t *xev) //{ // xcb_key_press_event_t *key = (xcb_key_press_event_t *)xev; // // if (!ephyrKbd || // !((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled) { // return; // } // // ephyrUpdateGrabModifierState(key->state); // ephyrUpdateModifierState(key->state); // KdEnqueueKeyboardEvent(ephyrKbd, key->detail, FALSE); //} //static void //ephyrProcessKeyRelease(xcb_generic_event_t *xev) //{ //} //static void //ephyrProcessConfigureNotify(xcb_generic_event_t *xev) //{ // xcb_configure_notify_event_t *configure = // (xcb_configure_notify_event_t *)xev; // KdScreenInfo *screen = screen_from_window(configure->window); // EphyrScrPriv *scrpriv = screen->driver; // //// //#ifdef RANDR // ephyrResizeScreen(screen->pScreen, configure->width, configure->height, NULL); //#endif /* RANDR */ //} //static void //ephyrXcbProcessEvents(Bool queued_only) //{ //} //static void //ephyrXcbNotify(int fd, int ready, void *data) //{ // ephyrXcbProcessEvents(FALSE); //} void ephyrCardFini(KdCardInfo * card) { EphyrPriv *priv = card->driver; free(priv); } void ephyrGetColors(ScreenPtr pScreen, int n, xColorItem * pdefs) { /* XXX Not sure if this is right */ EPHYR_LOG("mark"); while (n--) { pdefs->red = 0; pdefs->green = 0; pdefs->blue = 0; pdefs++; } } void ephyrPutColors(ScreenPtr pScreen, int n, xColorItem * pdefs) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; int min, max, p; /* XXX Not sure if this is right */ min = 256; max = 0; while (n--) { p = pdefs->pixel; if (p < min) min = p; if (p > max) max = p; pdefs++; } if (scrpriv->pDamage) { BoxRec box; RegionRec region; box.x1 = 0; box.y1 = 0; box.x2 = pScreen->width; box.y2 = pScreen->height; RegionInit(®ion, &box, 1); DamageReportDamage(scrpriv->pDamage, ®ion); RegionUninit(®ion); } } /* Mouse calls */ static Status MouseInit(KdPointerInfo * pi) { pi->driverPrivate = (EphyrPointerPrivate *) calloc(sizeof(EphyrPointerPrivate), 1); ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE; pi->nAxes = 3; pi->nButtons = 32; free(pi->name); pi->name = strdup("Xephyr virtual mouse"); /* * Must transform pointer coords since the pointer position * relative to the Xephyr window is controlled by the host server and * remains constant regardless of any rotation applied to the Xephyr screen. */ pi->transformCoordinates = TRUE; ephyrMouse = pi; return Success; } static Status MouseEnable(KdPointerInfo * pi) { ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = TRUE; return Success; } static void MouseDisable(KdPointerInfo * pi) { ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE; return; } static void MouseFini(KdPointerInfo * pi) { free(pi->driverPrivate); ephyrMouse = NULL; return; } KdPointerDriver EphyrMouseDriver = { "ephyr", MouseInit, MouseEnable, MouseDisable, MouseFini, NULL, }; /* Keyboard */ static Status EphyrKeyboardInit(KdKeyboardInfo * ki) { ki->driverPrivate = (EphyrKbdPrivate *) calloc(sizeof(EphyrKbdPrivate), 1); ki->minScanCode = 8; ki->maxScanCode = 255; if (ki->name != NULL) { free(ki->name); } ki->name = strdup("Xephyr virtual keyboard"); ephyrKbd = ki; return Success; } //static //void EphyrKeyboardConfig(KeySymsPtr keySyms, CARD8 *modmap, XkbControlsPtr controls) //{ // // ephyrKbd->minScanCode = keySyms->minKeyCode; // ephyrKbd->maxScanCode = keySyms->maxKeyCode; // XkbApplyMappingChange(ephyrKbd->dixdev, &keySyms, // keySyms->minKeyCode, // keySyms->maxKeyCode - keySyms->minKeyCode + 1, // modmap, serverClient); // XkbDDXChangeControls(ephyrKbd->dixdev, &controls, &controls); // free(keySyms->map); // // //} static Status EphyrKeyboardEnable(KdKeyboardInfo * ki) { ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = TRUE; return Success; } static void EphyrKeyboardDisable(KdKeyboardInfo * ki) { ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = FALSE; } static void EphyrKeyboardFini(KdKeyboardInfo * ki) { free(ki->driverPrivate); ephyrKbd = NULL; return; } static void EphyrKeyboardLeds(KdKeyboardInfo * ki, int leds) { } static void EphyrKeyboardBell(KdKeyboardInfo * ki, int volume, int frequency, int duration) { } KdKeyboardDriver EphyrKeyboardDriver = { "ephyr", EphyrKeyboardInit, EphyrKeyboardEnable, EphyrKeyboardLeds, EphyrKeyboardBell, EphyrKeyboardDisable, EphyrKeyboardFini, NULL, }; x2gokdrive-0.0.0.2/x2gokdrivecursor.c0000644000000000000000000000654414500121262014311 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Author Oleksandr Shneyder * * Copyright © 2018-2023 phoca-GmbH * * * * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * Copyright © 2004 Nokia * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H #include #if XORG_VERSION_CURRENT < 11999901 #include #endif /* XORG_VERSION_CURRENT */ #endif #include "x2gokdrive.h" #include "x2gokdrivelog.h" #include "x2gokdriveremote.h" #include "cursorstr.h" #include #include static DevPrivateKeyRec ephyrCursorPrivateKey; typedef struct _ephyrCursor { xcb_cursor_t cursor; } ephyrCursorRec, *ephyrCursorPtr; static ephyrCursorPtr ephyrGetCursor(CursorPtr cursor) { return dixGetPrivateAddr(&cursor->devPrivates, &ephyrCursorPrivateKey); } //static void //ephyrRealizeCoreCursor(EphyrScrPriv *scr, CursorPtr cursor) //{ //} //static void //ephyrRealizeARGBCursor(EphyrScrPriv *scr, CursorPtr cursor) //{ //} //static Bool //can_argb_cursor(void) //{ // return TRUE; //} static Bool ephyrRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor) { // KdScreenPriv(screen); // KdScreenInfo *kscr = pScreenPriv->screen; // EphyrScrPriv *scr = kscr->driver; return TRUE; } static Bool ephyrUnrealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor) { ephyrCursorPtr hw = ephyrGetCursor(cursor); if (hw->cursor) { remote_removeCursor(cursor->serialNumber); hw->cursor = None; } return TRUE; } static void ephyrSetCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor, int x, int y) { // KdScreenPriv(screen); // KdScreenInfo *kscr = pScreenPriv->screen; // EphyrScrPriv *scr = kscr->driver; // uint32_t attr = None; if(cursor) remote_sendCursor(cursor); } static void ephyrMoveCursor(DeviceIntPtr dev, ScreenPtr screen, int x, int y) { } static Bool ephyrDeviceCursorInitialize(DeviceIntPtr dev, ScreenPtr screen) { return TRUE; } static void ephyrDeviceCursorCleanup(DeviceIntPtr dev, ScreenPtr screen) { } miPointerSpriteFuncRec EphyrPointerSpriteFuncs = { ephyrRealizeCursor, ephyrUnrealizeCursor, ephyrSetCursor, ephyrMoveCursor, ephyrDeviceCursorInitialize, ephyrDeviceCursorCleanup }; Bool ephyrCursorInit(ScreenPtr screen) { if (!dixRegisterPrivateKey(&ephyrCursorPrivateKey, PRIVATE_CURSOR_BITS, sizeof(ephyrCursorRec))) return FALSE; miPointerInitialize(screen, &EphyrPointerSpriteFuncs, &ephyrPointerScreenFuncs, FALSE); return TRUE; } x2gokdrive-0.0.0.2/x2gokdrive.h0000644000000000000000000001212414500121262013047 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Author Oleksandr Shneyder * * Copyright © 2018-2023 phoca-GmbH * * * * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * Copyright © 2004 Nokia * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef X2GOKDRIVE_H #define X2GOKDRIVE_H #include #include #include #include #include "os.h" /* for OsSignal() */ #include "kdrive.h" #include "x2gokdriveremote.h" //#include "exa.h" #ifdef RANDR #include "randrstr.h" #endif #include "damage.h" extern char client_host_addr[64]; typedef struct _ephyrPriv { CARD8 *base; int bytes_per_line; } EphyrPriv; struct VirtScreen { uint16_t width, height; int16_t x,y; BOOL isPrimary; }; typedef struct _ephyrScrPriv { /* ephyr server info */ struct VirtScreen* virtualScreens; Bool localRandrCall; Rotation randr; Bool shadow; DamagePtr pDamage; unsigned char *img; Bool win_explicit_position; int win_x, win_y; int win_width, win_height; int server_depth; const char *output; /* Set via -output option */ unsigned char *fb_data; /* only used when host bpp != server bpp */ xcb_shm_segment_info_t shminfo; KdScreenInfo *screen; int mynum; /* Screen number */ unsigned long cmap[256]; ScreenBlockHandlerProcPtr BlockHandler; } EphyrScrPriv; extern KdCardFuncs ephyrFuncs; extern KdKeyboardInfo *ephyrKbd; extern KdPointerInfo *ephyrMouse; extern miPointerScreenFuncRec ephyrPointerScreenFuncs; Bool ephyrResizeScreen (ScreenPtr pScreen, int newwidth, int newheight, struct VirtScreen* virtualScreens); void addOutput(ScreenPtr pScreen, char* name, int width, int height, int x, int y, BOOL primary, BOOL connected); void updateOutput(ScreenPtr pScreen, RROutputPtr output, int width, int height, int x, int y, BOOL primary, BOOL connected); void ephyrClientMouseMotion(int x,int y); void ephyrClientButton(int event_type, int state, int button); void ephyrClientKey(int event_type, int state, int key); Bool ephyrInitialize(KdCardInfo * card, EphyrPriv * priv); Bool ephyrCardInit(KdCardInfo * card); Bool ephyrScreenInitialize(KdScreenInfo *screen); Bool ephyrInitScreen(ScreenPtr pScreen); Bool ephyrFinishInitScreen(ScreenPtr pScreen); Bool ephyrCreateResources(ScreenPtr pScreen); void ephyrPreserve(KdCardInfo * card); Bool ephyrEnable(ScreenPtr pScreen); Bool ephyrDPMS(ScreenPtr pScreen, int mode); void ephyrDisable(ScreenPtr pScreen); void ephyrRestore(KdCardInfo * card); void ephyrScreenFini(KdScreenInfo * screen); void ephyrCloseScreen(ScreenPtr pScreen); void ephyrCardFini(KdCardInfo * card); void ephyrGetColors(ScreenPtr pScreen, int n, xColorItem * pdefs); void ephyrPutColors(ScreenPtr pScreen, int n, xColorItem * pdefs); Bool ephyrMapFramebuffer(KdScreenInfo * screen); void *ephyrWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, CARD32 *size, void *closure); void ephyrSetScreenSizes(ScreenPtr pScreen); Bool ephyrUnmapFramebuffer(KdScreenInfo * screen); void ephyrUnsetInternalDamage(ScreenPtr pScreen); Bool ephyrSetInternalDamage(ScreenPtr pScreen); Bool ephyrCreateColormap(ColormapPtr pmap); #ifdef RANDR Bool ephyrRandRGetInfo(ScreenPtr pScreen, Rotation * rotations); Bool ephyrRandRSetConfig(ScreenPtr pScreen, Rotation randr, int rate, RRScreenSizePtr pSize); Bool ephyrRandRSetCRTC(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode, int x, int y, Rotation randr, int numOutputs, RROutputPtr * outputs); Bool ephyrRandRInit(ScreenPtr pScreen); void ephyrShadowUpdate(ScreenPtr pScreen, shadowBufPtr pBuf); #endif void ephyrUpdateModifierState(unsigned int state); extern KdPointerDriver EphyrMouseDriver; extern KdKeyboardDriver EphyrKeyboardDriver; #if XORG_VERSION_CURRENT < 11999901 extern KdOsFuncs EphyrOsFuncs; #endif /* XORG_VERSION_CURRENT */ extern Bool ephyrCursorInit(ScreenPtr pScreen); extern int ephyrBufferHeight(KdScreenInfo * screen); /* ephyr_draw.c */ Bool ephyrDrawInit(ScreenPtr pScreen); void ephyrDrawEnable(ScreenPtr pScreen); void ephyrDrawDisable(ScreenPtr pScreen); void ephyrDrawFini(ScreenPtr pScreen); #endif /* X2GOKDRIVE_H */ x2gokdrive-0.0.0.2/x2gokdriveinit.c0000644000000000000000000002474014500121262013735 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Author Oleksandr Shneyder * * Copyright © 2018-2023 phoca-GmbH * * * * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * Copyright © 2004 Nokia * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H #include #if XORG_VERSION_CURRENT < 11999901 #include #endif /* XORG_VERSION_CURRENT */ #endif #include "x2gokdrive.h" #include "x2gokdrivelog.h" #include "glx_extinit.h" #include "x2gokdriveremote.h" #ifdef EPHYR_WANT_DEBUG extern unsigned long long int debug_sendThreadId; extern unsigned long long int debug_selectThreadId; #endif /* EPHYR_WANT_DEBUG */ extern Window EphyrPreExistingHostWin; extern Bool EphyrWantGrayScale; extern Bool EphyrWantResize; extern Bool EphyrWantNoHostGrab; extern Bool kdHasPointer; extern Bool kdHasKbd; #if XORG_VERSION_CURRENT < 11999901 #ifdef KDRIVE_EVDEV extern KdPointerDriver LinuxEvdevMouseDriver; extern KdKeyboardDriver LinuxEvdevKeyboardDriver; #endif /* KDRIVE_EVDEV */ #endif /* XORG_VERSION_CURRENT */ void processScreenOrOutputArg(const char *screen_size, const char *output, char *parent_id); void processOutputArg(const char *output, char *parent_id); void processScreenArg(const char *screen_size, char *parent_id); #if XORG_VERSION_CURRENT < 11999901 int ephyrInitFake(void); #endif /* XORG_VERSION_CURRENT */ #if XORG_VERSION_CURRENT < 12007000 #if INPUTTHREAD void ddxInputThreadInit(void); #endif /* INPUTTHREAD */ #endif /* XORG_VERSION_CURRENT */ int main(int argc, char *argv[], char *envp[]) { // hostx_use_resname(basename(argv[0]), 0); return dix_main(argc, argv, envp); } void InitCard(char *name) { EPHYR_DBG("mark"); KdCardInfoAdd(&ephyrFuncs, 0); } #if XORG_VERSION_CURRENT < 11999901 static const ExtensionModule ephyrExtensions[] = { #ifdef GLXEXT { GlxExtensionInit, "GLX", &noGlxExtension }, #endif }; static void ephyrExtensionInit(void) { LoadExtensionList(ephyrExtensions, ARRAY_SIZE(ephyrExtensions), TRUE); } #endif /* XORG_VERSION_CURRENT */ void InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv) { #if XORG_VERSION_CURRENT < 11999901 if (serverGeneration == 1) ephyrExtensionInit(); #endif /* XORG_VERSION_CURRENT */ if (serverGeneration == 1) { remote_selection_init(); } KdInitOutput(pScreenInfo, argc, argv); } void InitInput(int argc, char **argv) { KdKeyboardInfo *ki; KdPointerInfo *pi; #if XORG_VERSION_CURRENT < 11999901 #ifdef KDRIVE_EVDEV KdAddKeyboardDriver(&LinuxEvdevKeyboardDriver); KdAddPointerDriver(&LinuxEvdevMouseDriver); #endif /* KDRIVE_EVDEV */ #endif /* XORG_VERSION_CURRENT */ if (!SeatId) { KdAddKeyboardDriver(&EphyrKeyboardDriver); KdAddPointerDriver(&EphyrMouseDriver); if (!kdHasKbd) { ki = KdNewKeyboard(); if (!ki) FatalError("Couldn't create Xephyr keyboard\n"); ki->driver = &EphyrKeyboardDriver; KdAddKeyboard(ki); } if (!kdHasPointer) { pi = KdNewPointer(); if (!pi) FatalError("Couldn't create Xephyr pointer\n"); pi->driver = &EphyrMouseDriver; KdAddPointer(pi); } } KdInitInput(); } void CloseInput(void) { KdCloseInput(); } #if INPUTTHREAD /** This function is called in Xserver/os/inputthread.c when starting the input thread. */ void ddxInputThreadInit(void) { } #endif #ifdef DDXBEFORERESET void ddxBeforeReset(void) { } #endif void ddxUseMsg(void) { KdUseMsg(); } void processScreenOrOutputArg(const char *screen_size, const char *output, char *parent_id) { KdCardInfo *card; InitCard(0); /*Put each screen on a separate card */ card = KdCardInfoLast(); if (card) { KdScreenInfo *screen; // unsigned long p_id = 0; // Bool use_geometry; screen = KdScreenInfoAdd(card); KdParseScreen(screen, screen_size); screen->driver = calloc(1, sizeof(EphyrScrPriv)); if (!screen->driver) FatalError("Couldn't alloc screen private\n"); // if (parent_id) { // p_id = strtol(parent_id, NULL, 0); // } // use_geometry = (strchr(screen_size, '+') != NULL); EPHYR_DBG("screen number: %d, size: %s, output %s\n", screen->mynum, screen_size, output); // hostx_add_screen(screen, p_id, screen->mynum, use_geometry, output); } else { ErrorF("No matching card found!\n"); } } void processScreenArg(const char *screen_size, char *parent_id) { processScreenOrOutputArg(screen_size, NULL, parent_id); } void processOutputArg(const char *output, char *parent_id) { processScreenOrOutputArg("100x100+0+0", output, parent_id); } int ddxProcessArgument(int argc, char **argv, int i) { EPHYR_DBG("mark argv[%d]='%s'", i, argv[i]); if (!strcmp(argv[i], "-geometry")) { if ((i + 1) < argc) { /* compat with nxagent */ remote_set_init_geometry(argv[i+1]); return 2; } UseMsg(); exit(1); } #if XORG_VERSION_CURRENT < 11899001 /* * older versions didn't support this command line arguments. Maybe better to patch it with: * https://github.com/freedesktop/xorg-xserver/commit/40e32e9fc9f3a1bd8287ee03dd399d8161cb98dd */ else if (!strcmp(argv[i], "-xkb-model")) { if ((i + 1) < argc) { return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-xkb-layout")) { if ((i + 1) < argc) { return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-xkb-variant")) { if ((i + 1) < argc) { return 2; } UseMsg(); exit(1); } #endif /* XORG_VERSION_CURRENT */ else if (!strcmp(argv[i], "-quality")) { if ((i + 1) < argc) { /* compat with nxagent */ remote_set_jpeg_quality(argv[i+1]); return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-name")) { if ((i + 1) < argc) { /* compat with nxagent */ return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-clipboard")) { if ((i + 1) < argc) { /* compat with nxagent */ return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-nomagicpixel")) { if ((i + 1) < argc) { /* compat with nxagent */ return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-autodpi")) { if ((i + 1) < argc) { /* compat with nxagent */ return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-autograb")) { if ((i + 1) < argc) { /* compat with nxagent */ return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-keystrokefile")) { if ((i + 1) < argc) { /* compat with nxagent */ return 2; } UseMsg(); exit(1); } else if (!strcmp(argv[i], "-D")) { /* compat with nxagent */ return 1; } else if (!strcmp(argv[i], "-K")) { /* compat with nxagent */ return 1; } else if (!strcmp(argv[i], "-R")) { /* start in rootless mode */ remote_set_rootless(); return 1; } else if (argv[i][0] == ':') remote_set_display_name(argv[i]); return KdProcessArgument(argc, argv, i); } void OsVendorInit(void) { EPHYR_DBG("mark"); restartTimerOnInit(); // if (SeatId) // hostx_use_sw_cursor(); // // if (hostx_want_host_cursor()) // { ephyrFuncs.initCursor = &ephyrCursorInit; // } remote_init(); #if XORG_VERSION_CURRENT < 11999901 KdOsInit(&EphyrOsFuncs); #endif if (serverGeneration == 1) { if (!KdCardInfoLast()) { processScreenArg(remote_get_init_geometry(), NULL); } } } KdCardFuncs ephyrFuncs = { ephyrCardInit, /* cardinit */ ephyrScreenInitialize, /* scrinit */ ephyrInitScreen, /* initScreen */ ephyrFinishInitScreen, /* finishInitScreen */ ephyrCreateResources, /* createRes */ #if XORG_VERSION_CURRENT < 11999901 ephyrPreserve, /* preserve */ ephyrEnable, /* enable */ ephyrDPMS, /* dpms */ ephyrDisable, /* disable */ ephyrRestore, /* restore */ #endif /* XORG_VERSION_CURRENT */ ephyrScreenFini, /* scrfini */ ephyrCardFini, /* cardfini */ 0, /* initCursor */ #if XORG_VERSION_CURRENT < 11999901 0, /* enableCursor */ 0, /* disableCursor */ 0, /* finiCursor */ 0, /* recolorCursor */ #endif /* XORG_VERSION_CURRENT */ 0, /* initAccel */ 0, /* enableAccel */ 0, /* disableAccel */ 0, /* finiAccel */ ephyrGetColors, /* getColors */ ephyrPutColors, /* putColors */ ephyrCloseScreen, /* closeScreen */ }; #if XORG_VERSION_CURRENT < 11999901 /* * Fake nearly empty EphyrOsFuncs for builds against X.Org << 1.19.99.901 */ int ephyrInitFake(void) { return 1; } KdOsFuncs EphyrOsFuncs = { .Init = ephyrInitFake, #if XORG_VERSION_CURRENT < 11900000 .pollEvents = pollEvents, #endif /* XORG_VERSION_CURRENT */ }; #endif /* XORG_VERSION_CURRENT */ x2gokdrive-0.0.0.2/x2gokdrivelog.h0000644000000000000000000000604614500121262013557 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Authored by Matthew Allum * * Copyright © 2007 OpenedHand Ltd * * 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 OpenedHand Ltd not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. OpenedHand Ltd makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL OpenedHand Ltd 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. * * Authors: * Dodji Seketeli */ #ifndef X2GOKDRIVELOG_H #define X2GOKDRIVELOG_H #include #include "os.h" #ifndef DEBUG /*we are not in debug mode*/ #define EPHYR_LOG(...) #define EPHYR_LOG_ERROR(...) #endif /*!DEBUG */ #define ERROR_LOG_LEVEL 3 #define INFO_LOG_LEVEL 4 #ifndef EPHYR_LOG #define EPHYR_LOG(...) \ LogMessageVerb(X_NOTICE, INFO_LOG_LEVEL, "in %s:%d:%s: ",\ __FILE__, __LINE__, __func__) ; \ LogMessageVerb(X_NOTICE, INFO_LOG_LEVEL, __VA_ARGS__) #endif /*nomadik_log */ #ifndef EPHYR_LOG_ERROR #define EPHYR_LOG_ERROR(...) \ LogMessageVerb(X_NOTICE, ERROR_LOG_LEVEL, "Error:in %s:%d:%s: ",\ __FILE__, __LINE__, __func__) ; \ LogMessageVerb(X_NOTICE, ERROR_LOG_LEVEL, __VA_ARGS__) #endif /*EPHYR_LOG_ERROR */ #ifndef EPHYR_RETURN_IF_FAIL #define EPHYR_RETURN_IF_FAIL(cond) \ if (!(cond)) {EPHYR_LOG_ERROR("condition %s failed\n", #cond);return;} #endif /*nomadik_return_if_fail */ #ifndef EPHYR_RETURN_VAL_IF_FAIL #define EPHYR_RETURN_VAL_IF_FAIL(cond,val) \ if (!(cond)) {EPHYR_LOG_ERROR("condition %s failed\n", #cond);return val;} #endif /*nomadik_return_val_if_fail */ // # warning DEBUG ENABLED #define EPHYR_WANT_DEBUG #ifdef EPHYR_WANT_DEBUG #define EPHYR_DBG(x, a...) \ if(pthread_self()==debug_sendThreadId)\ fprintf(stderr,"SEND:"__FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a);\ else if (pthread_self()==debug_selectThreadId)\ fprintf(stderr,"SEL:"__FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a);\ else \ fprintf(stderr,"MAIN:"__FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a) #else #define EPHYR_DBG(x, a...) do {} while (0) #endif #endif /* X2GOKDRIVELOG_H */ x2gokdrive-0.0.0.2/x2gokdriveremote.c0000644000000000000000000051363214500121262014270 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Author Oleksandr Shneyder * * Copyright © 2018-2023 phoca-GmbH * * * * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * Copyright © 2004 Nokia * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H #include #if XORG_VERSION_CURRENT < 11999901 #include #endif /* XORG_VERSION_CURRENT */ #endif #include "x2gokdriveremote.h" #include "x2gokdriveselection.h" #include "x2gokdrivelog.h" #include "inputstr.h" #include #include #ifdef EPHYR_WANT_DEBUG extern unsigned long long int debug_sendThreadId; extern unsigned long long int debug_selectThreadId; #endif /* EPHYR_WANT_DEBUG */ typedef struct { int32_t flags; /* marks which fields in this structure are defined */ Bool input; /* does this application rely on the window manager to get keyboard input? */ int initial_state; /* see below */ Pixmap icon_pixmap; /* pixmap to be used as icon */ Window icon_window; /* window to be used as icon */ int icon_x, icon_y; /* initial position of icon */ Pixmap icon_mask; /* icon mask bitmap */ XID window_group; /* id of related window group */ /* this structure may be extended in the future */ } ExWMHints; #define ExInputHint (1L << 0) #define ExStateHint (1L << 1) #define ExIconPixmapHint (1L << 2) #define ExIconWindowHint (1L << 3) #define ExIconPositionHint (1L << 4) #define ExIconMaskHint (1L << 5) #define ExWindowGroupHint (1L << 6) #define ExXUrgencyHint (1L << 8) /* Size hints mask bits */ #define ExUSPosition (1L << 0) /* user specified x, y */ #define ExUSSize (1L << 1) /* user specified width, height */ #define ExPPosition (1L << 2) /* program specified position */ #define ExPSize (1L << 3) /* program specified size */ #define ExPMinSize (1L << 4) /* program specified minimum size */ #define ExPMaxSize (1L << 5) /* program specified maximum size */ #define ExPResizeInc (1L << 6) /* program specified resize increments */ #define ExPAspect (1L << 7) /* program specified min and max aspect ratios */ #define ExPBaseSize (1L << 8) #define ExPWinGravity (1L << 9) /* Values */ typedef struct { int32_t flags; /* marks which fields in this structure are defined */ int x, y; /* Obsolete */ int width, height; /* Obsolete */ int min_width, min_height; int max_width, max_height; int width_inc, height_inc; struct { int x; /* numerator */ int y; /* denominator */ } min_aspect, max_aspect; int base_width, base_height; int win_gravity; /* this structure may be extended in the future */ } ExSizeHints; /* init it in OsInit() */ static struct _remoteHostVars remoteVars = {0}; // struct _remoteHostVars RemoteHostVars; static BOOL remoteInitialized=FALSE; void remote_selection_init(void) { remoteVars.selstruct.readingInputBuffer=-1; remoteVars.selstruct.currentInputBuffer=CLIPBOARD; selection_init(&remoteVars); } void restartTimerOnInit(void) { if(remoteInitialized) { EPHYR_DBG("checking timer"); if(remoteVars.checkConnectionTimer) { EPHYR_DBG("restarting timer"); remoteVars.checkConnectionTimer=TimerSet(0,0,ACCEPT_TIMEOUT, checkSocketConnection, NULL); } } } static void cancelBeforeStart(void) { EPHYR_DBG("Closing server connection"); close_server_socket(); setAgentState(SUSPENDED); } void remote_handle_signal(int signum) { EPHYR_DBG("GOT SIGNAL %d",signum); if(signum == SIGTERM) { terminateServer(0); } if(signum==SIGHUP) { switch(remoteVars.agentState) { case TERMINATING: case TERMINATED:return; case STARTING: case RESUMING: { if(remoteVars.checkConnectionTimer) { TimerFree(remoteVars.checkConnectionTimer); remoteVars.checkConnectionTimer=0; } cancelBeforeStart(); return; } case RUNNING: { send_srv_disconnect(); disconnect_client(); return; } case SUSPENDED: { if(remoteVars.nxagentMode) readOptionsFromFile(); setAgentState(RESUMING); open_socket(); return; } } } } static int queue_elements(void) { int elems=0; struct sendqueue_element* current=remoteVars.first_sendqueue_element; while(current) { elems++; current=current->next; } return elems; } static BOOL isCursorSent(uint32_t serialNumber) { struct sentCursor* current=remoteVars.sentCursorsHead; while(current) { if(current->serialNumber == serialNumber) return TRUE; current=current->next; } return FALSE; } static void addSentCursor(uint32_t serialNumber) { // #warning check memory struct sentCursor* curs=malloc(sizeof(struct sentCursor)); curs->next=0; curs->serialNumber=serialNumber; if(!remoteVars.sentCursorsTail) { remoteVars.sentCursorsTail=remoteVars.sentCursorsHead=curs; } else { remoteVars.sentCursorsTail->next=curs; remoteVars.sentCursorsTail=curs; } } static void addCursorToQueue(struct cursorFrame* cframe) { if(!remoteVars.firstCursor) { remoteVars.firstCursor=remoteVars.lastCursor=cframe; } else { remoteVars.lastCursor->next=cframe; remoteVars.lastCursor=cframe; } } static void freeCursors(void) { struct sentCursor* cur = NULL; struct cursorFrame* curf = NULL; cur=remoteVars.sentCursorsHead; while(cur) { struct sentCursor* next=cur->next; free(cur); cur=next; } curf=remoteVars.firstCursor; while(curf) { struct cursorFrame* next=curf->next; if(curf->data) free(curf->data); free(curf); curf=next; } remoteVars.sentCursorsHead=remoteVars.sentCursorsTail=0; remoteVars.firstCursor=remoteVars.lastCursor=0; } void remote_removeCursor(uint32_t serialNumber) { struct sentCursor* cur = NULL; struct sentCursor* prev = NULL; struct deletedCursor* dcur = NULL; pthread_mutex_lock(&remoteVars.sendqueue_mutex); cur=remoteVars.sentCursorsHead; while(cur) { if(cur->serialNumber==serialNumber) { if(prev) prev->next=cur->next; if(cur==remoteVars.sentCursorsHead) remoteVars.sentCursorsHead=cur->next; if(cur==remoteVars.sentCursorsTail) remoteVars.sentCursorsTail=prev; free(cur); break; } prev=cur; cur=cur->next; } dcur=malloc(sizeof(struct deletedCursor)); dcur->serialNumber=serialNumber; dcur->next=0; if(remoteVars.last_deleted_cursor) { remoteVars.last_deleted_cursor->next=dcur; remoteVars.last_deleted_cursor=dcur; } else { remoteVars.first_deleted_cursor=remoteVars.last_deleted_cursor=dcur; } ++remoteVars.deletedcursor_list_size; pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } void remote_sendCursor(CursorPtr cursor) { BOOL cursorSent=FALSE; // #warning check memory struct cursorFrame* cframe=malloc(sizeof(struct cursorFrame)); bzero(cframe, sizeof(struct cursorFrame)); cframe->serialNumber=cursor->serialNumber; pthread_mutex_lock(&remoteVars.sendqueue_mutex); cursorSent=isCursorSent(cursor->serialNumber); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); if(!cursorSent) { if(cursor->bits->argb) { if(remoteVars.client_os == WEB) { //for web client we need to convert cursor data to PNG format cframe->data=(char*)png_compress( cursor->bits->width, cursor->bits->height, (unsigned char *)cursor->bits->argb, &cframe->size, TRUE); } else { cframe->size=cursor->bits->width*cursor->bits->height*4; cframe->data=malloc(cframe->size); memcpy(cframe->data, cursor->bits->argb, cframe->size); } } else { cframe->size=cursor->bits->width*cursor->bits->height*2; cframe->data=malloc(cframe->size); memcpy(cframe->data, cursor->bits->source, cframe->size/2); memcpy(cframe->data+cframe->size/2, cursor->bits->mask, cframe->size/2); } cframe->width=cursor->bits->width; cframe->height=cursor->bits->height; cframe->xhot=cursor->bits->xhot; cframe->yhot=cursor->bits->yhot; /* In X11 implementation we have 2bits for color, not from 0 to 255 but from 0 to 65535. * no idea why, RGBA is still 4bytes. I think one byte per color component is suuficient, * so let's just recalculate to 1byte per component */ cframe->backR=cursor->backRed*255./65535.0; cframe->backG=cursor->backGreen*255./65535.0; cframe->backB=cursor->backBlue*255./65535.0; cframe->forR=cursor->foreRed*255./65535.0; cframe->forG=cursor->foreGreen*255./65535.0; cframe->forB=cursor->foreBlue*255./65535.0; pthread_mutex_lock(&remoteVars.sendqueue_mutex); addSentCursor(cursor->serialNumber); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } pthread_mutex_lock(&remoteVars.sendqueue_mutex); addCursorToQueue(cframe); pthread_cond_signal(&remoteVars.have_sendqueue_cond); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } void remote_sendVersion(void) { unsigned char buffer[56] = {0}; _X_UNUSED int l; *((uint32_t*)buffer)=SERVERVERSION; //4B *((uint16_t*)buffer+2)=FEATURE_VERSION; EPHYR_DBG("Sending server version: %d", FEATURE_VERSION); l=remote_write_socket(remoteVars.clientsock_tcp,buffer,56); remoteVars.server_version_sent=TRUE; } void request_selection_from_client(enum SelectionType selection) { unsigned char buffer[56] = {0}; _X_UNUSED int l; *((uint32_t*)buffer)=DEMANDCLIENTSELECTION; //4B *((uint16_t*)buffer+2)=(uint16_t)selection; l=remote_write_socket(remoteVars.clientsock_tcp,buffer,56); EPHYR_DBG("requesting selection from client"); } static int32_t send_cursor(struct cursorFrame* cursor) { unsigned char* buffer; unsigned char static_buffer[64]={0}; _X_UNUSED int ln = 0; int l = 0; int sent = 0; buffer=static_buffer; *((uint32_t*)buffer)=CURSOR; //4B *((uint8_t*)buffer+4)=cursor->forR; *((uint8_t*)buffer+5)=cursor->forG; *((uint8_t*)buffer+6)=cursor->forB; *((uint8_t*)buffer+7)=cursor->backR; *((uint8_t*)buffer+8)=cursor->backG; *((uint8_t*)buffer+9)=cursor->backB;//10B *((uint16_t*)buffer+5)=cursor->width; *((uint16_t*)buffer+6)=cursor->height; *((uint16_t*)buffer+7)=cursor->xhot; *((uint16_t*)buffer+8)=cursor->yhot;//18B *((uint32_t*)buffer+5)=cursor->serialNumber; *((uint32_t*)buffer+6)=cursor->size; // EPHYR_DBG("SENDING CURSOR %d with size %d", cursor->serialNumber, cursor->size); // #warning check this ln=remote_write_socket(remoteVars.clientsock_tcp,buffer,56); while(sentsize) { l=remote_write_socket(remoteVars.clientsock_tcp, cursor->data+sent,((cursor->size-sent)size-sent):MAXMSGSIZE); if(l<0) { EPHYR_DBG("Error sending cursor!!!!!"); break; } sent+=l; } remoteVars.data_sent+=sent; // EPHYR_DBG("SENT total %d", total); return sent; } static int32_t send_frame(u_int32_t width, uint32_t height, uint32_t x, uint32_t y, uint32_t crc, struct frame_region* regions, uint32_t winId) { unsigned char buffer[64] = {0}; unsigned char* head_buffer=buffer; unsigned char* data=0; unsigned int header_size=8*4; unsigned int region_header_size=8*4; _X_UNUSED int ln = 0; int l = 0; int sent = 0; int i; //number of datagrams uint32_t total=0; uint32_t numofregions=0; for(i=0;i<9;++i) { if(regions[i].rect.size.width && regions[i].rect.size.height) ++numofregions; } //calculating total size of the data need to be sent if(remoteVars.send_frames_over_udp) { //frame header size total=header_size; for(i=0;i<9;++i) { if(!(regions[i].rect.size.width && regions[i].rect.size.height)) continue; //region header size total+=header_size; total+=regions[i].size; } // EPHYR_DBG("Sending frame, total size %d", total); data=malloc(total); memset(data,0,header_size); head_buffer=data; } *((uint32_t*)head_buffer)=FRAME; *((uint32_t*)head_buffer+1)=width; *((uint32_t*)head_buffer+2)=height; *((uint32_t*)head_buffer+3)=x; *((uint32_t*)head_buffer+4)=y; *((uint32_t*)head_buffer+5)=numofregions; *((uint32_t*)head_buffer+6)=crc; if(remoteVars.rootless) { *((uint32_t*)head_buffer+7)=winId; /*if(winId) { EPHYR_DBG("Sending frame for Window 0x%X",winId); }*/ } if(!remoteVars.send_frames_over_udp) { ln=remote_write_socket(remoteVars.clientsock_tcp, buffer,56); } else { //increment offset on frame header size head_buffer+=header_size; } for(i=0;i<9;++i) { if(!(regions[i].rect.size.width && regions[i].rect.size.height)) continue; // EPHYR_DBG("SENDING FRAME REGION %x %dx%d %d",regions[i].source_crc, regions[i].rect.size.width, regions[i].rect.size.height, // regions[i].size); *((uint32_t*)head_buffer)=regions[i].source_crc; // if(*((uint32_t*)buffer)=regions[i].source_crc) // EPHYR_DBG("SENDING REFERENCE %x", *((uint32_t*)buffer)=regions[i].source_crc); *((uint32_t*)head_buffer+1)=regions[i].source_coordinates.x; *((uint32_t*)head_buffer+2)=regions[i].source_coordinates.y; *((uint32_t*)head_buffer+3)=regions[i].rect.lt_corner.x; *((uint32_t*)head_buffer+4)=regions[i].rect.lt_corner.y; *((uint32_t*)head_buffer+5)=regions[i].rect.size.width; *((uint32_t*)head_buffer+6)=regions[i].rect.size.height; *((uint32_t*)head_buffer+7)=regions[i].size; if(remoteVars.send_frames_over_udp) { //increment offset on region header size head_buffer+=region_header_size; //copy region data to data memcpy(head_buffer,regions[i].compressed_data, regions[i].size); head_buffer+=regions[i].size; } else { sent = 0; // #warning check this ln=remote_write_socket(remoteVars.clientsock_tcp, buffer, 64); while(sentcrc); *((uint32_t*)list+i)=remoteVars.first_deleted_elements->crc; elem=remoteVars.first_deleted_elements; remoteVars.first_deleted_elements=elem->next; free(elem); ++i; } remoteVars.last_deleted_elements=0l; // EPHYR_DBG("SENDING IMG length - %d, number - %d\n",length,framenum_sent++); ln=remote_write_socket(remoteVars.clientsock_tcp,buffer,56); while(sentserialNumber; // EPHYR_DBG("deleting cursor %d",first_deleted_cursor->serialNumber); elem=remoteVars.first_deleted_cursor; remoteVars.first_deleted_cursor=elem->next; free(elem); ++i; } remoteVars.last_deleted_cursor=0l; // EPHYR_DBG("Sending list of %d elements", deletedcursor_list_size); ln=remote_write_socket(remoteVars.clientsock_tcp,buffer,56); while(sentselection, chunk->data, chunk->size, chunk->mimeData, chunk->firstChunk, chunk->lastChunk, chunk->compressed_size, chunk->totalSize); } else { //older client doesn't support only uncompressed datas in single chunk //not sending chunk in other case if(!chunk->compressed_size && chunk->firstChunk && chunk->lastChunk) { return send_selection_chunk(chunk->selection, chunk->data, chunk->size, chunk->mimeData, TRUE, TRUE, FALSE, chunk->size); } EPHYR_DBG("Client doesn't support extended selection, not sending this chunk"); } return 0; } void send_reinit_notification(void) { unsigned char buffer[56] = {0}; _X_UNUSED int l; *((uint32_t*)buffer)=REINIT; EPHYR_DBG("SENDING REINIT NOTIFICATION"); l=remote_write_socket(remoteVars.clientsock_tcp,buffer,56); } int send_selection_chunk(int sel, unsigned char* data, uint32_t length, uint32_t format, BOOL first, BOOL last, uint32_t compressed, uint32_t total_sz) { unsigned char* buffer; unsigned char static_buffer[56]={0}; _X_UNUSED int ln = 0; int l = 0; int sent = 0; uint32_t uncompressed_length=length; //if the data is compressed, send "compressed" amount of bytes // EPHYR_DBG("sending chunk. total %d, chunk %d, compressed %d", total, length, compressed); if(compressed) { length=compressed; } buffer=static_buffer; *((uint32_t*)buffer)=SELECTION; //0 *((uint32_t*)buffer+1)=sel; //4 *((uint32_t*)buffer+2)=format; //8 *((uint32_t*)buffer+3)=uncompressed_length; //16 *((uint32_t*)buffer+4)=first; //20 *((uint32_t*)buffer+5)=last; //24 *((uint32_t*)buffer+6)=compressed; //28 *((uint32_t*)buffer+7)=total_sz; //32 ln=remote_write_socket(remoteVars.clientsock_tcp,buffer,56); while(sentprev; while(current) { unsigned int matchVal=0; if((best_match_frame&& best_match_value<=distance) || distance > MAX_MATCH_VAL) { break; } if(!current->sent || !current->data || !current->size) { current=current->prev; continue; } matchVal+=abs(current->width-frame->width)/10; matchVal+=abs(current->height-frame->height)/10; matchVal+=abs(current->rval-frame->rval); matchVal+=abs(current->gval-frame->gval); matchVal+=abs(current->bval-frame->bval); matchVal+=distance; if(!best_match_frame || (matchValprev; } *match_val=best_match_value; return best_match_frame; } static BOOL checkShiftedRegion( struct cache_elem* src, struct cache_elem* dst, int32_t x, int32_t y, int32_t width, int32_t height, int32_t horiz_shift, int32_t vert_shift) { // EPHYR_DBG("FENTER %d %d %d %d %d",x,y,width,height,shift); int32_t vert_point=20; int32_t hor_point=20; int32_t vert_inc = 0; int32_t hor_inc = 0; uint32_t i=0; if(vert_point>height) { vert_point=height; } if(hor_point>width) { hor_point=width; } vert_inc=height/vert_point; hor_inc=width/hor_point; if(vert_inc<1) { vert_inc=1; } if(hor_inc<1) { hor_inc=1; } for(int32_t ry=y;rywidth+rx)*CACHEBPP; int32_t dst_ind=((ry+vert_shift)*dst->width+rx+horiz_shift)*CACHEBPP; if (src_ind<0 || src_ind +2 > src->size || dst_ind <0 || dst_ind > dst->size ) { EPHYR_DBG("!!!!!WARNING BROKEN BOUNDARIES: sind %d, dind %d, ssize %d, dsize %d", src_ind, dst_ind, src->size, dst->size); } // EPHYR_DBG("Indices %d, %d, %d, %d %d", src_ind, dst_ind, src->size, dst->size, i); if(src->data[src_ind]!=dst->data[dst_ind]) { // EPHYR_DBG("FEXIT"); return FALSE; } if(src->data[src_ind+1]!=dst->data[dst_ind+1]) { // EPHYR_DBG("FEXIT"); return FALSE; } if(src->data[src_ind+2]!=dst->data[dst_ind+2]) { // EPHYR_DBG("FEXIT"); return FALSE; } } } // EPHYR_DBG("FEXIT"); return TRUE; } static int32_t checkScrollUp(struct cache_elem* source, struct cache_elem* dest) { // EPHYR_DBG("checking for up scroll %u, %u, %u, %u", source->width, source->height, dest->width, dest->height); int32_t max_shift=source->height/3; int32_t x=source->width/10; int32_t y=source->height/10; int32_t width = source->width/2-source->width/5; int32_t height=source->height/2-source->height/10; if(x+width >= dest->width) { width=dest->width-x-1; } if(width<2) { // EPHYR_DBG("DST too small (w), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return -1; } if(y+height+max_shift >=dest->height) { height=dest->height-max_shift-y; } if(height<2) { // EPHYR_DBG("DST too small (h), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return -1; } // EPHYR_DBG(" %u %u %u %u %u",x,y,width, height, max_shift); for(int32_t shift=0;shiftwidth, source->height, dest->width, dest->height); int32_t max_shift=source->height/3*-1; int32_t x=source->width/10; int32_t y=source->height/2; int32_t width=source->width/2-source->width/5; int32_t height=source->height/2-source->height/10; // EPHYR_DBG(" %u %u %u %u %u",x,y,width, height, max_shift); if(x+width >= dest->width) { width=dest->width-x-1; } if(width<2) { // EPHYR_DBG("DST too small (w), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return 1; } if(y+height+abs(max_shift) >=dest->height) { height=dest->height-abs(max_shift)-y; } if(height<2) { // EPHYR_DBG("DST too small (h), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return 1; } for(int32_t shift=0;shift>max_shift;--shift) { if(!checkShiftedRegion( source, dest, x, y, width, height, 0,shift)) continue; if(shift) // EPHYR_DBG("Shift %d, cursor matched!\n",shift); return shift; } return 1; } static int32_t checkScrollRight(struct cache_elem* source, struct cache_elem* dest) { // EPHYR_DBG("checking for up scroll %u, %u, %u, %u", source->width, source->height, dest->width, dest->height); int32_t max_shift=source->width/3; int32_t x=source->width/10; int32_t y=source->height/10; int32_t width=source->width/2-source->width/10; int32_t height=source->height/2-source->height/5; if(y+height >= dest->height) { height=dest->height-y-1; } if(height<2) { // EPHYR_DBG("DST too small (d), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return -1; } if(x+width+max_shift >=dest->width) { width=dest->width-abs(max_shift)-x; } if(width<2) { // EPHYR_DBG("DST too small (w), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return -1; } // EPHYR_DBG(" %u %u %u %u %u",x,y,width, height, max_shift); for(int32_t shift=0;shiftwidth, source->height, dest->width, dest->height); int32_t max_shift=source->width/3*-1; int32_t x=source->width/2; int32_t y=source->height/10; int32_t width=source->width/2-source->width/10; int32_t height=source->height/2-source->height/5; if(y+height >= dest->height) { height=dest->height-y-1; } if(height<2) { // EPHYR_DBG("DST too small (d), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return 1; } if(x+width+abs(max_shift) >=dest->width) { width=dest->width-abs(max_shift)-x; } if(width<2) { // EPHYR_DBG("DST too small (w), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return 1; } // EPHYR_DBG(" %d %d %d %d %d",x,y,width, height, max_shift); for(int32_t shift=0;shift>max_shift;--shift) { if(!checkShiftedRegion( source, dest, x, y, width, height, shift, 0 )) continue; if(shift) { // EPHYR_DBG("Shift %d, cursor matched!\n",shift); return shift; } } return 1; } static BOOL checkEquality(struct cache_elem* src, struct cache_elem* dst, int32_t shift_horiz, int32_t shift_vert, rectangle* common_rect) { int32_t center_x=src->width/2; int32_t center_y=src->height/2; int32_t x, y=center_y; int32_t right_x=src->width; int32_t down_y=src->height; int32_t left_x=0; int32_t top_y=0; --right_x; --down_y; if(center_x+shift_horiz >= dst->width || center_y+shift_vert >=dst->height) { /* dst is too small for shift */ return FALSE; } if(left_x+shift_horiz<0) { left_x=0-shift_horiz; } if(top_y+shift_vert<0) { top_y=0-shift_vert; } if( right_x+shift_horiz>=dst->width) { right_x=dst->width-shift_horiz-1; } if(down_y+shift_vert>=dst->height) { down_y=dst->height-shift_vert-1; } // EPHYR_DBG("Center: %dx%d", center_x, center_y); // EPHYR_DBG("initial down_right %dx%d",right_x,down_y); for(y=center_y;y<=down_y;++y) { for(x=center_x; x<=right_x;++x) { int32_t src_ind=(y*src->width+x)*CACHEBPP; int32_t dst_ind=((y+shift_vert)*dst->width+x+shift_horiz)*CACHEBPP; // EPHYR_DBG("%d %d %d %d %d %d", x, y, right_x, down_y, dst->height, shift_vert); if (src_ind<0 || src_ind +2 > src->size || dst_ind <0 || dst_ind > dst->size ) { EPHYR_DBG("!!!!!WARNING BROKEN BOUNDARIES: sind %d, dind %d, ssize %d, dsize %d", src_ind, dst_ind, src->size, dst->size); right_x=x-1; down_y=y-1; goto loop_exit_0; } if((src->data[src_ind]!=dst->data[dst_ind])||(src->data[src_ind+1]!=dst->data[dst_ind+1])|| (src->data[src_ind+2]!=dst->data[dst_ind+2])) { int32_t hor_dist=right_x-x; int32_t vert_dist=down_y-y; if(hor_dist=left_x;--x) { int32_t src_ind=(y*src->width+x)*CACHEBPP; int32_t dst_ind=((y+shift_vert)*dst->width+x+shift_horiz)*CACHEBPP; if (src_ind<0 || src_ind +2 > src->size || dst_ind <0 || dst_ind > dst->size ) { EPHYR_DBG("!!!!!WARNING BROKEN BOUNDARIES: sind %d, dind %d, ssize %d, dsize %d", src_ind, dst_ind, src->size, dst->size); left_x=x+1; down_y=y-1; goto loop_exit_1; } if((src->data[src_ind]!=dst->data[dst_ind])||(src->data[src_ind+1]!=dst->data[dst_ind+1])|| (src->data[src_ind+2]!=dst->data[dst_ind+2])) { uint32_t hor_dist=x-left_x; uint32_t vert_dist=down_y-y; if(hor_dist=top_y;--y) { for(x=center_x; x<=right_x;++x) { int32_t src_ind=(y*src->width+x)*CACHEBPP; int32_t dst_ind=((y+shift_vert)*dst->width+x+shift_horiz)*CACHEBPP; if (src_ind<0 || src_ind +2 > src->size || dst_ind <0 || dst_ind > dst->size ) { EPHYR_DBG("!!!!!WARNING BROKEN BOUNDARIES: sind %d, dind %d, ssize %d, dsize %d", src_ind, dst_ind, src->size, dst->size); right_x=x-1; top_y=y+1; goto loop_exit_2; } if((src->data[src_ind]!=dst->data[dst_ind])||(src->data[src_ind+1]!=dst->data[dst_ind+1])|| (src->data[src_ind+2]!=dst->data[dst_ind+2])) { uint32_t hor_dist=right_x-x; uint32_t vert_dist=y-top_y; if(hor_dist=top_y;--y) { for(x=center_x; x>=left_x;--x) { int32_t src_ind=(y*src->width+x)*CACHEBPP; int32_t dst_ind=((y+shift_vert)*dst->width+x+shift_horiz)*CACHEBPP; if (src_ind<0 || src_ind +2 > src->size || dst_ind <0 || dst_ind > dst->size ) { EPHYR_DBG("!!!!!WARNING BROKEN BOUNDARIES: sind %d, dind %d, ssize %d, dsize %d", src_ind, dst_ind, src->size, dst->size); left_x=x+1; top_y=y+1; goto loop_exit_3; } if((src->data[src_ind]!=dst->data[dst_ind])||(src->data[src_ind+1]!=dst->data[dst_ind+1])|| (src->data[src_ind+2]!=dst->data[dst_ind+2])) { uint32_t hor_dist=x-left_x; uint32_t vert_dist=y-top_y; if(hor_distsize.width=right_x-left_x+1; common_rect->size.height=down_y-top_y+1; if(common_rect->size.width<1 || common_rect->size.height <1) { // EPHYR_DBG("!!!!!!!NEGATIVE OR NULL GEOMETRY!!!!!!!"); return FALSE; } common_rect->lt_corner.x=left_x; common_rect->lt_corner.y=top_y; // EPHYR_DBG("Geometry: %d:%d %dx%d shift - %d %d ", left_x, top_y, common_rect->size.width, // common_rect->size.height, shift_horiz, shift_vert); return TRUE; } static BOOL checkMovedContent(struct cache_elem* source, struct cache_elem* dest, int32_t* horiz_shift, int32_t* vert_shift) { // EPHYR_DBG("checking for moved content %u, %u, %u, %u", source->width, source->height, dest->width, dest->height); int32_t max_shift=source->width/8; int32_t x=source->width/2; int32_t y=source->height/2; int32_t width=source->width/4; int32_t height=source->height/4; if(max_shift>source->height/8) max_shift=source->height/8; if(max_shift>20) max_shift=20; if(y+height+max_shift >= dest->height) { height=dest->height-max_shift-y-1; } if(height<2) { // EPHYR_DBG("DST too small (d), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return FALSE; } if(x+width+max_shift >=dest->width) { width=dest->width-max_shift-x; } if(width<2) { // EPHYR_DBG("DST too small (w), keep checking %d %d %d %d", source->width, source->height, dest->width, dest->height); return FALSE; } // EPHYR_DBG(" %d %d %d %d %d",x,y,width, height, max_shift); for(int32_t hshift=0;hshiftwidth-1, top_y=source->height-1, right_x=0, bot_y=0; float eff = 0; for(int32_t y=0;yheight;++y) { for(int32_t x=0;xwidth;++x) { int32_t ind=(y*source->width+x)*CACHEBPP; if((source->data[ind] != dest->data[ind]) || (source->data[ind+1] != dest->data[ind+1])|| (source->data[ind+2] != dest->data[ind+2])) { if(xright_x) right_x=x; if(ybot_y) bot_y=y; } } } diff_rect->size.width=right_x-left_x+1; diff_rect->size.height=bot_y-top_y+1; diff_rect->lt_corner.x=left_x; diff_rect->lt_corner.y=top_y; eff= (float)(diff_rect->size.width*diff_rect->size.height)/ (float)(source->width*source->height); if(eff>0.8) return FALSE; // EPHYR_DBG("REG_GEOM: %dx%d. DIF_GEOM %d,%d - %dx%d EFF=%f", source->width, source->height, left_x,top_y, // diff_rect->size.width, diff_rect->size.height,eff); return TRUE; } static BOOL find_common_regions(struct cache_elem* source, struct cache_elem* dest, BOOL* diff, rectangle* common_rect, int32_t* hshift, int32_t* vshift) { // EPHYR_DBG("checking for common regions"); *diff=FALSE; *hshift=0; *vshift=checkScrollDown(source,dest); if(*vshift<0) { // EPHYR_DBG("Found scroll down, vert shift %d %u %u %u %u" , *vshift, dest->width, dest->height, dest->crc, source->crc); return checkEquality(source, dest, 0, *vshift, common_rect); } *hshift=0; *vshift=checkScrollUp(source, dest); if(*vshift>0) { // EPHYR_DBG("Found scroll up, vert shift %d %u %u %u %u" , *vshift, dest->width, dest->height, dest->crc, source->crc); return checkEquality(source, dest, 0, *vshift, common_rect); } // #warning stop here for the moment, let's see later if we'll use it return FALSE; *vshift=0; *hshift=checkScrollRight(source, dest); if(*hshift>0) { return checkEquality(source, dest, *hshift, 0, common_rect); } *vshift=0; *hshift=checkScrollLeft(source, dest); if(*hshift<0) { // EPHYR_DBG("SCROLL LEFT %d", *hshift); return checkEquality(source, dest, *hshift, 0, common_rect); } if((source->width != dest->width) && (source->height!=dest->height)) { int32_t h_shift, v_shift; *vshift=0; *hshift=0; if(checkMovedContent(source, dest, &h_shift, &v_shift)) { *hshift=h_shift; *vshift=v_shift; // EPHYR_DBG("found moved content %d, %d", *hshift, *vshift); return checkEquality(source, dest, *hshift, *vshift, common_rect); } } if((source->width == dest->width) && (source->height==dest->height)) { *diff=TRUE; // EPHYR_DBG("LOOK FOR IMAGE DIFFERENCE"); return findDiff(source, dest, common_rect); } // EPHYR_DBG("Scroll not found %d",dest->crc); return FALSE; } /* use only from send thread */ static void sendMainImageFromSendThread(uint32_t width, uint32_t height, int32_t dx ,int32_t dy, uint32_t winId) { _X_UNUSED uint32_t length = 0; struct frame_region regions[9] = {{0}}; uint32_t isize = 0; unsigned char* data = NULL; uint32_t i = 0; uint32_t ind = 0; BOOL mainImage=FALSE; /* if(width!=0) { EPHYR_DBG("sending UPDATE- %dx%d, %d,%d",width, height,dx,dy); } else { EPHYR_DBG("sending mainImage"); }*/ pthread_mutex_lock(&remoteVars.mainimg_mutex); for(int j=0;j<9;++j) { regions[j].rect.size.width=0; regions[j].source_crc=0; regions[j].compressed_data=0; regions[j].size=0; } if(!width || (dx==0 && dy==0 && width==remoteVars.main_img_width && height==remoteVars.main_img_height)) { mainImage=TRUE; dx=dy=0; width=remoteVars.main_img_width; height=remoteVars.main_img_height; } isize=width*height*CACHEBPP; data=malloc(isize); for(int32_t y=0;ystate == CHANGED)||(rwin->state == NEW)) { bufSize+=WINUPDSIZE; if(rwin->name) { bufSize+=strlen(rwin->name); } bufSize+=rwin->icon_size; } if(rwin->state==WDEL) { bufSize+=WINUPDDELSIZE; } rwin=rwin->next; } //copy update data to buffer updateBuf=malloc(bufSize); rwin=remoteVars.windowList; while(rwin) { if(rwin->state != UNCHANGED) { memcpy(updateBuf+bufHead, &(rwin->id), sizeof(uint32_t)); bufHead+=sizeof(uint32_t); state=rwin->state; memcpy(updateBuf+bufHead, &state, sizeof(state)); bufHead+=sizeof(state); } if((rwin->state == CHANGED)||(rwin->state==NEW)) { memcpy(updateBuf+bufHead, &(rwin->parentId), sizeof(uint32_t)); bufHead+=sizeof(uint32_t); memcpy(updateBuf+bufHead, &(rwin->nextSibId), sizeof(uint32_t)); bufHead+=sizeof(uint32_t); memcpy(updateBuf+bufHead, &(rwin->transWinId), sizeof(uint32_t)); bufHead+=sizeof(uint32_t); memcpy(updateBuf+bufHead, &(rwin->x), sizeof(int16_t)); bufHead+=sizeof(int16_t); memcpy(updateBuf+bufHead, &(rwin->y), sizeof(int16_t)); bufHead+=sizeof(int16_t); memcpy(updateBuf+bufHead, &(rwin->w), sizeof(uint16_t)); bufHead+=sizeof(uint16_t); memcpy(updateBuf+bufHead, &(rwin->h), sizeof(uint16_t)); bufHead+=sizeof(uint16_t); memcpy(updateBuf+bufHead, &(rwin->minw), sizeof(uint16_t)); bufHead+=sizeof(uint16_t); memcpy(updateBuf+bufHead, &(rwin->minh), sizeof(uint16_t)); bufHead+=sizeof(uint16_t); memcpy(updateBuf+bufHead, &(rwin->bw), sizeof(uint16_t)); bufHead+=sizeof(uint16_t); memcpy(updateBuf+bufHead, &(rwin->visibility), sizeof(int8_t)); bufHead+=sizeof(int8_t); memcpy(updateBuf+bufHead, &(rwin->winType), sizeof(int8_t)); bufHead+=sizeof(int8_t); nameSize=0; if(rwin->name) { nameSize=strlen(rwin->name); } memcpy(updateBuf+bufHead, &nameSize, sizeof(nameSize)); bufHead+=sizeof(nameSize); if(nameSize) { memcpy(updateBuf+bufHead, rwin->name, nameSize); bufHead+=nameSize; } memcpy(updateBuf+bufHead, &(rwin->icon_size), sizeof(uint32_t)); bufHead+=sizeof(uint32_t); if(rwin->icon_size) { memcpy(updateBuf+bufHead, rwin->icon_png, rwin->icon_size); bufHead+=rwin->icon_size; //send icon data only once free(rwin->icon_png); rwin->icon_png=0; rwin->icon_size=0; } rwin->state=UNCHANGED; } if(rwin->state==WDEL) { //remove window from list and free resources // EPHYR_DBG("release window %p, %s",rwin->ptr, rwin->name); if(rwin==remoteVars.windowList) { remoteVars.windowList=rwin->next; } if(prev) { prev->next=rwin->next; } tmp=rwin; rwin=rwin->next; if(tmp->name) { free(tmp->name); } if(tmp->icon_png) { free(tmp->icon_png); } free(tmp); } else { prev=rwin; rwin=rwin->next; } } /* EPHYR_DBG("NEW LIST:"); rwin=remoteVars.windowList; while(rwin) { EPHYR_DBG("=====%p",rwin->ptr); rwin=rwin->next; }*/ //send win updates remoteVars.windowsUpdated=FALSE; pthread_mutex_unlock(&remoteVars.sendqueue_mutex); //send_updates remote_send_win_updates(updateBuf, bufSize); pthread_mutex_lock(&remoteVars.sendqueue_mutex); } static void *send_frame_thread (void *threadid) { enum SelectionType r; int dirty_region; //wait 100*1000 microseconds unsigned int ms_to_wait=100*1000; struct timespec ts; struct timeval tp; #ifdef EPHYR_WANT_DEBUG debug_sendThreadId=pthread_self(); #endif /* EPHYR_WANT_DEBUG */ while(1) { pthread_mutex_lock(&remoteVars.sendqueue_mutex); if(!remoteVars.client_connected) { EPHYR_DBG ("TCP connection closed\n"); close_client_sockets(); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); break; } remoteVars.client_connected=TRUE; //check if we should send the server version to client if(remoteVars.client_version && ! remoteVars.server_version_sent) { //the client supports versions and we didn't send our version yet remote_sendVersion(); } if(!remoteVars.first_sendqueue_element && !remoteVars.firstCursor && !remoteVars.selstruct.firstOutputChunk && !remoteVars.cache_rebuilt && !remoteVars.windowsUpdated) { gettimeofday(&tp, NULL); /* Convert from timeval to timespec */ ts.tv_sec = tp.tv_sec; ts.tv_nsec = tp.tv_usec * 1000+ms_to_wait*1000UL;//wait ms_to_wait microseconds if(ts.tv_nsec>=1000000000UL) { ts.tv_nsec-=1000000000UL; ++ts.tv_sec; } /*sleep with timeout till signal from other thread is sent*/ switch(pthread_cond_timedwait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex, &ts)) { case 0: //have a signal from other thread, continue execution ms_to_wait=100*1000; //reset timer break; case ETIMEDOUT: //timeout is ocured, we have nothing else to do, let's see if we need to update some screen regions dirty_region=getDirtyScreenRegion(); if(dirty_region!=-1) { send_dirty_region(dirty_region); ms_to_wait=200; //we can start to repaint faster till we don't have any new data incoming } else { /*send server alive event if needed*/ ms_to_wait=100*1000; //reset timer sendServerAlive(); } break; default: EPHYR_DBG("Error has occurred in pthread_cond_timedwait"); ms_to_wait=100*1000; //reset timer break; } } /* mutex is locked on this point */ //if windows list is updated send changes to client if(remoteVars.windowsUpdated) { remote_process_window_updates(); } /*mutex still locked*/ //send notification to client that cache is rebuilt if(remoteVars.cache_rebuilt) { remoteVars.cache_rebuilt=FALSE; pthread_mutex_unlock(&remoteVars.sendqueue_mutex); send_reinit_notification(); clean_everything(); pthread_mutex_lock(&remoteVars.sendqueue_mutex); } //only send output selection chunks if there are no frames and cursors in the queue //selections can take a lot of bandwidth and have less priority if(remoteVars.selstruct.firstOutputChunk && !remoteVars.first_sendqueue_element && !remoteVars.firstCursor) { //get chunk from queue struct OutputChunk* chunk=remoteVars.selstruct.firstOutputChunk; remoteVars.selstruct.firstOutputChunk=chunk->next; if(!remoteVars.selstruct.firstOutputChunk) { remoteVars.selstruct.lastOutputChunk=NULL; } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); //send chunk send_output_selection(chunk); //free chunk and it's data if(chunk->data) { free(chunk->data); } // EPHYR_DBG(" REMOVE CHUNK %p %p %p", remoteVars.selstruct.firstOutputChunk, remoteVars.selstruct.lastOutputChunk, chunk); free(chunk); pthread_mutex_lock(&remoteVars.sendqueue_mutex); } //check if we need to request the selection from client if(remoteVars.selstruct.requestSelection[PRIMARY] || remoteVars.selstruct.requestSelection[CLIPBOARD]) { for(r=PRIMARY; r<=CLIPBOARD; ++r) { if(remoteVars.selstruct.requestSelection[r]) { remoteVars.selstruct.requestSelection[r]=FALSE; pthread_mutex_unlock(&remoteVars.sendqueue_mutex); //send request for selection request_selection_from_client(r); pthread_mutex_lock(&remoteVars.sendqueue_mutex); } } } if(remoteVars.firstCursor) { /* get cursor from queue, delete it from queue, unlock mutex and send cursor. After sending free cursor */ struct cursorFrame* cframe=remoteVars.firstCursor; if(remoteVars.firstCursor->next) remoteVars.firstCursor=remoteVars.firstCursor->next; else remoteVars.firstCursor=remoteVars.lastCursor=0; pthread_mutex_unlock(&remoteVars.sendqueue_mutex); send_cursor(cframe); if(cframe->data) free(cframe->data); free(cframe); } else { pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } pthread_mutex_lock(&remoteVars.sendqueue_mutex); if(remoteVars.first_sendqueue_element) { int elems=queue_elements(); struct cache_elem* frame = NULL; struct sendqueue_element* current = NULL; uint32_t x=0, y = 0, winId=0; int32_t width, height = 0; if(remoteVars.maxfr 3) { if(remoteVars.jpegQuality >10) remoteVars.jpegQuality-=10; } if(elems <3) { if(remoteVars.jpegQuality frame; /* delete first element from frame queue */ current=remoteVars.first_sendqueue_element; if(remoteVars.first_sendqueue_element->next) { remoteVars.first_sendqueue_element=remoteVars.first_sendqueue_element->next; } else { remoteVars.first_sendqueue_element=remoteVars.last_sendqueue_element=NULL; } x=current->x; y=current->y; width=current->width; height=current->height; winId=current->winId; free(current); if(frame) { uint32_t crc = frame->crc; uint32_t frame_width=frame->width; uint32_t frame_height=frame->height; /* unlock sendqueue for main thread */ markDirtyRegions(x, y, frame_width, frame_height, remoteVars.jpegQuality, winId); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); send_frame(frame_width, frame_height, x, y, crc, frame->regions, winId); } else { // EPHYR_DBG("Sending main image or screen update"); markDirtyRegions(x, y, width, height, remoteVars.jpegQuality, winId); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); sendMainImageFromSendThread(width, height, x, y, winId); } pthread_mutex_lock(&remoteVars.sendqueue_mutex); if(frame) { frame->sent=TRUE; frame->busy--; if(frame->source) frame->source->busy--; frame->source=0; for(int i=0;i<9;++i) { if(frame->regions[i].size) { free(frame->regions[i].compressed_data); frame->regions[i].size=0; } frame->regions[i].source_crc=0; frame->regions[i].rect.size.width=0; } } if(remoteVars.cache_size>CACHEMAXELEMENTS) { clear_frame_cache(CACHEMAXELEMENTS); } if(remoteVars.first_deleted_elements) { send_deleted_elements(); } if(remoteVars.first_deleted_cursor) { send_deleted_cursors(); } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); remoteVars.framenum++; } else { pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } } EPHYR_DBG("exit sending thread"); remoteVars.send_thread_id=0; pthread_exit(0); } /* warning! sendqueue_mutex should be locked by thread calling this function! */ void clear_output_selection(void) { struct OutputChunk* chunk=remoteVars.selstruct.firstOutputChunk; struct OutputChunk* prev_chunk; while(chunk) { prev_chunk=chunk; chunk=chunk->next; if(prev_chunk->data) { free(prev_chunk->data); } free(prev_chunk); } remoteVars.selstruct.firstOutputChunk=remoteVars.selstruct.lastOutputChunk=NULL; } /* warning! sendqueue_mutex should be locked by thread calling this function! */ static void clear_send_queue(void) { struct sendqueue_element* current = NULL; struct sendqueue_element* next = NULL; current=remoteVars.first_sendqueue_element; while(current) { if(current->frame) { current->frame->busy=0; if(current->frame->source) current->frame->source->busy--; current->frame->source=0; } next=current->next; free(current); current=next; } remoteVars.first_sendqueue_element=remoteVars.last_sendqueue_element=NULL; } /* * remove elements from cache and release all images if existing. * warning! sendqueue_mutex should be locked by thread calling this function! */ void clear_frame_cache(uint32_t max_elements) { // EPHYR_DBG("cache elements %d, cache size %lu, reducing to size: %d\n", remoteVars.cache_elements, remoteVars.cache_size, max_elements); while(remoteVars.first_cache_element && (remoteVars.cache_elements > max_elements)) { struct cache_elem* next = NULL; /* don't delete it now, return to it later * but if max_elements is 0 we are clearing all elements */ if(remoteVars.first_cache_element->busy && max_elements) { EPHYR_DBG("%x - is busy (%d), not deleting", remoteVars.first_cache_element->crc, remoteVars.first_cache_element->busy); return; } next = remoteVars.first_cache_element->next; if(remoteVars.first_cache_element->size) { free(remoteVars.first_cache_element->data); remoteVars.cache_size-=remoteVars.first_cache_element->size; } //add element to deleted list if client is connected and we are not deleting all frame list if(remoteVars.client_connected && max_elements) { /* add deleted element to the list for sending */ struct deleted_elem* delem=malloc(sizeof(struct deleted_elem)); ++remoteVars.deleted_list_size; delem->next=0l; delem->crc=remoteVars.first_cache_element->crc; // EPHYR_DBG("delete %x",delem->crc); if(remoteVars.last_deleted_elements) { remoteVars.last_deleted_elements->next=delem; } else { remoteVars.first_deleted_elements=delem; } remoteVars.last_deleted_elements=delem; } if(remoteVars.first_cache_element->source) remoteVars.first_cache_element->source->busy--; free(remoteVars.first_cache_element); remoteVars.cache_elements--; remoteVars.first_cache_element=next; if(next) next->prev=NULL; } if(!remoteVars.first_cache_element) { remoteVars.last_cache_element=NULL; } // EPHYR_DBG("cache elements %d, cache size %d\n", cache_elements, cache_size); } static const char* getAgentStateAsString(int state) { switch(state) { case STARTING: return "STARTING"; case RUNNING: return "RUNNING"; case RESUMING: return "RESUMING"; case SUSPENDING: return "SUSPENDING"; case SUSPENDED: return "SUSPENDED"; case TERMINATING: return "TERMINATING"; case TERMINATED: return "TERMINATED"; } return 0; } void setAgentState(int state) { if(remoteVars.agentState == TERMINATED) return; if(remoteVars.agentState == TERMINATING && state != TERMINATED) return; EPHYR_DBG("Agent state %s",getAgentStateAsString(state)); if(strlen(remoteVars.stateFile)) { FILE* ptr=fopen(remoteVars.stateFile,"wt"); if(ptr) { fprintf(ptr,"%s",getAgentStateAsString(state)); fclose(ptr); } else { EPHYR_DBG("CAN'T WRITE STATE TO %s",remoteVars.stateFile); } } remoteVars.agentState=state; } void delete_all_windows(void) { //sendqueue_mutex should be locked here struct remoteWindow* rwin=remoteVars.windowList; struct remoteWindow* tmp; while(rwin) { //remove window from list and free resources //EPHYR_DBG("release window %p, %s",rwin->ptr, rwin->name); tmp=rwin; rwin=rwin->next; if(tmp->name) { free(tmp->name); } if(tmp->icon_png) { free(tmp->icon_png); } free(tmp); } remoteVars.windowList=NULL; } void disconnect_client(void) { EPHYR_DBG("DISCONNECTING CLIENT, DOING SOME CLEAN UP"); pthread_mutex_lock(&remoteVars.sendqueue_mutex); if(remoteVars.checkKeepAliveTimer) { TimerFree(remoteVars.checkKeepAliveTimer); remoteVars.checkKeepAliveTimer=0; } remoteVars.client_connected=FALSE; setAgentState(SUSPENDED); clean_everything(); #if XORG_VERSION_CURRENT >= 11900000 EPHYR_DBG("Remove notify FD for client sock %d",remoteVars.clientsock_tcp); RemoveNotifyFd(remoteVars.clientsock_tcp); #endif /* XORG_VERSION_CURRENT */ pthread_cond_signal(&remoteVars.have_sendqueue_cond); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } void unpack_current_chunk_to_buffer(struct InputBuffer* selbuff) { //unpacking the data from current chunk to selbuff z_stream stream; stream.zalloc = Z_NULL; stream.zfree = Z_NULL; stream.opaque = Z_NULL; // EPHYR_DBG("inflate %d bytes to %d", selbuff->currentChunkCompressedSize, selbuff->currentChunkSize); stream.avail_in = selbuff->currentChunkCompressedSize; stream.next_in = selbuff->currentChunkCompressedData; stream.avail_out = selbuff->currentChunkSize; stream.next_out = selbuff->data + selbuff->bytesReady; inflateInit(&stream); inflate(&stream, Z_NO_FLUSH); inflateEnd(&stream); if(stream.total_out != selbuff->currentChunkSize) { //something is wrong with extracting the data EPHYR_DBG("WARNING!!!! extracting the data failed output has %d bytes instead of %d", (uint32_t)stream.total_out, selbuff->currentChunkSize); } // EPHYR_DBG("%s", selbuff->data + selbuff->bytesReady); ///freeing compressed data free(selbuff->currentChunkCompressedData); selbuff->currentChunkCompressedData=NULL; selbuff->bytesReady+=selbuff->currentChunkSize; selbuff->currentChunkCompressedSize=0; } void readInputSelectionBuffer(char* buff) { //read th rest of the chunk data struct InputBuffer* selbuff; int leftToRead, l; //lock input selection pthread_mutex_lock(&remoteVars.selstruct.inMutex); selbuff = &remoteVars.selstruct.inSelection[remoteVars.selstruct.currentInputBuffer]; //if the data is not compressed read it directly to the buffer if(!selbuff->currentChunkCompressedSize) { leftToRead=selbuff->currentChunkSize - selbuff->currentChunkBytesReady; l=(leftToRead < EVLENGTH)?leftToRead:EVLENGTH; //copy data to selection memcpy(selbuff->data+selbuff->bytesReady, buff, l); selbuff->bytesReady+=l; selbuff->currentChunkBytesReady+=l; if(selbuff->currentChunkBytesReady==selbuff->currentChunkSize) { //selection chunk received completely, next event will start with event header // EPHYR_DBG("READY Selection Chunk, read %d",selbuff->currentChunkSize); remoteVars.selstruct.readingInputBuffer=-1; } } else { //copy to the buffer for compressed data leftToRead=selbuff->currentChunkCompressedSize - selbuff->currentChunkBytesReady; l=(leftToRead < EVLENGTH)?leftToRead:EVLENGTH; //copy data to selection memcpy(selbuff->currentChunkCompressedData+selbuff->currentChunkBytesReady, buff, l); selbuff->currentChunkBytesReady+=l; if(selbuff->currentChunkBytesReady==selbuff->currentChunkCompressedSize) { //selection chunk received completely, next event will start with event header EPHYR_DBG("READY Selection Chunk, read %d",selbuff->currentChunkSize); remoteVars.selstruct.readingInputBuffer=-1; //unpack data to selection buffer unpack_current_chunk_to_buffer(selbuff); } } if(selbuff->bytesReady==selbuff->size) { //selection buffer received completely // EPHYR_DBG("READY Selection %d, MIME %d, Read %d from %d", remoteVars.selstruct.currentInputBuffer, selbuff->mimeData, selbuff->bytesReady, selbuff->size); //send notify to system that we are using selection //if state is requested we already own this selection after notify if(selbuff->state != REQUESTED) own_selection(remoteVars.selstruct.currentInputBuffer); selbuff->state=COMPLETED; //send notification event to interrupt sleeping selection thread client_sel_data_notify(remoteVars.selstruct.currentInputBuffer); } //unlock selection pthread_mutex_unlock(&remoteVars.selstruct.inMutex); } void readInputSelectionHeader(char* buff) { //read the input selection event. //The event represents one chunk of imput selection //it has a header and some data of the chunk uint32_t size, totalSize; uint8_t destination, mime; struct InputBuffer* selbuff = NULL; BOOL firstChunk=FALSE, lastChunk=FALSE; uint32_t compressedSize=0; uint32_t headerSize=10; uint32_t l; size=*((uint32_t*)buff+1); destination=*((uint8_t*)buff+8); mime=*((uint8_t*)buff+9); //if client supports ext selection, read extended header if(remoteVars.selstruct.clientSupportsExetndedSelection) { headerSize=20; firstChunk=*((uint8_t*)buff + 10); lastChunk=*((uint8_t*)buff + 11); compressedSize=*((uint32_t*) (buff + 12)); totalSize=*( (uint32_t*) (buff+16)); } else { compressedSize=0; lastChunk=firstChunk=TRUE; totalSize=size; } //sanity check if((destination != PRIMARY)&& (destination!= CLIPBOARD)) { EPHYR_DBG("WARNING: unsupported destination %d, setting to CLIPBOARD",destination); destination=CLIPBOARD; } EPHYR_DBG("HAVE NEW INCOMING SELECTION Chunk: sel %d size %d mime %d compressed size %d, total %d",destination, size, mime, compressedSize, totalSize); //lock selection pthread_mutex_lock(&remoteVars.selstruct.inMutex); remoteVars.selstruct.readingInputBuffer=-1; selbuff = &remoteVars.selstruct.inSelection[destination]; //we recieved selection notify from client if(firstChunk && lastChunk && remoteVars.selstruct.clientSupportsExetndedSelection && (totalSize == 0) &&(size == 0)) { EPHYR_DBG("Selection notify from client for %d", destination); if(selbuff->size && selbuff->data) { free(selbuff->data); } selbuff->size=0; selbuff->mimeData=mime; selbuff->data=0; selbuff->bytesReady=0; selbuff->state=NOTIFIED; // own selection own_selection(destination); //unlock mutex pthread_mutex_unlock(&remoteVars.selstruct.inMutex); return; } if(firstChunk) { //if it's first chunk, initialize our selection buffer if(selbuff->size && selbuff->data) { free(selbuff->data); } selbuff->size=totalSize; selbuff->mimeData=mime; selbuff->data=malloc(totalSize); selbuff->bytesReady=0; } if(selbuff->currentChunkCompressedSize && selbuff->currentChunkCompressedData) { free(selbuff->currentChunkCompressedData); } selbuff->currentChunkCompressedData=NULL; selbuff->currentChunkCompressedSize=0; //if compressed data will be read in buffer for compressed data if(compressedSize) { selbuff->currentChunkCompressedData=malloc(compressedSize); selbuff->currentChunkCompressedSize=compressedSize; l=(compressedSize < EVLENGTH-headerSize)?compressedSize:(EVLENGTH-headerSize); memcpy(selbuff->currentChunkCompressedData, buff+headerSize, l); } else { //read the selection data from header l=(size < EVLENGTH-headerSize)?size:(EVLENGTH-headerSize); memcpy(selbuff->data+selbuff->bytesReady, buff+headerSize, l); selbuff->bytesReady+=l; } selbuff->currentChunkBytesReady=l; selbuff->currentChunkSize=size; if(!compressedSize) { if(selbuff->currentChunkBytesReady != selbuff->currentChunkSize) { // we didn't recieve complete chunk yet, next event will have data remoteVars.selstruct.currentInputBuffer=remoteVars.selstruct.readingInputBuffer=destination; } } else { if(selbuff->currentChunkBytesReady != selbuff->currentChunkCompressedSize) { // we didn't recieve complete chunk yet, next event will have data remoteVars.selstruct.currentInputBuffer=remoteVars.selstruct.readingInputBuffer=destination; } else { //we read all compressed chunk data, unpack it to sel buff unpack_current_chunk_to_buffer(selbuff); } } if(selbuff->size == selbuff->bytesReady) { //Selection is completed // EPHYR_DBG("READY INCOMING SELECTION for %d",destination); //own the selection //if state is requested we already own this selection after notify if(selbuff->state != REQUESTED) own_selection(destination); selbuff->state=COMPLETED; //send notification event to interrupt sleeping selection thread client_sel_data_notify(destination); } //unlock selection pthread_mutex_unlock(&remoteVars.selstruct.inMutex); } //length is only important for UDP connections. In case of TCP it'll be always EVLENGTH BOOL remote_process_client_event ( char* buff , int length) { uint32_t event_type=*((uint32_t*)buff); //updating keep alive time pthread_mutex_lock(&remoteVars.sendqueue_mutex); remoteVars.last_client_keepalive_time=time(NULL); if(remoteVars.client_version>=3 && remoteVars.checkKeepAliveTimer) { remoteVars.checkKeepAliveTimer=TimerSet(remoteVars.checkKeepAliveTimer,0,CLIENTALIVE_TIMEOUT, checkClientAlive, NULL); } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); switch(event_type) { case MotionNotify: { uint32_t x=*((uint32_t*)buff+1); uint32_t y=*((uint32_t*)buff+2); // EPHYR_DBG("HAVE MOTION EVENT %d, %d from client\n",x,y); ephyrClientMouseMotion(x,y); break; } case ButtonPress: case ButtonRelease: { uint32_t state=*((uint32_t*)buff+1); uint32_t button=*((uint32_t*)buff+2); // EPHYR_DBG("HAVE BUTTON PRESS/RELEASE EVENT %d, %d from client\n",state,button); ephyrClientButton(event_type,state, button); break; } case KeyPress: { uint32_t state=*((uint32_t*)buff+1); uint32_t key=*((uint32_t*)buff+2); // EPHYR_DBG("HAVE KEY PRESS EVENT state: %d(%x), key: %d(%x) from client\n",state,state, key, key); ephyrClientKey(event_type,state, key); //send key release immeidately after key press to avoid "key sticking" ephyrClientKey(KeyRelease,state, key); break; } case KeyRelease: { uint32_t state=*((uint32_t*)buff+1); uint32_t key=*((uint32_t*)buff+2); // EPHYR_DBG("HAVE KEY RELEASE EVENT state: %d(%x), key: %d(%x) from client\n",state,state, key, key); ephyrClientKey(event_type,state, key); break; } case GEOMETRY: { uint16_t width=*((uint16_t*)buff+2); uint16_t height=*((uint16_t*)buff+3); struct VirtScreen screens[4] = {{0}}; remoteVars.client_initialized=TRUE; EPHYR_DBG("Client want resize to %dx%d",width,height); memset(screens,0, sizeof(struct VirtScreen)*4); for(int j=0;j<4;++j) { char* record=buff+9+j*8; screens[j].width=*((uint16_t*)record); screens[j].height=*((uint16_t*)record+1); screens[j].x=*((int16_t*)record+2); screens[j].y=*((int16_t*)record+3); if(!screens[j].width || !screens[j].height) { break; } EPHYR_DBG("SCREEN %d - (%dx%d) - %d,%d", j, screens[j].width, screens[j].height, screens[j].x, screens[j].y); } ephyrResizeScreen (remoteVars.ephyrScreen->pScreen,width,height, screens); break; } case UPDATE: { int32_t width=*((uint32_t*)buff+1); int32_t height=*((uint32_t*)buff+2); int32_t x=*((uint32_t*)buff+3); int32_t y=*((uint32_t*)buff+4); uint32_t winid=0; if(remoteVars.rootless) { winid=*((uint32_t*)buff+5); } // EPHYR_DBG("HAVE UPDATE request from client, window 0x%X %dx%d %d,%d\n",winid, width, height, x,y ); pthread_mutex_lock(&remoteVars.mainimg_mutex); // EPHYR_DBG("DBF: %p, %d, %d",remoteVars.main_img, remoteVars.main_img_width, remoteVars.main_img_height); if(remoteVars.main_img && x+width <= remoteVars.main_img_width && y+height <= remoteVars.main_img_height ) { pthread_mutex_unlock(&remoteVars.mainimg_mutex); add_frame(width, height, x, y, 0, 0, winid); } else { EPHYR_DBG("UPDATE: skip request"); pthread_mutex_unlock(&remoteVars.mainimg_mutex); } break; } case SELECTIONEVENT: { readInputSelectionHeader(buff); break; } case CLIENTVERSION: { int16_t ver=*((uint16_t*)buff+2); int16_t os=*((uint16_t*)buff+3); set_client_version(ver, os); EPHYR_DBG("Client information: vesrion %d, os %d", ver, os); pthread_cond_signal(&remoteVars.have_sendqueue_cond); break; } case DEMANDSELECTION: { int16_t sel=*((uint16_t*)buff+2); // EPHYR_DBG("Client requesting selection %d", sel); client_sel_request_notify(sel); break; } case KEEPALIVE: { //receive keepalive event. break; } case RESENDFRAME: { resend_frame( *((uint32_t*)buff+1) ); break; } case CACHEREBUILD: { //rebuild all frame and cursors caches rebuild_caches(); break; } case WINCHANGE: { client_win_change(buff); break; } case DISCONNECTCLIENT: { EPHYR_DBG("Client sent disconnect event"); disconnect_client(); break; } case OPENUDP: { open_udp_socket(); break; } default: { EPHYR_DBG("UNSUPPORTED EVENT: %d",event_type); return FALSE; } } return TRUE; } void clientReadNotify(int fd, int ready, void *data) { BOOL con; int length = 0; int iterations = 0; int restDataLength, restDataPos = 0; pthread_mutex_lock(&remoteVars.sendqueue_mutex); con=remoteVars.client_connected; pthread_mutex_unlock(&remoteVars.sendqueue_mutex); if(!con) return; /* read max 99 events */ length=read(remoteVars.clientsock_tcp,remoteVars.eventBuffer + remoteVars.evBufferOffset, EVLENGTH*99); if(length<0) { EPHYR_DBG("WRONG data - %d\n",length); // disconnect_client(); return; } if(!length) { EPHYR_DBG("NO DATA, client disconnected\n"); disconnect_client(); return; } // EPHYR_DBG("Got ev bytes - %d\n",eventnum++); length+=remoteVars.evBufferOffset; iterations=length/EVLENGTH; for(int i=0;ieventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask) #define StrSend(pWin) \ ((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask) #define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) //this function is from dix/window.c static void ReflectStackChange(WindowPtr pWin, WindowPtr pSib, VTKind kind) { /* Note that pSib might be NULL */ Bool WasViewable = (Bool) pWin->viewable; Bool anyMarked; WindowPtr pFirstChange; WindowPtr pLayerWin; ScreenPtr pScreen = pWin->drawable.pScreen; /* if this is a root window, can't be restacked */ if (!pWin->parent) return; pFirstChange = MoveWindowInStack(pWin, pSib); if (WasViewable) { anyMarked = (*pScreen->MarkOverlappedWindows) (pWin, pFirstChange, &pLayerWin); if (pLayerWin != pWin) pFirstChange = pLayerWin; if (anyMarked) { (*pScreen->ValidateTree) (pLayerWin->parent, pFirstChange, kind); (*pScreen->HandleExposures) (pLayerWin->parent); if (pWin->drawable.pScreen->PostValidateTree) (*pScreen->PostValidateTree) (pLayerWin->parent, pFirstChange, kind); } } if (pWin->realized) WindowsRestructured(); } void client_win_close(uint32_t winId) { WindowPtr pWin; xEvent e; // EPHYR_DBG("Client request win close: 0x%x",winId); pWin=remote_find_window_on_screen_by_id(winId, remoteVars.ephyrScreen->pScreen->root); if(!pWin) { EPHYR_DBG("Window with ID 0x%X not found on current screen",winId); return; } e.u.u.type = ClientMessage; e.u.u.detail = 32; e.u.clientMessage.window = winId; e.u.clientMessage.u.l.type = MakeAtom("WM_PROTOCOLS",strlen("WM_PROTOCOLS"),FALSE); e.u.clientMessage.u.l.longs0 = MakeAtom("WM_DELETE_WINDOW",strlen("WM_DELETE_WINDOW"),FALSE); e.u.clientMessage.u.l.longs1 = 0; e.u.clientMessage.u.l.longs2 = 0; e.u.clientMessage.u.l.longs3 = 0; e.u.clientMessage.u.l.longs4 = 0; DeliverEvents(pWin, &e, 1, NullWindow); } void client_win_iconify(uint32_t winId) { WindowPtr pWin; xEvent e; EPHYR_DBG("Client request win iconify: 0x%x",winId); pWin=remote_find_window_on_screen_by_id(winId, remoteVars.ephyrScreen->pScreen->root); if(!pWin) { EPHYR_DBG("Window with ID 0x%X not found on current screen",winId); return; } e.u.u.type = ClientMessage; e.u.u.detail = 32; e.u.clientMessage.window = winId; e.u.clientMessage.u.l.type = MakeAtom("WM_CHANGE_STATE",strlen("WM_CHANGE_STATE"),FALSE); e.u.clientMessage.u.l.longs0 = 3;//iconicState e.u.clientMessage.u.l.longs1 = 0; e.u.clientMessage.u.l.longs2 = 0; e.u.clientMessage.u.l.longs3 = 0; e.u.clientMessage.u.l.longs4 = 0; DeliverEvents(pWin->parent, &e, 1, NullWindow); } void client_win_change(char* buff) { WindowPtr pWin, pParent, pSib; uint32_t winId=*((uint32_t*)(buff+4)); uint32_t newSibId=*((uint32_t*)(buff+8)); struct remoteWindow* rw; int16_t x,y; uint16_t w,h,bw; int16_t nx=*((int16_t*)(buff+12)); int16_t ny=*((int16_t*)(buff+14)); uint16_t nw=*((int16_t*)(buff+16)); uint16_t nh=*((int16_t*)(buff+18)); uint8_t focus=*((int8_t*)(buff+20)); uint8_t newstate=*((int8_t*)(buff+21)); BOOL move=FALSE, resize=FALSE, restack=FALSE; // EPHYR_DBG("Client request win change: %p %d:%d %dx%d",fptr, nx,ny,nw,nh); pWin=remote_find_window_on_screen_by_id(winId, remoteVars.ephyrScreen->pScreen->root); if(!pWin) { EPHYR_DBG("Window with ID 0x%X not found on current screen",winId); return; } if(newstate==WIN_DELETED) { client_win_close(winId); return; } if(newstate==WIN_ICONIFIED) { client_win_iconify(winId); ReflectStackChange(pWin, 0, VTOther); return; } pParent = pWin->parent; pSib=0; if(newSibId) { pSib=remote_find_window_on_screen_by_id(newSibId, remoteVars.ephyrScreen->pScreen->root); if(!pSib) { EPHYR_DBG("New Sibling with ID 0x%X not found on current screen, putting below all siblings",newSibId); } } w = pWin->drawable.width; h = pWin->drawable.height; bw = pWin->borderWidth; if (pParent) { x = pWin->drawable.x - pParent->drawable.x - (int16_t) bw; y = pWin->drawable.y - pParent->drawable.y - (int16_t) bw; } else { x = pWin->drawable.x; y = pWin->drawable.y; } if (SubStrSend(pWin, pParent)) { xEvent event = { .u.configureNotify.window = pWin->drawable.id, .u.configureNotify.aboveSibling = pSib ? pSib->drawable.id : None, .u.configureNotify.x = x, .u.configureNotify.y = y, .u.configureNotify.width = w, .u.configureNotify.height = h, .u.configureNotify.borderWidth = bw, .u.configureNotify.override = pWin->overrideRedirect }; event.u.u.type = ConfigureNotify; #ifdef PANORAMIX if (!noPanoramiXExtension && (!pParent || !pParent->parent)) { event.u.configureNotify.x += screenInfo.screens[0]->x; event.u.configureNotify.y += screenInfo.screens[0]->y; } #endif DeliverEvents(pWin, &event, 1, NullWindow); } pthread_mutex_lock(&remoteVars.sendqueue_mutex); rw=remote_find_window(pWin); if(!rw) { EPHYR_DBG("Error!!!! Window %p not found in list of ext windows",pWin); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); return; } if( x!=nx || y!=ny) { if(rw) { rw->x=nx; rw->y=ny; } move=TRUE; } if(w!=nw || h!=nh) { if(rw) { rw->w=nw; rw->h=nh; } resize=TRUE; } if(pWin->nextSib!=pSib) { rw->nextSib=pSib; if(pSib) { rw->nextSibId=pSib->drawable.id; } else { rw->nextSibId=0; } restack=TRUE; } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); if(move) { // EPHYR_DBG("MOVE from %d:%d to %d:%d",x,y,nx,ny); (*pWin->drawable.pScreen->MoveWindow) (pWin, nx, ny, pSib,VTMove); } if(resize) { // EPHYR_DBG("RESIZE from %dx%d to %dx%d",w,h,nw,nh); (*pWin->drawable.pScreen->ResizeWindow) (pWin, nx, ny, nw, nh, pSib); } if(restack) { // EPHYR_DBG("Client request to move: %p on top of %p",pWin, pSib); ReflectStackChange(pWin, pSib, VTOther); } if(rw->hasFocus!=focus) { // EPHYR_DBG("Focus changed for 0x%X",winId); rw->hasFocus=focus; if(focus) { SetInputFocus(wClient(pWin), inputInfo.keyboard, pWin->drawable.id, RevertToParent, CurrentTime, TRUE); } } } void set_client_version(uint16_t ver, uint16_t os) { remoteVars.client_version=ver; if(os > WEB) { EPHYR_DBG("Unsupported OS, assuming OS_LINUX"); } else remoteVars.client_os=os; //clients version >= 1 supporting extended selection (sending big amount of data aín several chunks) remoteVars.selstruct.clientSupportsExetndedSelection=(ver > 1); //Linux clients supporting sending selection on demand (not sending data if not needed) //Web client support clipboard and selection on demand starting from v.4 remoteVars.selstruct.clientSupportsOnDemandSelection=(((ver > 1) && (os == OS_LINUX)) || ((ver > 3) && (os == WEB))); if(remoteVars.client_version>=3) { //start timer for checking if client alive pthread_mutex_lock(&remoteVars.sendqueue_mutex); remoteVars.checkKeepAliveTimer=TimerSet(0,0,CLIENTALIVE_TIMEOUT, checkClientAlive, NULL); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } } #if XORG_VERSION_CURRENT < 11900000 void pollEvents(void) { //EPHYR_DBG("polling events"); struct pollfd fds[2]; int nfds = 1; BOOL client = FALSE; memset(fds, 0 , sizeof(fds)); pthread_mutex_lock(&remoteVars.sendqueue_mutex); //We are in connected state, poll client socket if(remoteVars.client_connected) { client = TRUE; fds[0].fd = remoteVars.clientsock_tcp; } //we are in connecting state, poll server socket else if(remoteVars.serversock_tcp != -1) { fds[0].fd = remoteVars.serversock_tcp; } else //not polling any sockets { pthread_mutex_unlock(&remoteVars.sendqueue_mutex); return; } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); fds[0].events = POLLIN; if(poll(fds, nfds, 0)) { if(client) clientReadNotify(fds[0].fd, 0, NULL); else serverAcceptNotify(fds[0].fd, 0, NULL); } } #endif /* XORG_VERSION_CURRENT */ unsigned int checkSocketConnection(OsTimerPtr timer, CARD32 time, void* args) { EPHYR_DBG("CHECKING ACCEPTED CONNECTION"); TimerFree(timer); pthread_mutex_lock(&remoteVars.sendqueue_mutex); remoteVars.checkConnectionTimer=0; if(!remoteVars.client_connected) { EPHYR_DBG("NO CLIENT CONNECTION SINCE %d seconds",ACCEPT_TIMEOUT); cancelBeforeStart(); } else { EPHYR_DBG("CLIENT CONNECTED"); } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); return 0; } void serverAcceptNotify(int fd, int ready_sock, void *data) { int ret; char msg[33]; int length=32; int ready=0; remoteVars.clientsock_tcp = accept ( remoteVars.serversock_tcp, (struct sockaddr *) &remoteVars.tcp_address, &remoteVars.tcp_addrlen); if (remoteVars.clientsock_tcp <= 0) { EPHYR_DBG( "ACCEPT ERROR OR CANCELLED!\n"); return; } EPHYR_DBG ("Connection from (%s)...\n", inet_ntoa (remoteVars.tcp_address.sin_addr)); //only accept one client, close server socket close_server_socket(); if(strlen(remoteVars.acceptAddr)) { struct addrinfo hints, *res; int errcode; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags |= AI_CANONNAME; errcode = getaddrinfo (remoteVars.acceptAddr, NULL, &hints, &res); if (errcode != 0 || !res) { EPHYR_DBG ("ERROR LOOKUP %s", remoteVars.acceptAddr); terminateServer(-1); } if( ((struct sockaddr_in *) (res->ai_addr))->sin_addr.s_addr != remoteVars.tcp_address.sin_addr.s_addr) { EPHYR_DBG("Connection only allowed from %s",inet_ntoa ( ((struct sockaddr_in *)(res->ai_addr))->sin_addr)); close_client_sockets(); return; } } if(strlen(remoteVars.cookie)) { while(ready= 11900000 EPHYR_DBG("Set notify FD for client sock: %d",remoteVars.clientsock_tcp); SetNotifyFd(remoteVars.clientsock_tcp, clientReadNotify, X_NOTIFY_READ, NULL); #endif // XORG_VERSION_CURRENT remoteVars.client_connected=TRUE; remoteVars.server_version_sent=FALSE; set_client_version(0,0); if(remoteVars.checkConnectionTimer) { TimerFree(remoteVars.checkConnectionTimer); remoteVars.checkConnectionTimer=0; } remoteVars.client_initialized=FALSE; remoteVars.con_start_time=time(NULL); remoteVars.data_sent=0; remoteVars.data_copy=0; remoteVars.evBufferOffset=0; setAgentState(RUNNING); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); //here start a send thread ret = pthread_create(&remoteVars.send_thread_id, NULL, send_frame_thread, (void *)remoteVars.send_thread_id); if (ret) { EPHYR_DBG("ERROR; return code of pthread_create() is %d\n", ret); terminateServer(-1); } } void close_server_socket(void) { #if XORG_VERSION_CURRENT >= 11900000 EPHYR_DBG("Remove notify FD for server sock %d",remoteVars.serversock_tcp); RemoveNotifyFd(remoteVars.serversock_tcp); #endif /* XORG_VERSION_CURRENT */ shutdown(remoteVars.serversock_tcp, SHUT_RDWR); close(remoteVars.serversock_tcp); remoteVars.serversock_tcp=-1; } void open_udp_socket(void) { int32_t tmp_cookie[8] ; unsigned char buffer[56] = {0}; struct pollfd fds[2]; int nfds = 1; int ready; EPHYR_DBG("Opening UDP socket..."); remoteVars.sock_udp=socket (AF_INET, SOCK_DGRAM, 0); remoteVars.udp_address.sin_family = AF_UNSPEC; remoteVars.udp_address.sin_addr.s_addr = INADDR_ANY; remoteVars.udpPort=remoteVars.listenPort+1000; while (1) { EPHYR_DBG("Trying to listen on UDP port %d", remoteVars.udpPort); remoteVars.udp_address.sin_port = htons (remoteVars.udpPort); if (bind ( remoteVars.sock_udp, (struct sockaddr *) &remoteVars.udp_address, sizeof (remoteVars.udp_address)) != 0) { EPHYR_DBG( "UDP PORT %d IN USE!\n",remoteVars.udpPort); ++remoteVars.udpPort; } else { EPHYR_DBG("Accepting UDP connection on %d",remoteVars.udpPort); break; } } listen (remoteVars.sock_udp, 1); remoteVars.udp_addrlen = sizeof (struct sockaddr_in); for(int i=0;i<8;++i) { tmp_cookie[i]=rand(); srand(tmp_cookie[i]); // EPHYR_DBG("Cookie %d - %d",i,tmp_cookie[i]); } *((uint32_t*)buffer)=UDPOPEN; //4B *((uint32_t*)buffer+1)=(uint32_t)remoteVars.udpPort; //4B memcpy(buffer+8,tmp_cookie,4*8); remote_write_socket(remoteVars.clientsock_tcp,buffer,56); memset(fds, 0 , sizeof(fds)); fds[0].fd = remoteVars.sock_udp; fds[0].events = POLLIN; //wait max 3 seconds for connection on UDP port if(poll(fds, nfds, 3000)) { ready = recvfrom(remoteVars.sock_udp, buffer, 56, MSG_WAITALL, (struct sockaddr *) &remoteVars.udp_address, &remoteVars.udp_addrlen); EPHYR_DBG ("UDP Connection from (%s)...\n", inet_ntoa (remoteVars.udp_address.sin_addr)); if(ready != 8*4) { EPHYR_DBG("Wrong message size, expecting %d, received %d", 8*4, ready); } else { if(!memcmp(buffer, tmp_cookie, 8*4)) { ready=connect(remoteVars.sock_udp, (struct sockaddr *) &remoteVars.udp_address, remoteVars.udp_addrlen); if(ready) { EPHYR_DBG("Error, failed to connect to client UDP socket: %s",gai_strerror(ready)); } else { //we are connected, return from function EPHYR_DBG("Connected to client UDP socket..."); remoteVars.send_frames_over_udp=TRUE; return; } } else { EPHYR_DBG("Client sent wrong cookie over UDP socket, disconnecting"); } } } else { EPHYR_DBG("No incoming UDP connection in 3 seconds"); } //no connection is established, closing udp socket and sending notification close_udp_socket(); *((uint32_t*)buffer)=UDPFAILED; //4B remote_write_socket(remoteVars.clientsock_tcp,buffer,56); } void open_socket(void) { const int y = 1; EPHYR_DBG("Opening TCP socket..."); remoteVars.send_frames_over_udp=FALSE; remoteVars.serversock_tcp=socket (AF_INET, SOCK_STREAM, 0); setsockopt( remoteVars.serversock_tcp, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(int)); remoteVars.tcp_address.sin_family = AF_INET; remoteVars.tcp_address.sin_addr.s_addr = INADDR_ANY; if(! strlen(remoteVars.acceptAddr)) EPHYR_DBG("Accepting connections from 0.0.0.0"); else EPHYR_DBG("Accepting connections from %s", remoteVars.acceptAddr); if(!remoteVars.listenPort) { remoteVars.listenPort=DEFAULT_PORT; } EPHYR_DBG("Listening on port %d", remoteVars.listenPort); remoteVars.tcp_address.sin_port = htons (remoteVars.listenPort); if (bind ( remoteVars.serversock_tcp, (struct sockaddr *) &remoteVars.tcp_address, sizeof (remoteVars.tcp_address)) != 0) { EPHYR_DBG( "TCP PORT IN USE!\n"); terminateServer(-1); } listen (remoteVars.serversock_tcp, 1); remoteVars.tcp_addrlen = sizeof (struct sockaddr_in); remoteVars.checkConnectionTimer=TimerSet(0,0,ACCEPT_TIMEOUT, checkSocketConnection, NULL); #if XORG_VERSION_CURRENT >= 11900000 EPHYR_DBG("Set notify FD for server sock: %d",remoteVars.serversock_tcp); EPHYR_DBG ("waiting for client connection\n"); SetNotifyFd(remoteVars.serversock_tcp, serverAcceptNotify, X_NOTIFY_READ, NULL); #endif // XORG_VERSION_CURRENT EPHYR_DBG("Server TCP socket is ready"); } void terminateServer(int exitStatus) { setAgentState(TERMINATING); if(remoteVars.client_connected) { send_srv_disconnect(); disconnect_client(); pthread_join(remoteVars.send_thread_id,NULL); remoteVars.send_thread_id=0; } if(remoteVars.send_thread_id) { pthread_cancel(remoteVars.send_thread_id); } if(remoteVars.selstruct.selThreadId) { pthread_cancel(remoteVars.selstruct.selThreadId); remove_obsolete_incr_transactions(FALSE); if(remoteVars.selstruct.xcbConnection) { xcb_disconnect(remoteVars.selstruct.xcbConnection); } pthread_mutex_destroy(&remoteVars.selstruct.inMutex); } pthread_mutex_destroy(&remoteVars.mainimg_mutex); pthread_mutex_destroy(&remoteVars.sendqueue_mutex); pthread_cond_destroy(&remoteVars.have_sendqueue_cond); if(remoteVars.main_img) { free(remoteVars.main_img); free(remoteVars.second_buffer); EPHYR_DBG("freeing screen regions"); free(remoteVars.screen_regions); } if(remoteVars.selstruct.inSelection[0].data) { free(remoteVars.selstruct.inSelection[0].data); } if(remoteVars.selstruct.inSelection[1].data) { free(remoteVars.selstruct.inSelection[1].data); } setAgentState(TERMINATED); EPHYR_DBG("exiting program with status %d", exitStatus); GiveUp(SIGTERM); } static void processConfigFileSetting(char* key, char* value) { // EPHYR_DBG("processing setting \"%s\" with value \"%s\"", key, value); if(!strcmp(key, "state")) { strncpy(remoteVars.stateFile, value, 255); remoteVars.stateFile[255]=0; EPHYR_DBG("state file %s", remoteVars.stateFile); } else if(!strcmp(key, "pack")) { unsigned char quality=value[strlen(value)-1]; if(quality>='0'&& quality<='9') { if(strncmp(value+strlen(value)-5,"png",3) ==0) { remoteVars.compression=PNG; EPHYR_DBG("Using PNG compression"); } else { remoteVars.compression=JPEG; EPHYR_DBG("Using JPEG compression"); } remoteVars.initialJpegQuality=(quality-'0')*10+9; if(remoteVars.initialJpegQuality > JPG_QUALITY) { //x2goclient can set by default quality 90, but it doesn't really make sense. Maybe we could think about overriding it in the future EPHYR_DBG("JPEG quality %d is requested, x2gokdrive will override it to %d",remoteVars.initialJpegQuality, JPG_QUALITY); remoteVars.initialJpegQuality=JPG_QUALITY; } remoteVars.jpegQuality=remoteVars.initialJpegQuality; EPHYR_DBG("Image quality: %d", remoteVars.jpegQuality); } } else if(!strcmp(key, "accept")) { strncpy(remoteVars.acceptAddr, value, 255); remoteVars.acceptAddr[255]=0; EPHYR_DBG("accept %s", remoteVars.acceptAddr); } else if(!strcmp(key, "cookie")) { strncpy(remoteVars.cookie, value, 32); remoteVars.cookie[32]=0; } else if(!strcmp(key, "listen")) { sscanf(value, "%d",&remoteVars.listenPort); EPHYR_DBG("listen %d", remoteVars.listenPort); } else if(!strcmp(key, "listen_udp")) { sscanf(value, "%d",&remoteVars.udpPort); EPHYR_DBG("listen_udp %d", remoteVars.udpPort); } else if(!strcmp(key, "clipboard")) { if(!strcmp(value,"client")) { remoteVars.selstruct.selectionMode=CLIP_CLIENT; EPHYR_DBG("CLIPBOARD MODE: client"); } else if(!strcmp(value,"server")) { remoteVars.selstruct.selectionMode=CLIP_SERVER; EPHYR_DBG("CLIPBOARD MODE: server"); } else if(!strcmp(value,"both")) { remoteVars.selstruct.selectionMode=CLIP_BOTH; EPHYR_DBG("CLIPBOARD MODE: both"); } else { remoteVars.selstruct.selectionMode=CLIP_NONE; EPHYR_DBG("CLIPBOARD MODE: disabled"); } } } void readOptionsFromFile(void) { FILE *ptr=fopen(remoteVars.optionsFile,"rt"); if(ptr) { char key[255]=""; char value[255]=""; BOOL readVal=FALSE; int ind=0; while(1) { int c=fgetc(ptr); if(c==EOF) break; // EPHYR_DBG("%c",c); if(c=='=') { key[ind]='\0'; ind=0; readVal=TRUE; continue; } if(c==',' || c==':') { value[ind]='\0'; ind=0; readVal=FALSE; processConfigFileSetting(key, value); if(c==':') break; continue; } if(readVal) value[ind++]=(unsigned char)c; else key[ind++]=(unsigned char)c; /* read file and get quality and state file */ } fclose(ptr); } else { EPHYR_DBG("Can't open options file %s", remoteVars.optionsFile); terminateServer(-1); } } int remote_init(void) { char* displayVar = NULL; /*init it in OsInit*/ EPHYR_DBG("Setting initial arguments"); fclose(stdout); fclose(stdin); remoteVars.serversock_tcp=remoteVars.sock_udp=-1; if(!remoteVars.initialJpegQuality) remoteVars.initialJpegQuality=remoteVars.jpegQuality=JPG_QUALITY; EPHYR_DBG("JPEG quality is %d", remoteVars.initialJpegQuality); remoteVars.compression=DEFAULT_COMPRESSION; remoteVars.selstruct.selectionMode = CLIP_BOTH; if(!strlen(remote_get_init_geometry())) { EPHYR_DBG("Setting initial geometry to \"800x600\""); remote_set_init_geometry("800x600"); } pthread_mutex_init(&remoteVars.mainimg_mutex, NULL); pthread_mutex_init(&remoteVars.sendqueue_mutex,NULL); pthread_cond_init(&remoteVars.have_sendqueue_cond,NULL); displayVar=secure_getenv("DISPLAY"); if(displayVar) { if(!strncmp(displayVar,"nx/nx,options=",strlen("nx/nx,options="))) { int i=strlen("nx/nx,options="); int j=0; EPHYR_DBG("running in NXAGENT MODE"); remoteVars.nxagentMode=TRUE; while(displayVar[i]!=':' && isize)+length; outdata->out=realloc(outdata->out, newLength); memcpy(outdata->out+*(outdata->size),data,length); *(outdata->size)=newLength; } unsigned char* png_compress( uint32_t image_width, uint32_t image_height, unsigned char* RGBA_buffer, uint32_t* png_size, BOOL compress_cursor) { struct { uint32_t* size; unsigned char *out; } outdata; unsigned char** rows = NULL; int color_type; int bpp; png_structp p; png_infop info_ptr; if(compress_cursor) { color_type = PNG_COLOR_TYPE_RGB_ALPHA; bpp = 4; } else { color_type = PNG_COLOR_TYPE_RGB; bpp = CACHEBPP; } p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(p); setjmp(png_jmpbuf(p)); png_set_IHDR(p, info_ptr,image_width, image_height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); *png_size=0; rows = calloc(sizeof(unsigned char*), image_height); outdata.size=png_size; outdata.out=0; for (uint32_t y = 0; y < image_height; ++y) rows[y] = (unsigned char*)RGBA_buffer + y * image_width * bpp; png_set_rows(p, info_ptr, &rows[0]); png_set_write_fn(p, &outdata, PngWriteCallback, NULL); png_write_png(p, info_ptr, PNG_TRANSFORM_BGR, NULL); png_destroy_info_struct(p, &info_ptr ); png_destroy_write_struct(&p, NULL); free(rows); return outdata.out; } unsigned char* jpeg_compress (int quality, uint32_t image_width, uint32_t image_height, unsigned char* RAW_buffer, uint32_t* jpeg_size, int bpp, char* fname) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1];/* pointer to JSAMPLE row[s] */ int row_stride;/* physical row width in image buffer */ unsigned char* out_bufer=0; long unsigned int length=0; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_mem_dest(&cinfo,&out_bufer, &length); cinfo.image_width = image_width; /* image width and height, in pixels */ cinfo.image_height = image_height; cinfo.input_components = bpp; /* # of color components per pixel */ if(bpp == 4) cinfo.in_color_space = JCS_EXT_BGRX; /* colorspace of input image */ else cinfo.in_color_space = JCS_EXT_BGR; /* colorspace of input image */ jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */ jpeg_start_compress(&cinfo, TRUE); row_stride = image_width * bpp; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = & RAW_buffer[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); *jpeg_size=length; jpeg_destroy_compress(&cinfo); if(fname && JPGDEBUG) { FILE * outfile; if ((outfile = fopen(fname, "wb")) == NULL) { // fprintf(stderr, "can't open %s\n", fname); } else { fwrite(out_bufer, 1, length, outfile); fclose(outfile); } } return out_bufer; } unsigned char* image_compress(uint32_t image_width, uint32_t image_height, unsigned char* RGBA_buffer, uint32_t* compressed_size, int bpp, char* fname) { if(remoteVars.compression==JPEG) return jpeg_compress(remoteVars.jpegQuality, image_width, image_height, RGBA_buffer, compressed_size, bpp, fname); else return png_compress(image_width, image_height, RGBA_buffer, compressed_size, FALSE); } static struct cache_elem* add_cache_element(uint32_t crc, int32_t dx, int32_t dy, uint32_t size, uint32_t width, uint32_t height) { struct cache_elem* el=malloc(sizeof(struct cache_elem)); bzero(el, sizeof(struct cache_elem)); el->crc=crc; el->width=width; el->height=height; // if(CACHEBPP==4) // { // el->size=size; // el->data=malloc(size); // remoteVars.cache_size+=size; // memcpy(el->data, data, size); // } // else { uint32_t i=0; uint32_t numOfPix=size/4; uint32_t isize=size/4*3; el->size=isize; // EPHYR_DBG("SIZE %d %d %d, %d, %d",isize, dx, dy, width, height); el->data=malloc(isize); if(!el->data) { EPHYR_DBG("error allocating data for frame"); exit(-1); } remoteVars.cache_size+=isize; /* copy RGB channels of every pixel and ignore A channel */ pthread_mutex_lock(&remoteVars.mainimg_mutex); for(int32_t y=0;ydata+i*CACHEBPP, remoteVars.main_img+ind, CACHEBPP); el->rval+= (unsigned char)(*(remoteVars.main_img+ind)); el->gval+= (unsigned char)(*(remoteVars.main_img+ind+1)); el->bval+= (unsigned char)(*(remoteVars.main_img+ind+2)); ++i; } } pthread_mutex_unlock(&remoteVars.mainimg_mutex); el->rval/=numOfPix; el->gval/=numOfPix; el->bval/=numOfPix; } remoteVars.cache_elements++; el->prev=remoteVars.last_cache_element; // EPHYR_DBG("\ncache elements %d, cache size %u(%dMB) %u, %u, %u\n", cache_elements, cache_size, (int) (cache_size/1024/1024), el->rval, // el->gval, el->bval); if(remoteVars.last_cache_element) { remoteVars.last_cache_element->next=el; } else { remoteVars.first_cache_element=el; } remoteVars.last_cache_element=el; return el; } /* * this function looking for the cache elements with specified crc * if the element is found we moving it in the end of list * in this case we keeping the most recent elements in the tail of * list for faster search */ static struct cache_elem* find_cache_element(uint32_t crc) { struct cache_elem* current=remoteVars.last_cache_element; while(current) { if(current->crc==crc) { if(current==remoteVars.last_cache_element) { return current; } if(current==remoteVars.first_cache_element) { remoteVars.first_cache_element=current->next; remoteVars.first_cache_element->prev=0; } else { current->prev->next=current->next; current->next->prev=current->prev; } current->prev=remoteVars.last_cache_element; remoteVars.last_cache_element->next=current; current->next=0l; remoteVars.last_cache_element=current; return current; } current=current->prev; } return 0; } static void initFrameRegions(struct cache_elem* frame) { BOOL haveMultplyRegions=FALSE; int32_t length=0; struct frame_region* regions=frame->regions; BOOL diff; if(frame->width>4 && frame->height>4 && frame->width * frame->height > 100 ) { unsigned int match_val = 0; uint32_t bestm_crc = 0; struct cache_elem* best_match = NULL; pthread_mutex_lock(&remoteVars.sendqueue_mutex); best_match = find_best_match(frame, &match_val); if(best_match) { best_match->busy+=1; } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); if(best_match && best_match->width>4 && best_match->height>4 && best_match->width * best_match->height > 100 ) { bestm_crc=best_match->crc; if(best_match && match_val<=MAX_MATCH_VAL) { rectangle rect = {{0}}; int hshift, vshift = 0; if(find_common_regions(best_match, frame, &diff, &rect, &hshift, &vshift)) { haveMultplyRegions=TRUE; if(!diff) { int prev = -1; // EPHYR_DBG("SOURCE: %x %d:%d - %dx%d- shift %d, %d",bestm_crc, // rect.lt_corner.x, rect.lt_corner.y, // rect.size.width, rect.size.height, hshift, vshift); rectangle* base=&(regions[8].rect); base->size.width=rect.size.width; base->size.height=rect.size.height; base->lt_corner.x=rect.lt_corner.x+hshift; base->lt_corner.y=rect.lt_corner.y+vshift; //regions[8] represents common with bestmatch region regions[8].source_coordinates.x=rect.lt_corner.x; regions[8].source_coordinates.y=rect.lt_corner.y; regions[8].source_crc=bestm_crc; frame->source=best_match; regions[0].rect.lt_corner.x=regions[3].rect.lt_corner.x= regions[5].rect.lt_corner.x=0; regions[0].rect.size.width=regions[3].rect.size.width= regions[5].rect.size.width=base->lt_corner.x; regions[2].rect.lt_corner.x=regions[4].rect.lt_corner.x= regions[7].rect.lt_corner.x=base->lt_corner.x+base->size.width; regions[2].rect.size.width=regions[4].rect.size.width= regions[7].rect.size.width=frame->width-regions[7].rect.lt_corner.x; regions[0].rect.lt_corner.y=regions[1].rect.lt_corner.y= regions[2].rect.lt_corner.y=0; regions[0].rect.size.height=regions[1].rect.size.height= regions[2].rect.size.height=base->lt_corner.y; regions[5].rect.lt_corner.y=regions[6].rect.lt_corner.y= regions[7].rect.lt_corner.y=base->lt_corner.y+base->size.height; regions[5].rect.size.height=regions[6].rect.size.height= regions[7].rect.size.height=frame->height-regions[7].rect.lt_corner.y; regions[1].rect.lt_corner.x=regions[6].rect.lt_corner.x=base->lt_corner.x; regions[1].rect.size.width=regions[6].rect.size.width=base->size.width; regions[3].rect.lt_corner.y=regions[4].rect.lt_corner.y=base->lt_corner.y; regions[3].rect.size.height=regions[4].rect.size.height=base->size.height; for(int i=0;i<8;++i) { if(regions[i].rect.size.width && regions[i].rect.size.height) { if((regions[i].rect.lt_corner.y == regions[prev].rect.lt_corner.y) && (regions[prev].rect.lt_corner.x+regions[prev].rect.size.width == regions[i].rect.lt_corner.x)&&prev>0) { //EPHYR_DBG("Unite %d and %d", prev,i); regions[prev].rect.size.width+=regions[i].rect.size.width; regions[i].rect.size.width=0; } else { prev=i; } } } } else { rectangle* base=&(regions[0].rect); base->size.width=frame->width; base->size.height=frame->height; base->lt_corner.x=0; base->lt_corner.y=0; /* regions[0] represents common with bestmatch region */ regions[0].source_coordinates.x=0; regions[0].source_coordinates.y=0; regions[0].source_crc=bestm_crc; frame->source=best_match; memcpy(&(regions[1].rect), &rect, sizeof(rectangle)); } } } } /* if we didn't find any common regions and have best match element, mark it as not busy */ pthread_mutex_lock(&remoteVars.sendqueue_mutex); if(best_match && frame->source != best_match) { // EPHYR_DBG("Have best match but no common region"); best_match->busy-=1; } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } if(!haveMultplyRegions) { // EPHYR_DBG("HAVE SINGLE REGION"); regions[0].compressed_data=image_compress(frame->width, frame->height, frame->data, &(regions[0].size), CACHEBPP, 0); length=regions[0].size; regions[0].rect.size.width=frame->width; regions[0].rect.size.height=frame->height; regions[0].rect.lt_corner.x=regions[0].rect.lt_corner.y=0; } else { if(!diff) { for (int i=0;i<8;++i) { if(regions[i].rect.size.width && regions[i].rect.size.height) { // uint32_t send_data=regions[i].rect.size.width*regions[i].rect.size.height; // uint32_t total_data=frame->width*frame->height; // EPHYR_DBG("saved space: %d%% %d %d %dx%d %dx%d", 100 - (int)((send_data*1./total_data)*100), total_data, send_data,frame->width, frame->height, // regions[i].rect.size.width,regions[i].rect.size.height); // #warning check this uint8_t *data=malloc(regions[i].rect.size.width*regions[i].rect.size.height*CACHEBPP); for(int line=0;linedata+((regions[i].rect.lt_corner.y+line)* frame->width+regions[i].rect.lt_corner.x)*CACHEBPP, regions[i].rect.size.width*CACHEBPP); } regions[i].compressed_data=image_compress(regions[i].rect.size.width, regions[i].rect.size.height, data, ®ions[i].size, CACHEBPP, 0); length+=regions[i].size; free(data); } } } else { char fname[255]; // #warning check this uint8_t *data=malloc(regions[1].rect.size.width*regions[1].rect.size.height*CACHEBPP); for(int line=0;linedata+((regions[1].rect.lt_corner.y+line)* frame->width+regions[1].rect.lt_corner.x)*CACHEBPP, regions[1].rect.size.width*CACHEBPP); } sprintf(fname,"/tmp/.x2go/x2gokdrive_dbg/%x-rect_inv.jpg",frame->crc); regions[1].compressed_data=image_compress(regions[1].rect.size.width, regions[1].rect.size.height, data, ®ions[1].size, CACHEBPP, fname); length+=regions[1].size; free(data); } } frame->compressed_size=length; } void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t crc, uint32_t size, uint32_t winId) { Bool isNewElement = FALSE; struct cache_elem* frame = 0; struct sendqueue_element* element = NULL; pthread_mutex_lock(&remoteVars.sendqueue_mutex); if(! (remoteVars.client_connected && remoteVars.client_initialized) || remoteVars.cache_rebuilt) { /* don't have any clients connected, or cache rebuild is requested, return */ pthread_mutex_unlock(&remoteVars.sendqueue_mutex); return; } if(crc==0) { /* sending main image */ pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } else { frame=find_cache_element(crc); if(!frame) { // EPHYR_DBG("ADD NEW FRAME %x",crc); frame=add_cache_element(crc, x, y, size, width, height); isNewElement=TRUE; } else { // EPHYR_DBG("ADD EXISTING FRAME %x",crc); } frame->busy+=1; pthread_mutex_unlock(&remoteVars.sendqueue_mutex); /* if element is new find common regions and compress the data */ if(isNewElement) { /* find bestmatch and lock it */ initFrameRegions(frame); } } pthread_mutex_lock(&remoteVars.sendqueue_mutex); /* add element in the queue for sending */ element=malloc(sizeof(struct sendqueue_element)); element->frame=frame; element->next=NULL; element->x=x; element->y=y; element->width=width; element->height=height; element->winId=winId; if(remoteVars.last_sendqueue_element) { remoteVars.last_sendqueue_element->next=element; remoteVars.last_sendqueue_element=element; } else { remoteVars.first_sendqueue_element=remoteVars.last_sendqueue_element=element; } pthread_cond_signal(&remoteVars.have_sendqueue_cond); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); /* on this point will be sent wakeup single to send mutex */ } void remote_send_main_image(void) { add_frame(0, 0, 0, 0, 0, 0,0); } struct remoteWindow* remote_find_window(WindowPtr win) { struct remoteWindow* rw=remoteVars.windowList; // EPHYR_DBG("LOOK for %p in list",win); while(rw) { if(rw->ptr==win) { return rw; } rw=rw->next; } // EPHYR_DBG("WINDOW %p not found in list",win); return NULL; } void remote_check_window(WindowPtr win) { char *name=NULL; int nameSize=0; char *netName=NULL; int netNameSize=0; char *dispName=NULL; int dispNameSize=0; BOOL ignore = TRUE; BOOL hasFocus=FALSE; struct remoteWindow* rwin; uint32_t transWinId=0; uint8_t winType=WINDOW_TYPE_NORMAL; int16_t x,y,i, minw=0, minh=0; uint16_t w,h,bw; uint32_t iw,ih; uint32_t max_icon_w=0, max_icon_h=0; unsigned char *icon_data; uint32_t focusWinId=0; // ExWMHints* wmhints; ExSizeHints* sizehints; FocusClassPtr focus = inputInfo.keyboard->focus; WindowPtr parPtr; WindowPtr nextSibPtr, tmpPtr; parPtr=win->parent; nextSibPtr=NULL; //if prentwindow is root, set it to 0 if(parPtr == remoteVars.ephyrScreen->pScreen->root) { parPtr=NULL; } w = win->drawable.width; h = win->drawable.height; bw = win->borderWidth; if (win->parent) { x = win->drawable.x - win->parent->drawable.x - (int) bw; y = win->drawable.y - win->parent->drawable.y - (int) bw; } else { x = win->drawable.x; y = win->drawable.y; } // EPHYR_DBG("Check win %p",win); if(!win->optional || !win->optional->userProps || !win->mapped || win->visibility<0 || win->visibility>2) { return; } //find nextSib tmpPtr=win->nextSib; while(tmpPtr) { if(remote_find_window(tmpPtr)) { nextSibPtr=tmpPtr; break; } tmpPtr=tmpPtr->nextSib; } /* * if window is not in list, create and send to client. If not same, update and send to client * if some list windows not there anymore, delete and send notification */ if (focus->win == NoneWin) focusWinId = None; else if (focus->win == PointerRootWin) focusWinId = PointerRoot; else focusWinId = focus->win->drawable.id; hasFocus=(win->drawable.id==focusWinId); if(win->optional && win->optional->userProps) { PropertyPtr prop=win->optional->userProps; // EPHYR_DBG("======%x - PARENT %p = VIS %d === MAP %d =============",win->drawable.id, parPtr, win->visibility, win->mapped); while(prop) { if(prop->propertyName==MakeAtom("WM_NAME", strlen("WM_NAME"),FALSE) && prop->data) { name=prop->data; nameSize=prop->size; } if(prop->propertyName==MakeAtom("WM_HINTS", strlen("WM_HINTS"),FALSE) && prop->data) { ignore=FALSE; } if(prop->propertyName==MakeAtom("_NET_WM_NAME", strlen("_NET_WM_NAME"),FALSE) && prop->data) { netName=prop->data; netNameSize=prop->size; } if(prop->propertyName==MakeAtom("WM_TRANSIENT_FOR", strlen("WM_TRANSIENT_FOR"),FALSE) && prop->data) { transWinId=((uint32_t*)prop->data)[0]; // EPHYR_DBG("Trans Win 0x%X = 0x%X", transWinId, win->drawable.id); } if(prop->propertyName==MakeAtom("_NET_WM_ICON", strlen("_NET_WM_ICON"),FALSE) && prop->data) { // EPHYR_DBG("_NET_WM_ICON size: %d",prop->size); i=0; while(isize/4) { iw=((uint32_t*)prop->data)[i++]; ih=((uint32_t*)prop->data)[i++]; if(!iw || !ih ||iw>256 || ih>256) break; // EPHYR_DBG("ICON: %dx%d", iw, ih); if(iw>max_icon_w) { max_icon_w=iw; max_icon_h=ih; icon_data=(unsigned char*)prop->data+i*4; } i+=iw*ih; } } // EPHYR_DBG("%s %s, Format %d, Size %d",NameForAtom(prop->propertyName), NameForAtom(prop->type), prop->format, prop->size); // if( prop->type == MakeAtom("STRING", strlen("STRING"),FALSE) || prop->type == MakeAtom("UTF8_STRING", strlen("UTF8_STRING"),FALSE)) // { // // EPHYR_DBG("-- %s",(char*)prop->data); // } if( prop->type == MakeAtom("ATOM", strlen("ATOM"),FALSE)) { ATOM* at=prop->data; // if(prop->propertyName==MakeAtom("_NET_WM_STATE", strlen("_NET_WM_STATE"),FALSE)) // { // for(i=0;isize;++i) // { // // EPHYR_DBG("--WINDOW STATE[%d]: %s, my ID 0x%X",i, NameForAtom( at[i] ), win->drawable.id); // } // } // EPHYR_DBG("-- %s",NameForAtom( at[0] )); if(prop->propertyName==MakeAtom("_NET_WM_WINDOW_TYPE", strlen("_NET_WM_WINDOW_TYPE"),FALSE)) { // EPHYR_DBG("WINDOW Type: %s, my ID 0x%X",NameForAtom( at[0] ), win->drawable.id); if(at[0]==MakeAtom("_NET_WM_WINDOW_TYPE_NORMAL", strlen("_NET_WM_WINDOW_TYPE_NORMAL"),FALSE)) { // EPHYR_DBG("Normal window"); winType=WINDOW_TYPE_NORMAL; } else if(at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_DIALOG", strlen("_NET_WM_WINDOW_TYPE_DIALOG"),FALSE)) { // EPHYR_DBG("Dialog"); winType=WINDOW_TYPE_DIALOG; } else if(at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", strlen("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),FALSE)) { // EPHYR_DBG("Dropdown menu"); winType=WINDOW_TYPE_DROPDOWN_MENU; } else if(at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_POPUP_MENU", strlen("_NET_WM_WINDOW_TYPE_POPUP_MENU"),FALSE)) { // EPHYR_DBG("Popup menu"); winType=WINDOW_TYPE_POPUP_MENU; } else if( at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_SPLASH", strlen("_NET_WM_WINDOW_TYPE_SPLASH"),FALSE)) { // EPHYR_DBG("Splash"); winType=WINDOW_TYPE_SPLASH; } else if( at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_TOOLTIP", strlen("_NET_WM_WINDOW_TYPE_TOOLTIP"),FALSE)) { winType=WINDOW_TYPE_TOOLTIP; } else if( at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_COMBO", strlen("_NET_WM_WINDOW_TYPE_COMBO"),FALSE)) { winType=WINDOW_TYPE_COMBO; } else if( at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_UTILITY", strlen("_NET_WM_WINDOW_TYPE_UTILITY"),FALSE)) { winType=WINDOW_TYPE_UTILITY; } else if( at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_DND", strlen("_NET_WM_WINDOW_TYPE_DND"),FALSE)) { //drag windows have similar properties to utility windows // EPHYR_DBG("Drag Window, WINDOW Type: %s, my ID 0x%X",NameForAtom( at[0] ), win->drawable.id); winType=WINDOW_TYPE_UTILITY; } } } // if(prop->propertyName==MakeAtom("WM_STATE", strlen("WM_STATE"),FALSE) && prop->data) // { // // EPHYR_DBG("-- WM_STATE: %d",*((uint32_t*)(prop->data))); // } /* if(prop->propertyName==MakeAtom("WM_NAME", strlen("WM_NAME"),FALSE) && prop->data) { // EPHYR_DBG("-- Name: %s",(char*)prop->data); } if(prop->propertyName==MakeAtom("WM_WINDOW_ROLE", strlen("WM_WINDOW_ROLE"),FALSE) && prop->data) { // EPHYR_DBG("-- Role: %s",(char*)prop->data); } if(prop->propertyName==MakeAtom("WM_CLASS", strlen("WM_CLASS"),FALSE) && prop->data) { // EPHYR_DBG("-- Class: %s",(char*)prop->data); } if(prop->propertyName==MakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"),FALSE) && prop->data) { ATOM* at=prop->data; EPHYR_DBG("-- WM_PROTOCOLS: %s",NameForAtom( at[0] )); } if(prop->propertyName==MakeAtom("WM_HINTS", strlen("WM_HINTS"),FALSE)) { EPHYR_DBG("--WM HINTS:"); wmhints=(ExWMHints*)prop->data; if(wmhints->flags & ExInputHint) { EPHYR_DBG(" Input: %d",wmhints->input); } if(wmhints->flags & ExStateHint) { EPHYR_DBG(" State: %d",wmhints->initial_state); } }*/ if(prop->propertyName==MakeAtom("WM_NORMAL_HINTS", strlen("WM_NORMAL_HINTS"),FALSE)) { // EPHYR_DBG("--SIZE HINTS:"); sizehints=(ExSizeHints*)prop->data; if(sizehints[0].flags & ExPMinSize) { minw=sizehints->min_width; minh=sizehints->min_height; // EPHYR_DBG(" Min Size: %dx%d",sizehints->min_width, sizehints->min_height); } if(sizehints[0].flags & ExUSSize) { // EPHYR_DBG(" User Size: need calc"); } } prop=prop->next; } } if(ignore) { // EPHYR_DBG("=======IGNORE THIS WINDOW=============="); return; } if(netNameSize && netName) { dispName=netName; dispNameSize=netNameSize; } else { dispName=name; dispNameSize=nameSize; } // EPHYR_DBG("\n\nWIN: %p, %s, PAR: %p, %d:%d %dx%d, border %d, visibility: %d, view %d, map %d ID %d", win, dispName, parPtr, x, y, // w, h, bw, win->visibility, win->viewable, win->mapped, win->drawable.id); if(winType == WINDOW_TYPE_NORMAL && transWinId) { winType=WINDOW_TYPE_DIALOG; } rwin=remote_find_window(win); if(!rwin) { /*create new window and put it as a first element of the list*/ rwin=malloc(sizeof(struct remoteWindow)); rwin->state=NEW; rwin->ptr=win; rwin->next=remoteVars.windowList; remoteVars.windowList=rwin; rwin->name=NULL; rwin->icon_png=NULL; rwin->icon_size=0; rwin->minw=minw; rwin->minh=minh; if(max_icon_w && (winType==WINDOW_TYPE_NORMAL || winType==WINDOW_TYPE_DIALOG)) { rwin->icon_png=png_compress( max_icon_w, max_icon_h, icon_data, &rwin->icon_size, TRUE); } else max_icon_w=0; // EPHYR_DBG("Add to list: ID 0x%X, type %d, %s, %d:%d %dx%d, visibility: %d", win->drawable.id, winType, rwin->name, x,y, // w, h, win->visibility); } else { // EPHYR_DBG("found in list: %p, %s, %d:%d %dx%d, visibility: %d", rwin->ptr, rwin->name, rwin->x,rwin->y, // rwin->w, rwin->h,rwin->visibility); if(rwin->name || dispName) { if(rwin->name==NULL && dispName) { rwin->state=CHANGED; }else if(strlen(rwin->name)!=dispNameSize) { rwin->state=CHANGED; }else if (strncmp(rwin->name,dispName, dispNameSize)) { rwin->state=CHANGED; } } if(rwin->x != x || rwin->y != y || rwin->w != w || rwin->h != h || rwin->bw != bw || rwin->visibility != win->visibility) { rwin->state=CHANGED; } if(rwin->parent != parPtr || rwin->nextSib != nextSibPtr) { // EPHYR_DBG("STACK order changed for %p %s old parent %p new parent %p, old nextsib %p, new nextsib %p", rwin->ptr, rwin->name, rwin->parent, parPtr, rwin->nextSib, nextSibPtr); rwin->state=CHANGED; } if(rwin->visibility!=win->visibility) { // EPHYR_DBG("Visibility changed for 0x%X from %d to %d", rwin->id, rwin->visibility, win->visibility); rwin->state=CHANGED; } if(rwin->hasFocus!=hasFocus) { // EPHYR_DBG("Focus changed for 0x%X from %d to %d", rwin->id, rwin->hasFocus, hasFocus); } } rwin->hasFocus=hasFocus; rwin->foundInWinTree=TRUE; rwin->x=x; rwin->y=y; rwin->w=w; rwin->h=h; rwin->bw=bw; rwin->visibility=win->visibility; rwin->parent=parPtr; rwin->nextSib=nextSibPtr; rwin->winType=winType; rwin->id=win->drawable.id; rwin->transWinId=transWinId; if(rwin->parent) rwin->parentId=rwin->parent->drawable.id; else rwin->parentId=0; if(rwin->nextSib) rwin->nextSibId=rwin->nextSib->drawable.id; else rwin->nextSibId=0; if(!rwin->name || strlen(rwin->name)!=dispNameSize || strncmp(rwin->name,dispName,dispNameSize)) { if(rwin->name) { free(rwin->name); rwin->name=NULL; } if(dispNameSize) { rwin->name=malloc(dispNameSize+1); strncpy(rwin->name, dispName, dispNameSize); rwin->name[dispNameSize]='\0'; } } if(rwin->state != UNCHANGED) { remoteVars.windowsUpdated=TRUE; if(rwin->state==NEW) { // EPHYR_DBG("NEW WINDOW %p, %s, %d:%d %dx%d bw-%d, visibility: %d parent %p nextSib %p",rwin->ptr, rwin->name, rwin->x,rwin->y, // rwin->w, rwin->h, rwin->bw ,rwin->visibility, rwin->parent, rwin->nextSib); } else { // EPHYR_DBG("WINDOW CHANGED:"); } /* if(rwin->name &&( !strncmp (rwin->name, "xterm",4))) { EPHYR_DBG("=======WIN: %p, %s, %d:%d %dx%d bw-%d, visibility: %d parent %p nextSib %p", rwin->ptr, rwin->name, rwin->x,rwin->y, rwin->w, rwin->h, rwin->bw ,rwin->visibility, rwin->parent, rwin->nextSib); }*/ //only for debug purpose /* EPHYR_DBG("CURRENT STACK:"); WindowPtr wn = remoteVars.ephyrScreen->pScreen->root->firstChild; while(wn) { char* nm=NULL; struct remoteWindow* rw=remote_find_window(wn); if(rw) { nm=rw->name; } if(wn->mapped) { EPHYR_DBG("%p (%s) mapped: %d",wn,nm,wn->mapped); } wn=wn->nextSib; } EPHYR_DBG("END OF STACK:");*/ // } // EPHYR_DBG("=====FOCUS WIN ID 0x%X=====================",focusWinId); } void remote_check_windowstree(WindowPtr root) { WindowPtr child; child=root->firstChild; while(child) { remote_check_windowstree(child); remote_check_window(child); child=child->nextSib; } } WindowPtr remote_find_window_on_screen_by_id(uint32_t winId, WindowPtr root) { WindowPtr child; child=root->firstChild; while(child) { if(child->drawable.id == winId) { return child; } if(remote_find_window_on_screen_by_id(winId,child)) { return child; } child=child->nextSib; } return NULL; } WindowPtr remote_find_window_on_screen(WindowPtr win, WindowPtr root) { WindowPtr child; child=root->firstChild; while(child) { if(child == win) { return win; } if(remote_find_window_on_screen(win,child)) { return win; } child=child->nextSib; } return NULL; } void remote_check_rootless_windows_for_updates(KdScreenInfo *screen) { struct remoteWindow* rwin; pthread_mutex_lock(&remoteVars.sendqueue_mutex); //don't check windows if no client is connected if(remoteVars.client_connected==FALSE) { pthread_mutex_unlock(&remoteVars.sendqueue_mutex); return; } // EPHYR_DBG("START TREE CHECK"); remote_check_windowstree(screen->pScreen->root); //check all windows in list and mark as deleted if not found in the tree rwin=remoteVars.windowList; while(rwin) { if(!rwin->foundInWinTree) { remoteVars.windowsUpdated=TRUE; //mark window as deleted rwin->state=WDEL; // EPHYR_DBG("DELETED WINDOW: %p, %s",rwin->ptr, rwin->name); } rwin->foundInWinTree=FALSE; rwin=rwin->next; } pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } //check if the point belongs to region. If the point is close enough, but not inside of region, extend the region boundaries BOOL insideOfRegion(struct PaintRectRegion* reg, int x , int y) { if(!reg) return FALSE; if(x >= reg->x1 - MAXDISTANCETOREGION && x <= reg->x2+MAXDISTANCETOREGION && y >= reg->y1 - MAXDISTANCETOREGION && y<= reg->y2 + MAXDISTANCETOREGION) { if(xx1) reg->x1=x; if(x>reg->x2) reg->x2=x; if(yy1) reg->y1=y; if(y>reg->y2) reg->y2=y; return TRUE; } return FALSE; } //find the region, point belongs to struct PaintRectRegion* findRegionForPoint(struct PaintRectRegion* firstRegion, int x , int y) { while(firstRegion) { if(insideOfRegion(firstRegion, x,y)) return firstRegion; firstRegion=firstRegion->next; } return firstRegion; } BOOL unitePaintRegions(struct PaintRectRegion* firstRegion) { struct PaintRectRegion* next; int ux1,ux2,uy1,uy2; BOOL haveUnited=FALSE; if(!firstRegion) return FALSE; if(!firstRegion->next) return FALSE; next=firstRegion->next; while(next) { if(!next->united) { //check if we need to unite with this one ux1=(firstRegion->x1 < next->x1)?firstRegion->x1:next->x1; ux2=(firstRegion->x2 > next->x2)?firstRegion->x2:next->x2; uy1=(firstRegion->y1 < next->y1)?firstRegion->y1:next->y1; uy2=(firstRegion->y2 > next->y2)?firstRegion->y2:next->y2; //if united size is smaller or same as separated size, we'll unite them if( ((firstRegion->x2-firstRegion->x1 +1)*(firstRegion->y2-firstRegion->y1+1) + (next->x2-next->x1 +1)*(next->y2-next->y1+1))> (ux2-ux1 +1)*(uy2-uy1+1) ) { // EPHYR_DBG("Uniting regions %d:%d-%d:%d and %d:%d-%d:%d", firstRegion->x1, firstRegion->y1, firstRegion->x2, firstRegion->y2, next->x1, next->y1, next->x2, next->y2); haveUnited=TRUE; next->united=TRUE; firstRegion->x1=ux1; firstRegion->x2=ux2; firstRegion->y1=uy1; firstRegion->y2=uy2; } } next=next->next; } next=firstRegion->next; while(next) { if(!next->united) { return haveUnited||unitePaintRegions(next); } next=next->next; } return haveUnited; } void remote_paint_rect(KdScreenInfo *screen, int sx, int sy, int dx, int dy, int width, int height) { // EphyrScrPriv *scrpriv = screen->driver; uint32_t size=width*height*XSERVERBPP; struct PaintRectRegion *regions=NULL; struct PaintRectRegion *currentRegion=NULL; struct PaintRectRegion *lastRegion=NULL; BOOL noRegions=FALSE; uint32_t reg_size; int reg_width, reg_height; int numOfRegs=0; int totalSizeOfRegions=0; int totalDirtySize=0; BOOL allUnited=FALSE; int centerx, centery; int xinc, yinc, firstquatx, lastquatx, firstqauty, lastquaty; int quarter; if(remoteVars.rootless) { remote_check_rootless_windows_for_updates(screen); } if(size) { int32_t dirtyx_max = 0; int32_t dirtyy_max = 0; int32_t dirtyx_min = 0; int32_t dirtyy_min = 0; char maxdiff = 0; char mindiff = 0; // EPHYR_DBG("---REPAINT %d:%d, %dx%d", dx, dy, width, height); dirtyx_max=dx-1; dirtyy_max=dy-1; dirtyx_min=dx+width; dirtyy_min=dy+height; /* * OK, here we are assuming that XSERVERBPP is 4. If not, we'll have * trouble but it should work faster like this */ pthread_mutex_lock(&remoteVars.mainimg_mutex); maxdiff=2; mindiff=-2; /* determine actual dimensions of the region which is updated */ // int dirty_pix=0; for(int32_t y=dy; y< dy+height;++y) { uint32_t ind=(y*remoteVars.main_img_width+dx)*XSERVERBPP; for(int32_t x=dx;x< dx+width; ++x) { BOOL pixIsDirty=FALSE; //CHECK R-COMPONENT int16_t diff=remoteVars.main_img[ind]-remoteVars.second_buffer[ind]; if(diff>maxdiff || diff< mindiff) { pixIsDirty=TRUE; } else { //CHECK G_COMPONENT diff=remoteVars.main_img[ind+1]-remoteVars.second_buffer[ind+1]; if(diff>maxdiff || diff< mindiff) { pixIsDirty=TRUE; } else { //CHECK B_COMPONENT diff=remoteVars.main_img[ind+2]-remoteVars.second_buffer[ind+2]; if(diff>maxdiff || diff< mindiff) { pixIsDirty=TRUE; } } } if(pixIsDirty) { // dirty_pix++; if(x>dirtyx_max) { dirtyx_max=x; } if(y>dirtyy_max) { dirtyy_max=y; } if(xnext=NULL; currentRegion->united=FALSE; currentRegion->x1=currentRegion->x2=x; currentRegion->y1=currentRegion->y2=y; if(lastRegion) lastRegion->next=currentRegion; if(!regions) regions=currentRegion; lastRegion=currentRegion; //EPHYR_DBG("Creating new region for pix %dx%d",x,y); } /* else { EPHYR_DBG("Dirty pix %dx%d from quarter belongs to existing region - %dx%d - %dx%d",x,y, currentRegion->x1, currentRegion->y1, currentRegion->x2, currentRegion->y2); }*/ } /* else { //EPHYR_DBG("Dirty pix %dx%d belongs to current region - %dx%d - %dx%d",x,y, currentRegion->x1, currentRegion->y1, currentRegion->x2, currentRegion->y2); }*/ } if(x==lastquatx) break; } if(y==lastquaty) break; } } } pthread_mutex_unlock(&remoteVars.mainimg_mutex); dx=sx=dirtyx_min; dy=sy=dirtyy_min; // remoteVars.sizeOfRects+=totalDirtySize; // if(size!=oldsize) // { // EPHYR_DBG("new update rect dimensions: %dx%d", width, height); // } /*#warning debug block currentRegion=regions; // int i=0; while(currentRegion) { // EPHYR_DBG("Region %d %d:%d %dx%d",i++, currentRegion->x1,currentRegion->y1, (currentRegion->x2-currentRegion->x1),(currentRegion->y2-currentRegion->y1)); totalSizeOfRegions+=(currentRegion->x2-currentRegion->x1 +1)*(currentRegion->y2-currentRegion->y1+1)*XSERVERBPP; numOfRegs++; currentRegion=currentRegion->next; } // EPHYR_DBG("---before union, regions: %d, total size %d", numOfRegs, totalSizeOfRegions); totalSizeOfRegions=0; numOfRegs=0; //end of debug block*/ while(!allUnited) { currentRegion=regions; allUnited=TRUE; while(currentRegion) { if(!currentRegion->united) { if(unitePaintRegions(currentRegion)) { allUnited=FALSE; } } currentRegion=currentRegion->next; } } currentRegion=regions; while(currentRegion) { if(!currentRegion->united) { totalSizeOfRegions+=(currentRegion->x2-currentRegion->x1 +1)*(currentRegion->y2-currentRegion->y1+1)*XSERVERBPP; } currentRegion=currentRegion->next; } currentRegion=regions; while(currentRegion) { if(!currentRegion->united) { reg_width=currentRegion->x2-currentRegion->x1 +1; reg_height=currentRegion->y2-currentRegion->y1+1; reg_size=reg_width*reg_height*XSERVERBPP; numOfRegs++; if(totalDirtySize-totalSizeOfRegions > 0) { add_frame(reg_width, reg_height, currentRegion->x1, currentRegion->y1, calculate_crc(reg_width, reg_height, currentRegion->x1,currentRegion->y1), reg_size,0); } // EPHYR_DBG("Region %d - %d:%d %dx%d", numOfRegs, currentRegion->x1, currentRegion->y1, reg_width, reg_height); } regions=currentRegion; currentRegion=currentRegion->next; free(regions); } // EPHYR_DBG("---after union, regions: %d, total size %d", numOfRegs, totalSizeOfRegions); /*if(totalDirtySize-totalSizeOfRegions > 0) { remoteVars.sizeOfRegions+=totalSizeOfRegions; EPHYR_DBG("rects %lu, regs %lu, transferred %d%%", remoteVars.sizeOfRects, remoteVars.sizeOfRegions, (int)((((double)remoteVars.sizeOfRegions) / ((double)remoteVars.sizeOfRects))*100)) ; //EPHYR_DBG("regions: %d dirty size=%d, total reg size=%d, diff=%d ",numOfRegs, totalDirtySize, totalSizeOfRegions, totalDirtySize-totalSizeOfRegions); }*/ if(totalDirtySize-totalSizeOfRegions <= 0 || noRegions) { /*if(totalDirtySize-totalSizeOfRegions < 0) { EPHYR_DBG("TOTAL SIZE of regions worse than dirty rect %d %d",totalDirtySize, totalSizeOfRegions); } remoteVars.sizeOfRegions+=totalDirtySize;*/ add_frame(width, height, dx, dy, calculate_crc(width, height,dx,dy), size,0); } } } uint32_t calculate_crc(uint32_t width, uint32_t height, int32_t dx, int32_t dy) { uint32_t crc=crc32(0L, Z_NULL, 0); pthread_mutex_lock(&remoteVars.mainimg_mutex); for(uint32_t y=0; y< height;++y) { crc=crc32(crc,remoteVars.main_img+ ((y+dy)*remoteVars.main_img_width + dx)*XSERVERBPP, width*XSERVERBPP); } pthread_mutex_unlock(&remoteVars.mainimg_mutex); return crc; } const char* remote_get_init_geometry(void) { return remoteVars.initGeometry; } void remote_set_init_geometry ( const char* geometry ) { if(strlen(geometry)>128) { EPHYR_DBG("INIT Geometry %s is too long, we'll ignore it", geometry); return; } strncpy(remoteVars.initGeometry,geometry,strlen(geometry)); } void remote_set_jpeg_quality(const char* quality) { sscanf(quality, "%d", &remoteVars.initialJpegQuality); if(remoteVars.initialJpegQuality<10 || remoteVars.initialJpegQuality > 90) { remoteVars.initialJpegQuality=JPG_QUALITY; } } void remote_set_display_name(const char* name) { int max_len=256; if(strlen(name)driver; //We should not install callback at first screen init, it was installed by selection_init //but we need to reinstall it by the next screen init. EPHYR_DBG("REMOTE SCREEN INIT!!!!!!!!!!!!!!!!!!"); if(remoteVars.selstruct.threadStarted) { EPHYR_DBG("SKIPPING Selection CALLBACK INSTALL"); // remoteVars.selstruct.callBackInstalled=FALSE; } else { EPHYR_DBG("REINSTALLING CALLBACKS"); install_selection_callbacks(); } EPHYR_DBG("host_screen=%p x=%d, y=%d, wxh=%dx%d, buffer_height=%d", screen, x, y, width, height, buffer_height); pthread_mutex_lock(&remoteVars.mainimg_mutex); if(remoteVars.main_img) { free(remoteVars.main_img); free(remoteVars.screen_regions); EPHYR_DBG("FREEING DBF"); free(remoteVars.second_buffer); EPHYR_DBG("DONE FREEING DBF"); } EPHYR_DBG("TRYING TO ALLOC MAIN_IMG %d", width*height*XSERVERBPP); remoteVars.main_img=malloc(width*height*XSERVERBPP); EPHYR_DBG("TRYING TO ALLOC DOUBLE BUF %d", width*height*XSERVERBPP); remoteVars.second_buffer=malloc(width*height*XSERVERBPP); remoteVars.reg_horiz=width/SCREEN_REG_WIDTH; if(width%SCREEN_REG_WIDTH) ++remoteVars.reg_horiz; remoteVars.reg_vert=height/SCREEN_REG_HEIGHT; if(height%SCREEN_REG_HEIGHT) ++remoteVars.reg_vert; EPHYR_DBG("Initializing %dx%d screen regions", remoteVars.reg_horiz, remoteVars.reg_vert); remoteVars.screen_regions=malloc(remoteVars.reg_horiz*remoteVars.reg_vert*sizeof(screen_region)); EPHYR_DBG("ALL INITIALIZED"); if(!remoteVars.main_img) { EPHYR_DBG("failed to init main buf"); exit(-1); } if(!remoteVars.second_buffer) { EPHYR_DBG("failed to init second buf"); exit(-1); } if(!remoteVars.second_buffer) { EPHYR_DBG("failed to init screen regions"); exit(-1); } memset(remoteVars.screen_regions, 0, remoteVars.reg_horiz*remoteVars.reg_vert*sizeof(screen_region)); memset(remoteVars.main_img,0, width*height*XSERVERBPP); memset(remoteVars.second_buffer,0, width*height*XSERVERBPP); remoteVars.main_img_width=width; remoteVars.main_img_height=height; scrpriv->win_width = width; scrpriv->win_height = height; scrpriv->win_x = x; scrpriv->win_y = y; scrpriv->img=remoteVars.main_img; remoteVars.ephyrScreen=screen; *bytes_per_line = width*XSERVERBPP; *bits_per_pixel = 32; pthread_mutex_unlock(&remoteVars.mainimg_mutex); return remoteVars.main_img; } void rebuild_caches(void) { EPHYR_DBG("CLIENT REQUESTED CLEARING ALL CACHES AND QUEUES"); pthread_mutex_lock(&remoteVars.sendqueue_mutex); remoteVars.cache_rebuilt=TRUE; pthread_cond_signal(&remoteVars.have_sendqueue_cond); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } void markDirtyRegions(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint8_t jpegQuality, uint32_t winId) { int first_horiz, last_horiz; int first_vert, last_vert; int i,j; // #warning for debugging // int marked=0; first_horiz=x/SCREEN_REG_WIDTH; first_vert=y/SCREEN_REG_HEIGHT; last_horiz=(x+width)/SCREEN_REG_WIDTH-1; last_vert=(y+height)/SCREEN_REG_HEIGHT-1; if((x+width)%SCREEN_REG_WIDTH) ++last_horiz; if((y+height)%SCREEN_REG_HEIGHT) ++last_vert; // EPHYR_DBG("marking regions at %d,%d for %dx%d, first %dx%d, last %dx%d", x,y,width, height, first_horiz, first_vert, last_horiz, last_vert); for(i=first_vert;i<=last_vert;++i) for(j=first_horiz;j<=last_horiz;++j) { // ++marked; if((remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality == 0)||(remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality>jpegQuality)) remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality=jpegQuality; remoteVars.screen_regions[i*remoteVars.reg_horiz+j].winId=winId; } // EPHYR_DBG("Marked %d regions",marked); } int getDirtyScreenRegion(void) { int i; int worst_reg=-1; for(i=0;iremoteVars.screen_regions[i].quality)) { worst_reg=i; } } } return worst_reg; } void send_dirty_region(int index) { //remoteVars.sendqueue_mutex is locked int width, height, x, y, winId; unsigned char compression; if(index==-1) return; x=(index%remoteVars.reg_horiz)*SCREEN_REG_WIDTH; y=(index/remoteVars.reg_horiz)*SCREEN_REG_HEIGHT; if(x+SCREEN_REG_WIDTH > remoteVars.main_img_width) width=remoteVars.main_img_width-x; else width=SCREEN_REG_WIDTH; if(y+SCREEN_REG_HEIGHT > remoteVars.main_img_height) height=remoteVars.main_img_height-y; else height=SCREEN_REG_HEIGHT; winId=remoteVars.screen_regions[index].winId; remoteVars.screen_regions[index].quality=0; pthread_mutex_unlock(&remoteVars.sendqueue_mutex); // EPHYR_DBG("SEND REGION UPDATE %d,%d %dx%d", x,y,width,height); compression=remoteVars.compression; remoteVars.compression=PNG; sendMainImageFromSendThread(width, height, x, y, winId); remoteVars.compression=compression; pthread_mutex_lock(&remoteVars.sendqueue_mutex); } //split packet to datagrams and send it int send_packet_as_datagrams(unsigned char* data, uint32_t length, uint8_t dgType) { /*split to datagrams, reserve header space for each dgram, set sequence number for each dgram ,set correct flag FOR EACH DGRAM and send all datagrams*/ uint16_t* seqNumber; uint16_t dgSeqNumber=0; uint16_t dgInPack; uint32_t sent_bytes=0; uint16_t dgram_length; unsigned char* dgram; uint32_t checksum; int writeRes; dgInPack=length/(UDPDGRAMSIZE-SRVDGRAMHEADERSIZE); if(length%(UDPDGRAMSIZE-SRVDGRAMHEADERSIZE)) ++dgInPack; // EPHYR_DBG("Sending DG packet of %d bytes",length); //setting sequence number switch(dgType) { case ServerFramePacket: seqNumber=&remoteVars.framePacketSeq; break; case ServerRepaintPacket: seqNumber=&remoteVars.repaintPacketSeq; break; } // EPHYR_DBG("Seq number: %d", *seqNumber); while(sent_bytes=CLIENTALIVE_TIMEOUT/1000) { EPHYR_DBG("no data from client since %d seconds, disconnecting...", (int)time_diff); disconnect_client(); return 0; } return CLIENTALIVE_TIMEOUT; } void sendServerAlive(void) { unsigned char buffer[56] = {0}; if(remoteVars.client_os==WEB || remoteVars.client_version<3) { //client doesn't support this event return; } if((time(NULL) - remoteVars.lastServerKeepAlive)>=SERVERALIVE_TIMEOUT) { *((uint32_t*)buffer)=SRVKEEPALIVE; //4B remote_write_socket(remoteVars.clientsock_tcp,buffer,56); // EPHYR_DBG("SENDING SRV KEEPALIVE!!!!"); } } void send_srv_disconnect(void) { unsigned char buffer[56] = {0}; _X_UNUSED int l; if(remoteVars.client_version<3) return; *((uint32_t*)buffer)=SRVDISCONNECT; //4B l=remote_write_socket(remoteVars.clientsock_tcp,buffer,56); } void clean_everything(void) { //sendqueue_mutex is locked clear_send_queue(); clear_frame_cache(0); freeCursors(); clear_output_selection(); delete_all_windows(); remoteVars.framePacketSeq=remoteVars.repaintPacketSeq=0; } void resend_frame(uint32_t crc) { unsigned char* data; unsigned char* packet; uint32_t size; struct cache_elem* frame=find_cache_element(crc); EPHYR_DBG("Client asks to resend frame from cache with crc %x",crc); if(remoteVars.send_frames_over_udp) return; pthread_mutex_lock(&remoteVars.sendqueue_mutex); if(! frame) { EPHYR_DBG("requested frame not found in cache"); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); return; } data=image_compress(frame->width, frame->height, frame->data, &(size), CACHEBPP, 0l); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); packet=malloc(size+8); *((uint32_t*)packet)=CACHEFRAME; *((uint32_t*)packet+1)=crc; memcpy(packet+8, data, size); free(data); send_packet_as_datagrams(packet,size+8,ServerFramePacket); } void close_client_sockets(void) { shutdown(remoteVars.clientsock_tcp, SHUT_RDWR); close(remoteVars.clientsock_tcp); close_udp_socket(); } void close_udp_socket(void) { if(remoteVars.send_frames_over_udp || remoteVars.sock_udp !=-1) { EPHYR_DBG("Closing UDP Socket"); shutdown(remoteVars.sock_udp, SHUT_RDWR); close(remoteVars.sock_udp); remoteVars.send_frames_over_udp=FALSE; remoteVars.sock_udp=-1; } } ssize_t remote_write_socket(int fd, const void *buf, size_t count) { remoteVars.lastServerKeepAlive=time(NULL); return write(fd,buf,count); } x2gokdrive-0.0.0.2/x2gokdriveremote.h0000644000000000000000000004704514500121262014275 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Author Oleksandr Shneyder * * Copyright © 2018-2023 phoca-GmbH * * * * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * Copyright © 2004 Nokia * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef X2GOKDRIVE_REMOTE_H #define X2GOKDRIVE_REMOTE_H #include #include #include #include #include "x2gokdrive.h" #include "kdrive.h" #include "cursorstr.h" #include "input.h" #include #include #include #include #include /* for memset */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //FEATURE_VERSION is not cooresponding to actual version of server //it used to tell server which features are supported by server //Changes 0 - 1: sending and recieving client and OS version //Changes 1 - 2: supporting extended selection and sending selection on demand //Changes 2 - 3: supporting web client, sending cursors in PNG format and know about KEEPALIVE event //Changes 3 - 4: extended clipboard support for web client //Changes 4 - 5: support for CACHEREBUILD event //Changes 5 - 6: support for rootless mode //Changes 6 - 7: Sending KEYRELEASE immediately after KEYPRESS to avoid the "key sticking" //Changes 7 - 8: support for UDP sockets #define FEATURE_VERSION 8 #define MAXMSGSIZE 1024*16 //max size for UDP dgram 1200 (experimental value for VPN, maybe we should determine the MTU size later) #define UDPDGRAMSIZE 1200 //UDP Server DGRAM Header - 4B checksum + 2B packet seq number + 2B amount of datagrams + 2B datagram seq number + 1B type #define SRVDGRAMHEADERSIZE (4+2+2+2+1) //port to listen by default #define DEFAULT_PORT 15000 #define ACCEPT_TIMEOUT 30000 //msec #define CLIENTALIVE_TIMEOUT 30000 //msec #define SERVERALIVE_TIMEOUT 10 //sec //if true, will save compressed jpg in file #define JPGDEBUG FALSE //it define how close should be two pages to search common regions (see find_best_match) #define MAX_MATCH_VAL 51 #define JPG_QUALITY 70 //always 4 #define XSERVERBPP 4 enum msg_type{FRAME,DELETED, CURSOR, DELETEDCURSOR, SELECTION, SERVERVERSION, DEMANDCLIENTSELECTION, REINIT, WINUPDATE, SRVKEEPALIVE, SRVDISCONNECT, CACHEFRAME, UDPOPEN, UDPFAILED}; enum AgentState{STARTING, RUNNING, RESUMING, SUSPENDING, SUSPENDED, TERMINATING, TERMINATED}; enum Compressions{JPEG,PNG}; enum SelectionType{PRIMARY,CLIPBOARD}; enum SelectionMime{STRING,UTF_STRING,PIXMAP}; enum ClipboardMode{CLIP_NONE,CLIP_CLIENT,CLIP_SERVER,CLIP_BOTH}; enum OS_VERSION{OS_LINUX, OS_WINDOWS, OS_DARWIN, WEB}; enum WinUpdateType{UPD_NEW,UPD_CHANGED,UPD_DELETED}; enum WinType{WINDOW_TYPE_DESKTOP, WINDOW_TYPE_DOCK, WINDOW_TYPE_TOOLBAR, WINDOW_TYPE_MENU, WINDOW_TYPE_UTILITY, WINDOW_TYPE_SPLASH, WINDOW_TYPE_DIALOG, WINDOW_TYPE_DROPDOWN_MENU, WINDOW_TYPE_POPUP_MENU, WINDOW_TYPE_TOOLTIP, WINDOW_TYPE_NOTIFICATION, WINDOW_TYPE_COMBO, WINDOW_TYPE_DND, WINDOW_TYPE_NORMAL}; //new state requested by WINCHANGE event enum WinState{WIN_UNCHANGED, WIN_DELETED, WIN_ICONIFIED}; //UDP datagrams types enum ServerDgramTypes{ ServerFramePacket, //dgram belongs to packet representing frame ServerRepaintPacket, // dgram belongs to packet with screen repaint and the loss can be ignored }; //Size of 1 window update (new or changed window) = 4xwinId + type of update + 7 coordinates + visibility + type of window + size of name buffer + icon_size #define WINUPDSIZE 4*sizeof(uint32_t) + sizeof(int8_t) + 7*sizeof(int16_t) + sizeof(int8_t) + sizeof(int8_t) + sizeof(int16_t) + sizeof(int32_t) //Size of 1 window update (deleted window) = winId + type of update #define WINUPDDELSIZE sizeof(uint32_t) + sizeof(int8_t) #define DEFAULT_COMPRESSION JPEG // could be 3 or 4 // 3 saves some memory because not keeping A-value, which is always 0 anyway. // 4 doesn't need to do transformation between XImage and internal data. // I think we should always use 3 #define CACHEBPP 3 #define CACHEMAXELEMENTS 50 //store max 50 elements in cache //Events #define KEYPRESS 2 #define KEYRELEASE 3 #define MOUSEPRESS 4 #define MOUSERELEASE 5 #define MOUSEMOTION 6 #define GEOMETRY 7 #define UPDATE 8 #define SELECTIONEVENT 9 #define CLIENTVERSION 10 #define DEMANDSELECTION 11 #define KEEPALIVE 12 #define CACHEREBUILD 13 #define WINCHANGE 14 //client is going to disconnect #define DISCONNECTCLIENT 15 //ask to resend particular frame #define RESENDFRAME 16 //client is requesting UDP port for frames #define OPENUDP 17 #define EVLENGTH 41 //width of screen region #define SCREEN_REG_WIDTH 40 //height of screen region #define SCREEN_REG_HEIGHT 40 //the distance to determinate if the point belongs to region #define MAXDISTANCETOREGION 20 //regions to split the paint rectangle struct PaintRectRegion { int x1, x2, y1, y2; struct PaintRectRegion* next; BOOL united; }; //represents the screen regions for updates typedef struct { uint8_t quality; uint32_t winId; } screen_region; typedef struct { int32_t x; int32_t y; } point_t; typedef struct { int32_t width; int32_t height; }rect_size; typedef struct { point_t lt_corner; rect_size size; }rectangle; struct cache_elem; // represents frame regions for frames with multiply regions struct frame_region { uint8_t* compressed_data; uint32_t size; rectangle rect; uint32_t source_crc; point_t source_coordinates; }; //elemnet of the dgram list struct dgram_element { unsigned char* data; uint16_t length; struct dgram_element* next; }; //we can find out cursor type by analyzing size of data. //size = 0 - cursor is already sent to client //size = width*height*4 - RGBA cursor //size = width*height/8*2 - Core cursor struct cursorFrame { uint32_t size; char* data; uint16_t width; uint16_t height; uint16_t xhot; uint16_t yhot; uint8_t forR, forG, forB; uint8_t backR, backG, backB; struct cursorFrame* next; uint32_t serialNumber; }; struct sentCursor { uint32_t serialNumber; struct sentCursor* next; }; //we need to delete cursor on client when XServer deleting cursor struct deletedCursor { struct deletedCursor* next; uint32_t serialNumber; }; //this structure represent elements in cash struct cache_elem { struct cache_elem* next; struct cache_elem* prev; uint32_t crc; uint8_t* data; uint32_t size; uint32_t width; uint32_t height; uint32_t compressed_size; uint32_t rval, gval, bval; struct cache_elem* source; //element on which one of regions is based. It should be cleared after sending struct frame_region regions[9]; //this should be inited before add client to queue and deleted after sending BOOL sent; //if the element already sent to client uint32_t busy; //if the element is busy (for example in sending queue and can't be deleted) //or if the element referenced by another element which not sent yet. Every time the value will be incremented // when referenced element is ent, this value will be decremented }; //this structure represents a deleted cash elements. It need to be sent to client to release deleted elements struct deleted_elem { struct deleted_elem* next; uint32_t crc; }; struct sendqueue_element { struct cache_elem* frame; int32_t x, y; uint32_t width, height; uint32_t crc; uint32_t winId; struct sendqueue_element* next; }; //chunk of data with output selection struct OutputChunk { unsigned char* data; //data uint32_t size; //size of chunk in B enum SelectionMime mimeData; //UTF_STRING or PIXMAP (text or image) uint32_t compressed_size; // if chunk is compressed the size of compressed data, otherwise 0 BOOL firstChunk; // if it's a first chunk in selection BOOL lastChunk; // if it's a last chunk in selection enum SelectionType selection; //PRIMARY or CLIPBOARD uint32_t totalSize; //the total size of the selection data struct OutputChunk* next; //next chunk in the queue }; //input selection struct InputBuffer { unsigned char* data; //data uint32_t size; //total size of selection uint32_t bytesReady; //how many bytes already read uint32_t currentChunkSize; //size of chunk we reading now; uint32_t currentChunkBytesReady; //how many bytes of current chunk are ready; uint32_t currentChunkCompressedSize; //if chunk is compressed, size of compressed data unsigned char* currentChunkCompressedData; //if chunk is compressed, compressed dat will be stored here enum SelectionMime mimeData; //UTF_STRING or PIXMAP xcb_timestamp_t timestamp; //ts when we own selection BOOL owner; //if we are the owners of selection enum {NOTIFIED, REQUESTED, COMPLETED} state; }; //requests which processing should be delayed till we get data from client struct DelayedRequest { xcb_selection_request_event_t *request; // request from X-client xcb_selection_notify_event_t* event; // event which we are going to send to X-client struct DelayedRequest* next; }; //save running INCR transactions in this struct struct IncrTransaction { xcb_window_t requestor; xcb_atom_t property; xcb_atom_t target; char* data; uint32_t size; uint32_t sentBytes; xcb_timestamp_t timestamp; struct IncrTransaction* next; }; struct SelectionStructure { unsigned long selThreadId; //id of selection thread enum ClipboardMode selectionMode; //CLIP_NONE, CLIP_CLIENT, CLIP_SERVER, CLIP_BOTH //output selection members uint32_t incrementalSize; //the total size of INCR selection we are currently reading uint32_t incrementalSizeRead; //bytes already read xcb_window_t clipWinId; // win id of clipboard window xcb_connection_t* xcbConnection; //XCB connection BOOL threadStarted; //if selection thread already started BOOL clientSupportsExetndedSelection; //if client supports extended selection - sending selection in several chunks for big size data BOOL clientSupportsOnDemandSelection; //if client supports selection on demand - sending data only if client requests it xcb_atom_t incrAtom; //mime type of the incr selection we are reading xcb_atom_t currentSelection; //selection we are currently reading struct OutputChunk* firstOutputChunk; //the first and last elements of the struct OutputChunk* lastOutputChunk; //queue of selection chunks xcb_atom_t best_atom[2]; //the best mime type for selection to request on demand sel request from client BOOL requestSelection[2]; //selection thread will set it to TRUE if the selection need to be requested //Input selection members int readingInputBuffer; //which selection are reading input buffer at the moments: PRIMARY, CLIPBOARD or -1 if none int currentInputBuffer; //which selection represents input buffer at the moments: PRIMARY or CLIPBOARD struct InputBuffer inSelection[2]; //PRIMARY an CLIPBOARD selection buffers //list of delayed requests struct DelayedRequest* firstDelayedRequest; struct DelayedRequest* lastDelayedRequest; //list of INCR transactions struct IncrTransaction* firstIncrTransaction; struct IncrTransaction* lastIncrTransaction; pthread_mutex_t inMutex; //mutex for synchronization of incoming selection }; struct remoteWindow { enum {UNCHANGED, CHANGED, NEW, WDEL}state; int16_t x,y; uint16_t w,h,bw, minw, minh; int8_t visibility; int8_t hasFocus; uint8_t winType; char* name; unsigned char* icon_png; uint32_t icon_size; BOOL foundInWinTree; uint32_t id; uint32_t parentId, nextSibId, transWinId; struct remoteWindow *next; WindowPtr ptr, parent, nextSib; }; struct _remoteHostVars { unsigned char compression; OsTimerPtr checkConnectionTimer, checkKeepAliveTimer; time_t lastServerKeepAlive; int agentState; BOOL nxagentMode; char optionsFile[256]; char stateFile[256]; char acceptAddr[256]; char cookie[33]; char displayName[256]; char initGeometry[128]; int listenPort; int udpPort; int jpegQuality, initialJpegQuality; uint32_t framenum; uint32_t framenum_sent; uint32_t eventnum; uint32_t eventbytes; char eventBuffer[EVLENGTH*100]; uint32_t evBufferOffset; unsigned long send_thread_id; uint16_t framePacketSeq; uint16_t repaintPacketSeq; //client information enum OS_VERSION client_os; uint16_t client_version; BOOL server_version_sent; BOOL send_frames_over_udp; //for control uint32_t cache_elements; uint32_t cache_size; uint32_t con_start_time; uint32_t data_sent; uint32_t data_copy; unsigned char* main_img; unsigned char* second_buffer; KdScreenInfo* ephyrScreen; uint32_t main_img_height, main_img_width; /*#warning for debug purposes uint64_t sizeOfRects; uint64_t sizeOfRegions;*/ int clientsock_tcp, serversock_tcp, sock_udp; BOOL rootless; //array of screen regions screen_region* screen_regions; int reg_horiz, reg_vert; struct cache_elem* first_cache_element; struct cache_elem* last_cache_element; struct sendqueue_element* first_sendqueue_element; struct sendqueue_element* last_sendqueue_element; struct deleted_elem* first_deleted_elements; struct deleted_elem* last_deleted_elements; uint32_t deleted_list_size; struct deletedCursor* first_deleted_cursor; struct deletedCursor* last_deleted_cursor; uint32_t deletedcursor_list_size; int maxfr; struct cursorFrame* firstCursor; struct cursorFrame* lastCursor; struct sentCursor* sentCursorsHead; struct sentCursor* sentCursorsTail; struct remoteWindow* windowList; BOOL windowsUpdated; pthread_mutex_t sendqueue_mutex; pthread_mutex_t mainimg_mutex; pthread_cond_t have_sendqueue_cond; socklen_t tcp_addrlen, udp_addrlen; struct sockaddr_in tcp_address, udp_address; BOOL client_connected; BOOL client_initialized; //last time when client sent sync packet time_t last_client_keepalive_time; //if all cache are cleared and notofictaion to client should be send BOOL cache_rebuilt; struct SelectionStructure selstruct; } ; int send_selection_chunk(int sel, unsigned char* data, uint32_t length, uint32_t format, BOOL first, BOOL last, uint32_t compressed, uint32_t total_sz); int send_output_selection(struct OutputChunk* chunk); int send_packet_as_datagrams(unsigned char* data, uint32_t length, uint8_t dgType); void set_client_version(uint16_t ver, uint16_t os); void readInputSelectionBuffer(char* buff); void readInputSelectionHeader(char* buff); #if XORG_VERSION_CURRENT < 11900000 void pollEvents(void); #endif /* XORG_VERSION_CURRENT */ void clear_frame_cache(uint32_t max_elements); void delete_all_windows(void); uint32_t calculate_crc(uint32_t width, uint32_t height, int32_t dx, int32_t dy); void readOptionsFromFile(void); unsigned int checkSocketConnection(OsTimerPtr timer, CARD32 time, void* args); void restartTimerOnInit(void); void open_socket(void); void open_udp_socket(void); void close_server_socket(void); void close_client_sockets(void); void close_udp_socket(void); void setAgentState(int state); void terminateServer(int exitStatus); void unpack_current_chunk_to_buffer(struct InputBuffer* selbuff); unsigned char* image_compress(uint32_t image_width, uint32_t image_height, unsigned char* RGBA_buffer, uint32_t* compressed_size, int bpp, char* fname); unsigned char* jpeg_compress(int quality, uint32_t image_width, uint32_t image_height, unsigned char* RGBA_buffer, uint32_t* jpeg_size, int bpp, char* fname); unsigned char* png_compress(uint32_t image_width, uint32_t image_height, unsigned char* RGBA_buffer, uint32_t* png_size, BOOL compress_cursor); void clientReadNotify(int fd, int ready, void *data); void serverAcceptNotify(int fd, int ready, void *data); void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t crc, uint32_t size, uint32_t winId); void clear_output_selection(void); void disconnect_client(void); void remote_handle_signal(int signum); void remote_sendCursor(CursorPtr cursor); void remote_removeCursor(uint32_t serialNumber); void remote_send_main_image(void); void remote_sendVersion(void); int remote_init(void); void remote_selection_init(void); void remote_set_display_name(const char* name); void *remote_screen_init(KdScreenInfo *screen, int x, int y, int width, int height, int buffer_height, int *bytes_per_line, int *bits_per_pixel); void remote_paint_rect(KdScreenInfo *screen, int sx, int sy, int dx, int dy, int width, int height); void request_selection_from_client(enum SelectionType selection); void rebuild_caches(void); void remote_set_rootless(void); void remote_set_init_geometry(const char* geometry); void remote_set_jpeg_quality(const char* quality); const char* remote_get_init_geometry(void); void remote_check_windowstree(WindowPtr root); void remote_check_window(WindowPtr win); BOOL remote_process_client_event(char* buff, int length); struct remoteWindow* remote_find_window(WindowPtr win); WindowPtr remote_find_window_on_screen(WindowPtr win, WindowPtr root); WindowPtr remote_find_window_on_screen_by_id(uint32_t winId, WindowPtr root); void remote_process_window_updates(void); void send_reinit_notification(void); void client_win_change(char* buff); void client_win_close(uint32_t winId); void client_win_iconify(uint32_t winId); void remote_check_rootless_windows_for_updates(KdScreenInfo *screen); void markDirtyRegions(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint8_t jpegQuality, uint32_t winId); int getDirtyScreenRegion(void); void send_dirty_region(int index); unsigned int checkClientAlive(OsTimerPtr timer, CARD32 time_card, void* args); void send_srv_disconnect(void); BOOL insideOfRegion(struct PaintRectRegion* reg, int x , int y); struct PaintRectRegion* findRegionForPoint(struct PaintRectRegion* firstRegion, int x , int y); BOOL unitePaintRegions(struct PaintRectRegion* firstRegion); //perform cleanup of all caches and queues when disconnecting or performing reinitialization void clean_everything(void); void resend_frame(uint32_t crc); ssize_t remote_write_socket(int fd, const void *buf, size_t count); void sendServerAlive(void); #endif /* X2GOKDRIVE_REMOTE_H */ x2gokdrive-0.0.0.2/x2gokdriveselection.c0000644000000000000000000014555114500121262014763 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Author Oleksandr Shneyder * * Copyright © 2018-2023 phoca-GmbH * * * * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * Copyright © 2004 Nokia * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #if XORG_VERSION_CURRENT < 11999901 #include #endif // XORG_VERSION_CURRENT #endif #include "x2gokdriveselection.h" #include "x2gokdrivelog.h" #ifdef EPHYR_WANT_DEBUG extern unsigned long long int debug_sendThreadId; extern unsigned long long int debug_selectThreadId; #endif /* EPHYR_WANT_DEBUG */ #define SELECTION_DELAY 30000 //timeout for selection operation #define INCR_SIZE 256*1024 //size of part for incr selection incr selection static struct _remoteHostVars *remoteVars = NULL; //internal atoms static xcb_atom_t ATOM_ATOM; static xcb_atom_t ATOM_CLIPBOARD; static xcb_atom_t ATOM_TARGETS; static xcb_atom_t ATOM_TIMESTAMP; static xcb_atom_t ATOM_INCR; static xcb_atom_t ATOM_XT_SELECTION; static xcb_atom_t ATOM_QT_SELECTION; //text atoms static xcb_atom_t ATOM_UTF8_STRING; static xcb_atom_t ATOM_TEXT_PLAIN_UTF; static xcb_atom_t ATOM_STRING; static xcb_atom_t ATOM_TEXT; static xcb_atom_t ATOM_TEXT_PLAIN; //image atoms static xcb_atom_t ATOM_IMAGE_PNG; static xcb_atom_t ATOM_IMAGE_XPM; static xcb_atom_t ATOM_IMAGE_JPG; static xcb_atom_t ATOM_IMAGE_JPEG; static xcb_atom_t ATOM_PIXMAP; static xcb_atom_t ATOM_IMAGE_BMP; uint32_t max_chunk(void) { if(remoteVars->selstruct.clientSupportsExetndedSelection) return 1024*100/4; //100KB else return 10*1024*1024/4; //10MB } void init_atoms(void) { //init intern atoms ATOM_ATOM=string_to_atom("ATOM"); ATOM_CLIPBOARD=string_to_atom("CLIPBOARD"); ATOM_TARGETS=string_to_atom("TARGETS"); ATOM_TIMESTAMP=string_to_atom("TIMESTAMP"); ATOM_INCR=string_to_atom("INCR"); ATOM_XT_SELECTION=string_to_atom("_XT_SELECTION_0"); ATOM_QT_SELECTION=string_to_atom("_QT_SELECTION"); ATOM_UTF8_STRING=string_to_atom("UTF8_STRING"); ATOM_TEXT_PLAIN_UTF=string_to_atom("text/plain;charset=utf-8"); ATOM_STRING=string_to_atom("STRING"); ATOM_TEXT=string_to_atom("TEXT"); ATOM_TEXT_PLAIN=string_to_atom("text/plain"); ATOM_IMAGE_PNG=string_to_atom("image/png"); ATOM_IMAGE_XPM=string_to_atom("image/xpm"); ATOM_IMAGE_JPG=string_to_atom("image/jpg"); ATOM_IMAGE_JPEG=string_to_atom("image/jpeg"); ATOM_PIXMAP=string_to_atom("PIXMAP"); ATOM_IMAGE_BMP=string_to_atom("image/bmp"); } struct DelayedRequest* discard_delayed_request(struct DelayedRequest* d, struct DelayedRequest* prev) { //this function finalizing delayed request and destroys XCB request and event //removing the request from list and returning the pointer of the next element for iteration struct DelayedRequest* next=d->next; xcb_send_event(remoteVars->selstruct.xcbConnection, FALSE, d->request->requestor, XCB_EVENT_MASK_NO_EVENT, (char*)d->event); xcb_flush(remoteVars->selstruct.xcbConnection); free(d->event); free((xcb_generic_event_t *)(d->request)); //remove element from list if(prev) prev->next=next; if(d==remoteVars->selstruct.firstDelayedRequest) remoteVars->selstruct.firstDelayedRequest=next; if(d==remoteVars->selstruct.lastDelayedRequest) remoteVars->selstruct.lastDelayedRequest=prev; free(d); return next; } void destroy_incr_transaction(struct IncrTransaction* tr, struct IncrTransaction* prev) { //destroy incr transaction struct IncrTransaction* next=tr->next; const uint32_t mask[] = { XCB_EVENT_MASK_NO_EVENT }; //don't resive property notify events for this window anymore xcb_change_window_attributes(remoteVars->selstruct.xcbConnection, tr->requestor, XCB_CW_EVENT_MASK, mask); xcb_flush(remoteVars->selstruct.xcbConnection); //free data free(tr->data); //remove element from list if(prev) prev->next=next; if(tr==remoteVars->selstruct.firstIncrTransaction) remoteVars->selstruct.firstIncrTransaction=next; if(tr==remoteVars->selstruct.lastIncrTransaction) remoteVars->selstruct.lastIncrTransaction=prev; free(tr); } BOOL check_req_sanity(xcb_selection_request_event_t* req) { //check if the requested mime can be delivered //inmutex should be locked from calling function enum SelectionType sel=selection_from_atom(req->selection); if(remoteVars->selstruct.inSelection[sel].mimeData==UTF_STRING) { //if it's one of supported text formats send without convertion if(is_string_atom(req->target)) { return TRUE; } else { EPHYR_DBG("Unsupported property requested %d", req->target); return FALSE; } } else { if(!is_image_atom(req->target)) { EPHYR_DBG("Unsupported property requested %d", req->target); return FALSE; } return TRUE; } } void remove_obsolete_incr_transactions( BOOL checkTs) { //remove_obsolete_incr_transactions //if checkTS true, check timestamp and destroy only if ts exceed delay struct DelayedRequest* prev=NULL; struct DelayedRequest* d=remoteVars->selstruct.firstDelayedRequest; while(d) { if(!checkTs || (currentTime.milliseconds > (d->request->time + SELECTION_DELAY))) { d=discard_delayed_request(d, prev); } else { prev=d; d=d->next; } } } void process_delayed_requests(void) { //process delayed requests enum SelectionType selection; struct DelayedRequest* prev=NULL; struct DelayedRequest* d=remoteVars->selstruct.firstDelayedRequest; while(d) { selection = selection_from_atom( d->request->selection); if(currentTime.milliseconds > (d->request->time + SELECTION_DELAY)) { EPHYR_DBG("timeout selection: %d",selection); d=discard_delayed_request(d, prev); continue; } pthread_mutex_lock(&remoteVars->selstruct.inMutex); if(!remoteVars->selstruct.inSelection[selection].owner) { pthread_mutex_unlock(&remoteVars->selstruct.inMutex); EPHYR_DBG("we are not owner of requested selection %d",selection); //we are not anymore owners of this selection d=discard_delayed_request(d, prev); continue; } if(remoteVars->selstruct.inSelection[selection].timestamp > d->request->time ) { pthread_mutex_unlock(&remoteVars->selstruct.inMutex); EPHYR_DBG("selection request for %d is too old", selection); //requested selection is older than the current one d=discard_delayed_request(d, prev); continue; } if(!check_req_sanity(d->request)) { pthread_mutex_unlock(&remoteVars->selstruct.inMutex); // EPHYR_DBG("can't convert selection %d to requested myme type %d",selection, d->request->property); //our selection don't support requested mime type d=discard_delayed_request(d, prev); continue; } if(remoteVars->selstruct.inSelection[selection].state != COMPLETED) { pthread_mutex_unlock(&remoteVars->selstruct.inMutex); //we don't have the data yet prev=d; d=d->next; continue; } //data is ready, send data to requester and discard the request //inMutex need be locked for sending data d->event->property=send_data(d->request); pthread_mutex_unlock(&remoteVars->selstruct.inMutex); d=discard_delayed_request(d, prev); } } void process_incr_transaction_property(xcb_property_notify_event_t * pn) { //process incr transactions struct IncrTransaction* prev=NULL; struct IncrTransaction* tr=remoteVars->selstruct.firstIncrTransaction; uint32_t left, sendingBytes; while(tr) { if((tr->requestor == pn->window) && (tr->property == pn->atom ) && ( pn->state == XCB_PROPERTY_DELETE) ) { //requestor ready for the new portion of data left=tr->size-tr->sentBytes; if(!left) { // EPHYR_DBG("all INCR data sent to %d",tr->requestor); //all data sent, sending NULL data and destroying transaction xcb_change_property(remoteVars->selstruct.xcbConnection, XCB_PROP_MODE_REPLACE, tr->requestor, tr->property, tr->target, 8, 0, NULL); xcb_flush(remoteVars->selstruct.xcbConnection); destroy_incr_transaction(tr, prev); return; } sendingBytes=(INCR_SIZE< left)?INCR_SIZE:left; xcb_change_property(remoteVars->selstruct.xcbConnection, XCB_PROP_MODE_REPLACE, tr->requestor, tr->property, tr->target, 8, sendingBytes, tr->data + tr->sentBytes); xcb_flush(remoteVars->selstruct.xcbConnection); tr->sentBytes+=sendingBytes; tr->timestamp=currentTime.milliseconds; return; } prev=tr; tr=tr->next; } //notify event doesn't belong to any of started incr transactions or it's notification for new property return; } int own_selection(enum SelectionType selection) { //owning selection //remoteVars.selstruct.inMutex locked in the calling function xcb_atom_t sel=XCB_ATOM_PRIMARY; if(remoteVars->selstruct.selectionMode == CLIP_NONE || remoteVars->selstruct.selectionMode == CLIP_SERVER) { EPHYR_DBG("Client selection is disabled"); return 0; } if(selection!=PRIMARY) { sel=ATOM_CLIPBOARD; } xcb_set_selection_owner(remoteVars->selstruct.xcbConnection, remoteVars->selstruct.clipWinId, sel, XCB_CURRENT_TIME); xcb_flush(remoteVars->selstruct.xcbConnection); remoteVars->selstruct.inSelection[selection].owner=TRUE; remoteVars->selstruct.inSelection[selection].timestamp=currentTime.milliseconds; // EPHYR_DBG("own selection %d", currentTime.milliseconds); return 0; } void selection_init(struct _remoteHostVars *obj) { remoteVars=obj; return; } xcb_atom_t string_to_atom(const char* name) { //get atom for the name, return 0 if not found xcb_intern_atom_cookie_t cookie; xcb_intern_atom_reply_t *reply; xcb_atom_t a=0; cookie = xcb_intern_atom(remoteVars->selstruct.xcbConnection, 0, strlen(name), name); if ((reply = xcb_intern_atom_reply(remoteVars->selstruct.xcbConnection, cookie, NULL))) { a=reply->atom; free(reply); } EPHYR_DBG("The %s atom has ID %u", name, a); return a; } char *atom_to_string(xcb_atom_t xatom) { //get name for atom, don't forget to free return value char* name; xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(remoteVars->selstruct.xcbConnection, xatom); xcb_get_atom_name_reply_t *reply=xcb_get_atom_name_reply(remoteVars->selstruct.xcbConnection, cookie, NULL); if(!reply) return NULL; if(!reply->name_len) { free(reply); return NULL; } name=malloc( xcb_get_atom_name_name_length(reply)+1); strncpy(name, xcb_get_atom_name_name(reply),xcb_get_atom_name_name_length(reply)); name [xcb_get_atom_name_name_length(reply)]='\0'; free(reply); return name; } static xcb_atom_t target_has_atom(xcb_atom_t* list, size_t size, xcb_atom_t a) { //check if the atom which represents "name" is in the list of supported mime types size_t i = 0; for (i = 0;i < size;i++) { if (list[i]==a) return a; } return 0; } int is_string_atom( xcb_atom_t at) { //check if selection data is string/text if((at==ATOM_UTF8_STRING) || (at==ATOM_TEXT_PLAIN_UTF) || (at==ATOM_STRING) || (at==ATOM_TEXT) || (at==ATOM_TEXT_PLAIN)) return 1; return 0; } int is_image_atom( xcb_atom_t at) { //check if selection data is image if( at == ATOM_IMAGE_PNG || at == ATOM_IMAGE_XPM || at == ATOM_IMAGE_JPEG || at == ATOM_IMAGE_JPG || at == ATOM_PIXMAP || at == ATOM_IMAGE_BMP) return 1; return 0; } static xcb_atom_t best_atom_from_target(xcb_atom_t* list, size_t size) { //here we chose the best of supported formats for selection xcb_atom_t a; //selecting utf formats first if((a=target_has_atom(list, size, ATOM_UTF8_STRING))) { // EPHYR_DBG("selecting mime type UTF8_STRING"); return a; } if((a=target_has_atom(list, size, ATOM_TEXT_PLAIN_UTF))) { // EPHYR_DBG("selecting mime type text/plain;charset=utf-8"); return a; } if((a=target_has_atom(list, size, ATOM_STRING))) { // EPHYR_DBG( "selecting mime type STRING"); return a; } if((a=target_has_atom(list, size, ATOM_TEXT))) { // EPHYR_DBG( "selecting mime type TEXT"); return a; } if((a=target_has_atom(list, size, ATOM_TEXT_PLAIN))) { // EPHYR_DBG( "selecting mime type text/plain"); return a; } //selecting lossless formats first if((a=target_has_atom(list, size, ATOM_IMAGE_PNG))) { // EPHYR_DBG( "selecting mime type image/png"); return a; } if((a=target_has_atom(list, size, ATOM_IMAGE_XPM))) { // EPHYR_DBG( "selecting mime type image/xpm"); return a; } if((a=target_has_atom(list, size, ATOM_PIXMAP))) { // EPHYR_DBG( "selecting mime type PIXMAP"); return a; } if((a=target_has_atom(list, size, ATOM_IMAGE_BMP))) { // EPHYR_DBG( "selecting mime type image/bmp"); return a; } if((a=target_has_atom(list, size, ATOM_IMAGE_JPG))) { // EPHYR_DBG( "selecting mime type image/jpg"); return a; } if((a=target_has_atom(list, size, ATOM_IMAGE_JPEG))) { // EPHYR_DBG( "selecting mime type image/jpeg"); return a; } return 0; } void request_selection_data( xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t) { //execute convert selection for primary or clipboard to get mimetypes or data (depends on target atom) if(!t) t=XCB_CURRENT_TIME; if(property) { xcb_delete_property(remoteVars->selstruct.xcbConnection,remoteVars->selstruct.clipWinId,property); } xcb_convert_selection(remoteVars->selstruct.xcbConnection,remoteVars->selstruct.clipWinId,selection, target, property, t); xcb_flush(remoteVars->selstruct.xcbConnection); } void read_selection_property(xcb_atom_t selection, xcb_atom_t property) { xcb_atom_t data_atom; unsigned int bytes_left, bytes_read=0; xcb_get_property_cookie_t cookie; xcb_get_property_reply_t *reply; struct OutputChunk* chunk; unsigned char* compressed_data; uint32_t compressed_size; //request property which represents value of selection (data or mime types) //get max 100K of data, we don't need to send more than that over network for perfomance reasons cookie= xcb_get_property(remoteVars->selstruct.xcbConnection,FALSE, remoteVars->selstruct.clipWinId, property, XCB_GET_PROPERTY_TYPE_ANY, 0, max_chunk()); reply=xcb_get_property_reply(remoteVars->selstruct.xcbConnection, cookie, NULL); if(!reply) { // EPHYR_DBG( "NULL reply"); } else { if(reply->type==XCB_NONE) { // EPHYR_DBG( "NONE reply"); } else { //here we have type of data /* stype=atom_name(reply->type); sprop=atom_name(property); EPHYR_DBG( "Property %s type %s, format %d, length %d", sprop, stype, reply->format, reply->length); if(stype) free(stype); if(sprop) free(sprop); */ //need to read property incrementally if(reply->type == ATOM_INCR) { unsigned int sz=*((unsigned int*) xcb_get_property_value(reply)); // EPHYR_DBG( "have incr property size: %d", sz); remoteVars->selstruct.incrAtom=property; remoteVars->selstruct.incrementalSize=sz; remoteVars->selstruct.incrementalSizeRead=0; //deleting property should tell the selection owner that we are ready for incremental reading of data xcb_delete_property(remoteVars->selstruct.xcbConnection,remoteVars->selstruct.clipWinId, property); xcb_flush(remoteVars->selstruct.xcbConnection); free(reply); return; } //we have supported mime types in reply if(reply->type == ATOM_ATOM) { if(reply->format!=32) { EPHYR_DBG( "wrong format for TARGETS"); } else { // EPHYR_DBG( "target supports %lu mime types",xcb_get_property_value_length(reply)/sizeof(xcb_atom_t)); /* #warning debug tg=(xcb_atom_t*) xcb_get_property_value(reply); for(int i=0;iselstruct.xcbConnection, remoteVars->selstruct.clipWinId, property); xcb_flush(remoteVars->selstruct.xcbConnection); if(data_atom) { if(remoteVars->client_os == OS_WINDOWS && selection_from_atom(selection) == PRIMARY) { // EPHYR_DBG("client doesn't support PRIMARY selection"); } else { if(remoteVars->selstruct.clientSupportsOnDemandSelection) { //don't ask for data yet, only send notification that we have a selection to client // EPHYR_DBG("client supports onDemand selection, notify client"); send_notify_to_client(selection, data_atom); //save the data atom for possible data demand remoteVars->selstruct.best_atom[selection_from_atom(selection)]=data_atom; } else { //request selection data // EPHYR_DBG("client doesn't support onDemand selection, requesting data"); request_selection_data( selection, data_atom, data_atom, 0); } } } else { EPHYR_DBG( "there are no supported mime types in the target"); } } } else { //here we have selection as string or image if(is_image_atom( reply->type) || is_string_atom( reply->type)) { //read property data in loop in the chunks with size (100KB) do { bytes_left=reply->bytes_after; //now we can access property data /*FILE* cp=fopen("/tmp/clip", "a"); fwrite(xcb_get_property_value(reply),1, xcb_get_property_value_length(reply),cp); fclose(cp);*/ chunk=malloc(sizeof(struct OutputChunk)); memset((void*)chunk,0,sizeof(struct OutputChunk)); if(xcb_get_property_value_length(reply)) { chunk->size=xcb_get_property_value_length(reply); chunk->data=(unsigned char*)malloc(chunk->size); memcpy(chunk->data, xcb_get_property_value(reply),chunk->size); } chunk->compressed_size=0; if(is_string_atom(property)) { chunk->mimeData=UTF_STRING; //for text chunks > 1K using zlib compression if client supports it if(remoteVars->selstruct.clientSupportsExetndedSelection && chunk->size > 1024 && remoteVars->client_os != WEB ) { compressed_data=zcompress(chunk->data, chunk->size, &compressed_size); if(compressed_data && compressed_size) { free(chunk->data); chunk->data=compressed_data; chunk->compressed_size=compressed_size; EPHYR_DBG("compressed chunk from %d to %d", chunk->size, chunk->compressed_size); } } } else chunk->mimeData=PIXMAP; chunk->selection=selection_from_atom(selection); if(remoteVars->selstruct.incrementalSize && (remoteVars->selstruct.incrAtom==property)) { //this is the total size of our selection chunk->totalSize=remoteVars->selstruct.incrementalSize; //we are doing incremental reading if(remoteVars->selstruct.incrementalSizeRead == 0) { //it's the first chunk chunk->firstChunk=TRUE; } remoteVars->selstruct.incrementalSizeRead+=xcb_get_property_value_length(reply); if(!bytes_left && ! bytes_read && !xcb_get_property_value_length(reply)) { //we got the property with 0 size it means that we received all data of incr property // EPHYR_DBG("INCR Property done, read %d", remoteVars->selstruct.incrementalSizeRead); remoteVars->selstruct.incrAtom=0; remoteVars->selstruct.incrementalSize=0; //it's the last chunk chunk->lastChunk=TRUE; } } else { //we are doing simple read if(bytes_read==0) { //it's the first chunk chunk->firstChunk=TRUE; } if(bytes_left==0) { //the last chunk chunk->lastChunk=TRUE; } //total size of the selection chunk->totalSize=xcb_get_property_value_length(reply)+bytes_left; } bytes_read+=xcb_get_property_value_length(reply); // EPHYR_DBG( "read chunk of selection - size %d, total read %d, left %d, first:%d, last:%d", xcb_get_property_value_length(reply), bytes_read, bytes_left, chunk->firstChunk, chunk->lastChunk); pthread_mutex_lock(&remoteVars->sendqueue_mutex); //attach chunk to the end of output chunk queue if(!remoteVars->selstruct.lastOutputChunk) { remoteVars->selstruct.lastOutputChunk=remoteVars->selstruct.firstOutputChunk=chunk; } else { remoteVars->selstruct.lastOutputChunk->next=chunk; remoteVars->selstruct.lastOutputChunk=chunk; } EPHYR_DBG(" ADD CHUNK %p %p %p", remoteVars->selstruct.firstOutputChunk, remoteVars->selstruct.lastOutputChunk, chunk); pthread_cond_signal(&remoteVars->have_sendqueue_cond); pthread_mutex_unlock(&remoteVars->sendqueue_mutex); if(bytes_left) { free(reply); cookie= xcb_get_property(remoteVars->selstruct.xcbConnection, 0, remoteVars->selstruct.clipWinId, property, XCB_GET_PROPERTY_TYPE_ANY, bytes_read/4, max_chunk()); reply=xcb_get_property_reply(remoteVars->selstruct.xcbConnection, cookie, NULL); if(!reply) { //something is wrong EPHYR_DBG("NULL reply"); break; } } //read in loop till no data left }while(bytes_left); } else { EPHYR_DBG("Unsupported mime type: %d",reply->type); } } if(reply) free(reply); //if reading incr property this will say sel owner that we are ready for the next chunk of data xcb_delete_property(remoteVars->selstruct.xcbConnection, remoteVars->selstruct.clipWinId, property); xcb_flush(remoteVars->selstruct.xcbConnection); } } } void send_notify_to_client(xcb_atom_t selection, xcb_atom_t mime) { //creating the selection chunk with no data, which notifyes client that we have a selection struct OutputChunk* chunk= malloc(sizeof(struct OutputChunk)); memset((void*)chunk,0,sizeof(struct OutputChunk)); if(is_string_atom(mime)) chunk->mimeData=UTF_STRING; else chunk->mimeData=PIXMAP; chunk->selection=selection_from_atom(selection); chunk->totalSize=0; chunk->firstChunk=chunk->lastChunk=TRUE; pthread_mutex_lock(&remoteVars->sendqueue_mutex); //attach chunk to the end of output chunk queue if(!remoteVars->selstruct.lastOutputChunk) { remoteVars->selstruct.lastOutputChunk=remoteVars->selstruct.firstOutputChunk=chunk; } else { remoteVars->selstruct.lastOutputChunk->next=chunk; remoteVars->selstruct.lastOutputChunk=chunk; } pthread_cond_signal(&remoteVars->have_sendqueue_cond); pthread_mutex_unlock(&remoteVars->sendqueue_mutex); } void process_selection_notify(xcb_generic_event_t *e) { xcb_selection_notify_event_t *sel_event; enum SelectionType selection; // EPHYR_DBG("selection notify"); sel_event=(xcb_selection_notify_event_t *)e; selection=selection_from_atom(sel_event->selection); if(sel_event->property== XCB_NONE && sel_event->target==XCB_NONE) { //have data demand from client request_selection_data( sel_event->selection, remoteVars->selstruct.best_atom[selection],remoteVars->selstruct.best_atom[selection], 0); return; } if(sel_event->property== sel_event->selection && sel_event->target==sel_event->selection) { //have data ready from server. We don't need to do anything here. This event interrupted the waiting procedure and the delayed requests are already processed // EPHYR_DBG("Have DATA READY event"); return; } //processing the event which is reply for convert selection call remoteVars->selstruct.incrAtom=0; remoteVars->selstruct.incrementalSize=0; if (sel_event->requestor != remoteVars->selstruct.clipWinId) { // EPHYR_DBG("not our window"); return; } else { // EPHYR_DBG("selection notify sel %d, target %d, property %d", sel_event->selection, sel_event->target, sel_event->property); if(sel_event->property==XCB_NONE) { // EPHYR_DBG( "NO SELECTION"); } else { remoteVars->selstruct.currentSelection=sel_event->selection; //read property read_selection_property(remoteVars->selstruct.currentSelection, sel_event->property); } } } void process_property_notify(xcb_generic_event_t *e) { xcb_property_notify_event_t *pn; // EPHYR_DBG("property notify"); pn = (xcb_property_notify_event_t *)e; if (pn->window != remoteVars->selstruct.clipWinId) { //this property doesn't belong to our window; //let's check if it's not the property corresponding to one of incr transactions process_incr_transaction_property(pn); return; } // EPHYR_DBG("property %d, state %d ", pn->atom, pn->state); if(pn->state==XCB_PROPERTY_NEW_VALUE) { // EPHYR_DBG( "NEW VALUE"); if(remoteVars->selstruct.incrAtom==pn->atom && remoteVars->selstruct.incrementalSize) { //we're receiving the selection data incrementally, let's read the next chunk // EPHYR_DBG("reading incr property %d", pn->atom); read_selection_property(remoteVars->selstruct.currentSelection, pn->atom); } } if(pn->state==XCB_PROPERTY_DELETE) { // EPHYR_DBG( "DELETE"); } if(pn->state==XCB_PROPERTY_NOTIFY) { // EPHYR_DBG( "NOTIFY"); } } void process_selection_owner_notify(xcb_generic_event_t *e) { enum SelectionType selection; xcb_xfixes_selection_notify_event_t *notify_event=(xcb_xfixes_selection_notify_event_t *)e; // EPHYR_DBG("SEL OWNER notify, selection: %d, window: %d, owner: %d",notify_event->selection, notify_event->window, notify_event->owner); if(notify_event->owner == remoteVars->selstruct.clipWinId) { // EPHYR_DBG("It's our own selection, ignoring"); return; } //web clients V. < 4 not support selections if(remoteVars->selstruct.selectionMode == CLIP_NONE || remoteVars->selstruct.selectionMode == CLIP_CLIENT || ((remoteVars->client_version < 4) && (remoteVars->client_os == WEB))) { EPHYR_DBG("Server selection is disabled"); return; } //cancel all previous incr reading remoteVars->selstruct.incrementalSize=remoteVars->selstruct.incrementalSizeRead=0; remoteVars->selstruct.incrAtom=0; selection=selection_from_atom(notify_event->selection); //we are not owners of this selection anymore pthread_mutex_lock(&remoteVars->selstruct.inMutex); remoteVars->selstruct.inSelection[selection].owner=FALSE; pthread_mutex_unlock(&remoteVars->selstruct.inMutex); //get supported mime types request_selection_data( notify_event->selection, ATOM_TARGETS, ATOM_TARGETS, 0); } static void *selection_thread (void* id) { xcb_screen_t *screen; uint response_type; xcb_generic_event_t *e=NULL; uint32_t mask = 0; uint32_t values[2]; xcb_generic_error_t *error = 0; const xcb_query_extension_reply_t *reply; xcb_xfixes_query_version_cookie_t xfixes_query_cookie; xcb_xfixes_query_version_reply_t *xfixes_query; #ifdef EPHYR_WANT_DEBUG debug_selectThreadId=pthread_self(); #endif /* EPHYR_WANT_DEBUG */ /* Create the window */ remoteVars->selstruct.xcbConnection = xcb_connect (remoteVars->displayName, NULL); if(xcb_connection_has_error(remoteVars->selstruct.xcbConnection)) { EPHYR_DBG("Warning! Can't create XCB connection to display %s, selections exchange between client and server will be disabled", remoteVars->displayName); remoteVars->selstruct.xcbConnection=0; pthread_exit(0); return NULL; } screen = xcb_setup_roots_iterator (xcb_get_setup (remoteVars->selstruct.xcbConnection)).data; remoteVars->selstruct.clipWinId = xcb_generate_id (remoteVars->selstruct.xcbConnection); mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; values[0] = screen->white_pixel; values[1] = XCB_EVENT_MASK_PROPERTY_CHANGE; init_atoms(); //create window which will receive selection events and provide remote selection to X clients xcb_create_window (remoteVars->selstruct.xcbConnection, XCB_COPY_FROM_PARENT, remoteVars->selstruct.clipWinId, screen->root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values); xcb_flush(remoteVars->selstruct.xcbConnection); //check if we have xfixes, we need it to receive selection owner events reply = xcb_get_extension_data(remoteVars->selstruct.xcbConnection, &xcb_xfixes_id); if (reply && reply->present) { xfixes_query_cookie = xcb_xfixes_query_version(remoteVars->selstruct.xcbConnection, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); xfixes_query = xcb_xfixes_query_version_reply (remoteVars->selstruct.xcbConnection, xfixes_query_cookie, &error); if (!xfixes_query || error || xfixes_query->major_version < 2) { free(error); } else { //we'll receive sel owner events for primary and clipboard mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER; xcb_xfixes_select_selection_input_checked(remoteVars->selstruct.xcbConnection,remoteVars->selstruct.clipWinId, XCB_ATOM_PRIMARY, mask); xcb_xfixes_select_selection_input_checked(remoteVars->selstruct.xcbConnection, remoteVars->selstruct.clipWinId, ATOM_CLIPBOARD, mask); } free(xfixes_query); } xcb_flush(remoteVars->selstruct.xcbConnection); // event loop while ((e = xcb_wait_for_event(remoteVars->selstruct.xcbConnection))) { process_delayed_requests(); remove_obsolete_incr_transactions(TRUE); response_type = e->response_type & ~0x80; //we're notified that selection has changed in primary or clipboard if (response_type == reply->first_event + XCB_XFIXES_SELECTION_NOTIFY) { process_selection_owner_notify(e); } else { //we're notified that property has changed if (response_type == XCB_PROPERTY_NOTIFY) { process_property_notify(e); } //we've got a reply to our selection request (mime types or data) else if (response_type == XCB_SELECTION_NOTIFY) { process_selection_notify(e); } else if (response_type == XCB_SELECTION_REQUEST) { if(!process_selection_request(e)) { //we delayed this request, not deleting the event yet continue; } } else { // EPHYR_DBG("not processing this event %d ", response_type); } } free(e); xcb_flush(remoteVars->selstruct.xcbConnection); } pthread_exit(0); return NULL; } void install_selection_callbacks(void) { int ret; if(remoteVars->selstruct.threadStarted) return; remoteVars->selstruct.threadStarted=TRUE; ret = pthread_create(&(remoteVars->selstruct.selThreadId), NULL, selection_thread, (void *)remoteVars->selstruct.selThreadId); if (ret) { EPHYR_DBG("ERROR; return code of pthread_create() is %d", ret); remoteVars->selstruct.selThreadId=0; } else pthread_mutex_init(&remoteVars->selstruct.inMutex, NULL); return; } void client_sel_request_notify(enum SelectionType sel) { //this function will be used from main thread to send the event which will // notify selection thread that client want us to send data for selection sel xcb_selection_notify_event_t* event= (xcb_selection_notify_event_t*)calloc(32, 1); event->response_type = XCB_SELECTION_NOTIFY; event->requestor = remoteVars->selstruct.clipWinId; event->selection = atom_from_selection(sel); event->target = XCB_NONE; event->property = XCB_NONE; event->time = XCB_TIME_CURRENT_TIME; xcb_send_event(remoteVars->selstruct.xcbConnection, FALSE, remoteVars->selstruct.clipWinId, XCB_EVENT_MASK_NO_EVENT, (char*)event); xcb_flush(remoteVars->selstruct.xcbConnection); free(event); } void client_sel_data_notify(enum SelectionType sel) { //this function will be used from main thread to send the event which will // notify selection thread that client sent us data for selection sel xcb_selection_notify_event_t* event= (xcb_selection_notify_event_t*)calloc(32, 1); event->response_type = XCB_SELECTION_NOTIFY; event->requestor = remoteVars->selstruct.clipWinId; event->selection = atom_from_selection(sel); event->target = atom_from_selection(sel); event->property = atom_from_selection(sel); event->time = XCB_TIME_CURRENT_TIME; xcb_send_event(remoteVars->selstruct.xcbConnection, FALSE, remoteVars->selstruct.clipWinId, XCB_EVENT_MASK_NO_EVENT, (char*)event); xcb_flush(remoteVars->selstruct.xcbConnection); free(event); } BOOL process_selection_request(xcb_generic_event_t *e) { //processing selection request. //return true if the processing is finishing after return //false if data is not ready and we are delaying processing of this request //in this case calling function SHOULD NOT destroy the request neither event should not be destroyed //we'll free this objects after processing of the request when the data is available xcb_selection_request_event_t *req=(xcb_selection_request_event_t*)e; enum SelectionType sel=selection_from_atom(req->selection); xcb_atom_t property=req->property; xcb_atom_t target=req->target; xcb_selection_notify_event_t* event= (xcb_selection_notify_event_t*)calloc(32, 1); event->response_type = XCB_SELECTION_NOTIFY; event->requestor = req->requestor; event->selection = req->selection; event->target = req->target; event->property = XCB_NONE; event->time = req->time; if(property == XCB_NONE) property=target; //synchronize with main thread pthread_mutex_lock(&remoteVars->selstruct.inMutex); if(! remoteVars->selstruct.inSelection[sel].owner) { pthread_mutex_unlock(&remoteVars->selstruct.inMutex); //we don't own this selection // EPHYR_DBG("not our selection"); xcb_send_event(remoteVars->selstruct.xcbConnection, FALSE, req->requestor, XCB_EVENT_MASK_NO_EVENT, (char*)event); xcb_flush(remoteVars->selstruct.xcbConnection); free(event); return TRUE; } if(remoteVars->selstruct.inSelection[sel].timestamp > req->time) { pthread_mutex_unlock(&remoteVars->selstruct.inMutex); //selection changed after request // EPHYR_DBG("requested selection doesn't exist anymore"); xcb_send_event(remoteVars->selstruct.xcbConnection, FALSE, req->requestor, XCB_EVENT_MASK_NO_EVENT, (char*)event); xcb_flush(remoteVars->selstruct.xcbConnection); free(event); return TRUE; } if(req->target==ATOM_TIMESTAMP) { event->property=property; // EPHYR_DBG("requested TIMESTAMP"); xcb_change_property(remoteVars->selstruct.xcbConnection, XCB_PROP_MODE_REPLACE, req->requestor, property, XCB_ATOM_INTEGER, 32, 1, &remoteVars->selstruct.inSelection[sel].timestamp); } else if(req->target==ATOM_TARGETS) { event->property=property; // EPHYR_DBG("requested TARGETS"); send_mime_types(req); } else { if(remoteVars->selstruct.inSelection[sel].state==COMPLETED) event->property=send_data(req); else { // EPHYR_DBG("the data for %d is not ready yet",sel); delay_selection_request(req,event); pthread_mutex_unlock(&remoteVars->selstruct.inMutex); return FALSE; } } pthread_mutex_unlock(&remoteVars->selstruct.inMutex); xcb_send_event(remoteVars->selstruct.xcbConnection, FALSE, req->requestor, XCB_EVENT_MASK_NO_EVENT, (char*)event); xcb_flush(remoteVars->selstruct.xcbConnection); free(event); return TRUE; } xcb_atom_t atom_from_selection(enum SelectionType sel) { if(sel==PRIMARY) return XCB_ATOM_PRIMARY; return ATOM_CLIPBOARD; } enum SelectionType selection_from_atom(xcb_atom_t selection) { if(selection == XCB_ATOM_PRIMARY) return PRIMARY; return CLIPBOARD; } void send_mime_types(xcb_selection_request_event_t* req) { //inmutex is locked in the caller function //send supported targets enum SelectionType sel=selection_from_atom(req->selection); //we'll have max 7 mimetypes, don't forget to change this dimension if adding new mimetypes xcb_atom_t targets[7]; uint32_t mcount=0; targets[mcount++]=ATOM_TARGETS; targets[mcount++]=ATOM_TIMESTAMP; if(remoteVars->selstruct.inSelection[sel].mimeData==PIXMAP) { //only supporting PNG here at the moment targets[mcount++]=ATOM_IMAGE_PNG; /* //return PNG mime, if our data in PNG format, otherwise return JPEG if((a=atom("image/png")) && is_png(remoteVars->selstruct.inSelection[sel].data, remoteVars->selstruct.inSelection[sel].size)) { //our buffer is PNG file targets[mcount++]=a; EPHYR_DBG("SENDING PNG ATOMS"); } else { EPHYR_DBG("SENDING JPG ATOMS"); if((a=atom("image/jpg"))) targets[mcount++]=a; if((a=atom("image/jpeg"))) targets[mcount++]=a; }*/ } else { // EPHYR_DBG("SENDING STRING ATOMS"); targets[mcount++]=ATOM_UTF8_STRING; targets[mcount++]=ATOM_TEXT_PLAIN_UTF; targets[mcount++]=ATOM_STRING; targets[mcount++]=ATOM_TEXT; targets[mcount++]=ATOM_TEXT_PLAIN; } xcb_change_property(remoteVars->selstruct.xcbConnection, XCB_PROP_MODE_REPLACE, req->requestor, req->property, XCB_ATOM_ATOM, 32, mcount, (const void *)targets); xcb_flush(remoteVars->selstruct.xcbConnection); } xcb_atom_t send_data(xcb_selection_request_event_t* req) { //inmutex is locked in the caller function //send data enum SelectionType sel=selection_from_atom(req->selection); if(remoteVars->selstruct.inSelection[sel].mimeData==UTF_STRING) { //if it's one of supported text formats send without convertion if(is_string_atom(req->target)) { // EPHYR_DBG("sending UTF text"); return set_data_property(req, remoteVars->selstruct.inSelection[sel].data, remoteVars->selstruct.inSelection[sel].size); } else { EPHYR_DBG("unsupported property requested: %d",req->target); return XCB_NONE; } } else { if(!is_image_atom(req->target)) { EPHYR_DBG("unsupported property requested: %d",req->target); return XCB_NONE; } /* starget=atom_name(req->target); EPHYR_DBG("requested %s",starget); if(starget) free(starget); */ //TODO: implement conversion between different image formats if(is_png(remoteVars->selstruct.inSelection[sel].data, remoteVars->selstruct.inSelection[sel].size)) { if(req->target!=ATOM_IMAGE_PNG) { EPHYR_DBG("unsupported property requested: %d",req->target); return XCB_NONE; } } else { if((req->target!=ATOM_IMAGE_JPEG)&&(req->target!=ATOM_IMAGE_JPG)) { EPHYR_DBG("unsupported property requested: %d",req->target); return XCB_NONE; } } return set_data_property(req, remoteVars->selstruct.inSelection[sel].data, remoteVars->selstruct.inSelection[sel].size); } return XCB_NONE; } xcb_atom_t set_data_property(xcb_selection_request_event_t* req, unsigned char* data, uint32_t size) { //inmutex locked in parent thread //set data to window property //change when implemented BOOL support_incr=TRUE; //this types of application not supporting incr selection if(req->property == ATOM_XT_SELECTION|| req->property == ATOM_QT_SELECTION ) { EPHYR_DBG("property %d doesn't support INCR",req->property); support_incr=FALSE; } //check if we are sending incr if(!support_incr) { if(size < xcb_get_maximum_request_length(remoteVars->selstruct.xcbConnection) * 4 - 24) { // EPHYR_DBG( "sending %d bytes, property %d, target %d", size, req->property, req->target); xcb_change_property(remoteVars->selstruct.xcbConnection, XCB_PROP_MODE_REPLACE, req->requestor, req->property, req->target, 8, size, (const void *)data); xcb_flush(remoteVars->selstruct.xcbConnection); return req->property; } //the data is to big to sent in one property and requestor doesn't support INCR EPHYR_DBG("data is too big"); return XCB_NONE; } if(size < INCR_SIZE) { //if size is < 256K send in one property xcb_change_property(remoteVars->selstruct.xcbConnection, XCB_PROP_MODE_REPLACE, req->requestor, req->property, req->target, 8, size, (const void *)data); xcb_flush(remoteVars->selstruct.xcbConnection); return req->property; } //sending INCR atom to let requester know that we are starting data incrementally // EPHYR_DBG("starting INCR send of size %d for win ID %d" ,size, req->requestor); xcb_change_property(remoteVars->selstruct.xcbConnection, XCB_PROP_MODE_REPLACE, req->requestor, req->property, ATOM_INCR, 32, 1, (const void *)&size); start_incr_transaction(req->requestor, req->property, req->target, data, size); xcb_flush(remoteVars->selstruct.xcbConnection); return req->property; } void start_incr_transaction(xcb_window_t requestor, xcb_atom_t property, xcb_atom_t target, unsigned char* data, uint32_t size) { //creating INCR transaction //inmutex is locked from parent thread const uint32_t mask[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; struct IncrTransaction* tr=malloc( sizeof(struct IncrTransaction)); tr->requestor=requestor; tr->property=property; tr->target=target; tr->sentBytes=0; tr->timestamp=currentTime.milliseconds; tr->data=malloc(size); tr->size=size; tr->next=NULL; memcpy(tr->data, data, size); //add new transaction to the list if(!remoteVars->selstruct.firstIncrTransaction) { remoteVars->selstruct.firstIncrTransaction=remoteVars->selstruct.lastIncrTransaction=tr; } else { remoteVars->selstruct.lastIncrTransaction->next=tr; remoteVars->selstruct.lastIncrTransaction=tr; } //we'll receive property change events for requestor window from now xcb_change_window_attributes(remoteVars->selstruct.xcbConnection, requestor, XCB_CW_EVENT_MASK, mask); } BOOL is_png(unsigned char* data, uint32_t size) { if( size<8) return FALSE; return !png_sig_cmp(data, 0, 8); } unsigned char* zcompress(unsigned char *inbuf, uint32_t size, uint32_t* compress_size) { //compressing the data with zlib //return compressed data, storing the size of compressed data in compress_size //caller function should check result of compression and free the output buffer //out buffer at least the size of input buffer unsigned char* out=malloc(size); z_stream stream; stream.zalloc = Z_NULL; stream.zfree = Z_NULL; stream.opaque = Z_NULL; stream.avail_in = size; stream.next_in = inbuf; stream.avail_out = size; stream.next_out = out; deflateInit(&stream, Z_BEST_COMPRESSION); deflate(&stream, Z_FINISH); deflateEnd(&stream); if(!stream.total_out || stream.total_out >= size) { EPHYR_DBG("zlib compression failed"); free(out); *compress_size=0; return NULL; } *compress_size=stream.total_out; return out; } void delay_selection_request( xcb_selection_request_event_t *request, xcb_selection_notify_event_t* event) { //delay the request for later processing when data will be ready //inmutex is locked in the caller function enum SelectionType sel=selection_from_atom(request->selection); struct DelayedRequest* dr = malloc( sizeof(struct DelayedRequest)); dr->event=event; dr->request=request; dr->next=NULL; //add new request to the queue if(!remoteVars->selstruct.firstDelayedRequest) { remoteVars->selstruct.firstDelayedRequest=remoteVars->selstruct.lastDelayedRequest=dr; } else { remoteVars->selstruct.lastDelayedRequest->next=dr; remoteVars->selstruct.lastDelayedRequest=dr; } if(remoteVars->selstruct.inSelection[sel].state==NOTIFIED) { //if we didn't request the data yet, let's do it now // EPHYR_DBG("requesting data"); pthread_mutex_lock(&remoteVars->sendqueue_mutex); remoteVars->selstruct.requestSelection[sel] = TRUE; pthread_cond_signal(&remoteVars->have_sendqueue_cond); pthread_mutex_unlock(&remoteVars->sendqueue_mutex); remoteVars->selstruct.inSelection[sel].state=REQUESTED; } } x2gokdrive-0.0.0.2/x2gokdriveselection.h0000644000000000000000000000614514500121262014763 0ustar /* * X2GoKDrive - A kdrive X server for X2Go (based on Xephyr) * Author Oleksandr Shneyder * * Copyright © 2018-2023 phoca-GmbH * * * * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * Copyright © 2004 Nokia * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef X2GOKDRIVESELECTION_H #define X2GOKDRIVESELECTION_H #include "x2gokdriveremote.h" uint32_t max_chunk(void); void selection_init(struct _remoteHostVars *obj); void install_selection_callbacks(void); int own_selection(enum SelectionType selection); int is_string_atom( xcb_atom_t at); int is_image_atom( xcb_atom_t at); xcb_atom_t string_to_atom(const char* name); char *atom_to_string(xcb_atom_t xatom); void init_atoms(void); void send_notify_to_client(xcb_atom_t selection, xcb_atom_t mime); void request_selection_data( xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t); void read_selection_property(xcb_atom_t selection, xcb_atom_t property); void process_selection_notify(xcb_generic_event_t *e); void process_property_notify(xcb_generic_event_t *e); void process_selection_owner_notify(xcb_generic_event_t *e); BOOL process_selection_request(xcb_generic_event_t *e); void send_mime_types(xcb_selection_request_event_t* req); enum SelectionType selection_from_atom(xcb_atom_t selection); xcb_atom_t atom_from_selection(enum SelectionType sel); xcb_atom_t send_data(xcb_selection_request_event_t* req); xcb_atom_t set_data_property(xcb_selection_request_event_t* req, unsigned char* data, uint32_t size); void client_sel_request_notify(enum SelectionType sel); void client_sel_data_notify(enum SelectionType sel); BOOL is_png(unsigned char* data, uint32_t size); void delay_selection_request( xcb_selection_request_event_t *reqest, xcb_selection_notify_event_t* event); void process_delayed_requests(void); struct DelayedRequest* discard_delayed_request(struct DelayedRequest* d, struct DelayedRequest* prev); BOOL check_req_sanity(xcb_selection_request_event_t* req); void start_incr_transaction(xcb_window_t requestor, xcb_atom_t property, xcb_atom_t target, unsigned char* data, uint32_t size); void process_incr_transaction_property(xcb_property_notify_event_t * pn); void destroy_incr_transaction(struct IncrTransaction* tr, struct IncrTransaction* prev); void remove_obsolete_incr_transactions( BOOL checkTs); unsigned char* zcompress(unsigned char *inbuf, uint32_t size, uint32_t* compress_size); #endif /* X2GOKDRIVESELECTION_H */