Skip to content

Commit

Permalink
#496: use fakeXinerama library to get applications to maximize on a s…
Browse files Browse the repository at this point in the history
…pecific monitor instead of across all of them

git-svn-id: https://xpra.org/svn/Xpra/trunk@5323 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Jan 31, 2014
1 parent b4d2f2e commit 650ee62
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 6 deletions.
24 changes: 24 additions & 0 deletions src/fakexinerama/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*****************************************************************
Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
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.

The above copyright notice and this permission notice 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
DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL 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.

Except as contained in this notice, the name of Digital Equipment Corporation
shall not be used in advertising or otherwise to promote the sale, use or other
dealings in this Software without prior written authorization from Digital
Equipment Corporation.
******************************************************************/
57 changes: 57 additions & 0 deletions src/fakexinerama/README.TXT
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
= libfakeXinerama =


1) What it is
This fake library can be used to override the default libXinerama
library and expose customized screen dimensions.


2) Origins
This code is based on fakexinerama,
which used to live here:
http://home.kde.org/~seli/fakexinerama
but this link is now dead.

I found another copy here:
https://github.com/asafge/xrdp_dualmon/tree/master/fakexinerama


3) Modifications
This version is modified to allow multiple displays for the same user.
Instead of looking for its configuration in the file:
~/.fakexinerama
It will first attempt to load its configuration from the file:
~/.$DISPLAY-fakexinerama

We also rename it to prevent overwriting or conflicting with
the real libXinerama shared library.

As with the rest of the X11 code, it used the MIT license.


4) Configuration file
The .fakexinerama configuration file follows a simple but strict format:
* use "#" at the beginning of a line for comments
* the first line that is not a comment MUST contain the number of screens defined in the file,
* the number of screens MUST be a valid positive number between 1 and 10
* each of the following lines that are not comments MUST define each of the screen
* all screens MUST be defined
* each screen MUST consist of four numeric values separated by a single space: x y w h
this defines the area of the display that belongs to the given screen


5) Example Configuration File:
# 2 screens:
2
# Laptop Main screen "LVDS1":
0 0 1366 768
# External LCD screen "HDMI1":
1366 0 1920 1080


6) Building it
gcc -O2 -Wall fakeXinerama.c -fPIC -o libfakeXinerama.so.1.0 -shared


7) Using it
LD_PRELOAD=/path/to/libfakeXinerama.so.1.0 yourapplication
153 changes: 153 additions & 0 deletions src/fakexinerama/fakeXinerama.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*****************************************************************
Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
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.
The above copyright notice and this permission notice 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
DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL 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.
Except as contained in this notice, the name of Digital Equipment Corporation
shall not be used in advertising or otherwise to promote the sale, use or other
dealings in this Software without prior written authorization from Digital
Equipment Corporation.
******************************************************************/

#include <X11/Xlibint.h>
#include <X11/extensions/Xinerama.h>
#include <stdio.h>

static int num_screens = -1;
static struct
{
int x_org, y_org;
int width, height;
} screen_info[ 10 ];

static void skipComments( FILE* f )
{
char tmp[ 4096 ];
for(;;)
{
int c;
for(;;)
{
c = fgetc( f );
if( c == EOF )
return;
if( c != ' ' && c != '\t' && c != '\n' )
break;
}
if (c != '#')
{
ungetc( c, f );
return;
}
fgets( tmp, 4096, f );
}
}

static void initFakeXinerama()
{
const char* home;
const char* display;
char buf[ 4096 ];
FILE* f;
int i;

if (num_screens != -1)
return;
num_screens = 0;
home = getenv("HOME");

if (home == NULL)
return;

f = NULL;
display = getenv("DISPLAY");
if (display != NULL) {
sprintf(buf, "%s/.%s-fakexinerama", display, home);
f = fopen(buf, "r");
}
if (f == NULL) {
sprintf(buf, "%s/.fakexinerama", home);
f = fopen(buf, "r");
}
if (f == NULL)
return;
skipComments(f);
if (fscanf(f, "%d\n", &num_screens) != 1)
{
num_screens = 0;
fclose(f);
return;
}
if (num_screens >= 10)
num_screens = 10;
for (i = 0; i < num_screens; ++i)
{
skipComments(f);
if (fscanf(f, "%d %d %d %d\n", &screen_info[i].x_org, &screen_info[i].y_org,
&screen_info[ i ].width, &screen_info[i].height) != 4)
{
num_screens = 0;
fclose(f);
return;
}
}
fclose(f);
}

Bool XineramaQueryExtension(Display *dpy, int *event_base, int *error_base)
{
(void) dpy;
*event_base = 0;
*error_base = 0;
return True;
}

Status XineramaQueryVersion(Display *dpy, int *major, int *minor)
{
(void) dpy;
*major = 1;
*minor = 1;
return 1;
}

Bool XineramaIsActive(Display *dpy)
{
(void) dpy;
initFakeXinerama();
return num_screens != 0;
}

XineramaScreenInfo *XineramaQueryScreens(Display *dpy, int *number)
{
XineramaScreenInfo *scrnInfo = NULL;
initFakeXinerama();

if (num_screens) {
if((scrnInfo = Xmalloc(sizeof(XineramaScreenInfo) * num_screens))) {
int i;
for(i = 0; i < num_screens; i++) {
scrnInfo[i].screen_number = i;
scrnInfo[i].x_org = screen_info[ i ].x_org;
scrnInfo[i].y_org = screen_info[ i ].y_org;
scrnInfo[i].width = screen_info[ i ].width;
scrnInfo[i].height = screen_info[ i ].height;
}
*number = num_screens;
}
}
return scrnInfo;
}
2 changes: 2 additions & 0 deletions src/xpra/scripts/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ def read_xpra_defaults():
"debug" : bool,
"daemon" : bool,
"use-display" : bool,
"fake-xinerama" : bool,
"tray" : bool,
"clipboard" : bool,
"pulseaudio" : bool,
Expand Down Expand Up @@ -317,6 +318,7 @@ def get_defaults():
"debug" : False,
"daemon" : True,
"use-display" : False,
"fake-xinerama" : True,
"tray" : True,
"clipboard" : True,
"pulseaudio" : True,
Expand Down
5 changes: 5 additions & 0 deletions src/xpra/scripts/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,14 @@ def parse_cmdline(cmdline):
default=defaults.xvfb,
metavar="CMD",
help="How to run the headless X server (default: '%default')")
group.add_option("--no-fake-xinerama", action="store_false",
dest="fake_xinerama",
default=defaults.fake_xinerama,
help="Turn off fake xinerama support (default: '%default')")
else:
hidden_options["use_display"] = False
hidden_options["xvfb"] = ''
hidden_options["fake_xinerama"] = False
if supports_server or supports_shadow:
group.add_option("--bind-tcp", action="append",
dest="bind_tcp", default=defaults.bind_tcp,
Expand Down
22 changes: 18 additions & 4 deletions src/xpra/scripts/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,12 +533,24 @@ def verify_display_ready(xvfb, display_name, shadowing):
return None
return display

def start_children(child_reaper, commands):
def start_children(child_reaper, commands, fake_xinerama):
assert os.name=="posix"
from xpra.log import Logger
log = Logger()
#disable ubuntu's global menu using env vars:
env = os.environ.copy()
#add fake xinerama:
if fake_xinerama:
#locate the fakeXinerama lib:
#it would be better to rely on dlopen to find the paths
#but I cannot find a way of getting ctypes to tell us the path
#it found the library in
for libpath in ["/usr/lib64", "/usr/lib", "/usr/local/lib64", "/usr/local/lib"]:
if not os.path.exists(libpath):
continue
libfakeXinerama_so = "%s/%s" % (libpath, "libfakeXinerama.so.1")
if os.path.exists(libfakeXinerama_so):
env["LD_PRELOAD"] = libfakeXinerama_so
#disable ubuntu's global menu using env vars:
env.update({
"UBUNTU_MENUPROXY" : "",
"QT_X11_NO_NATIVE_MENUBAR" : "1"})
Expand All @@ -561,10 +573,11 @@ def run_server(parser, opts, mode, xpra_file, extra_args):
return 0

assert mode in ("start", "upgrade", "shadow", "proxy")
starting = mode == "start"
upgrading = mode == "upgrade"
shadowing = mode == "shadow"
proxying = mode == "proxy"
clobber = upgrading or opts.use_display
clobber = upgrading or opts.use_display

#get the display name:
if shadowing and len(extra_args)==0:
Expand Down Expand Up @@ -672,6 +685,7 @@ def run_server(parser, opts, mode, xpra_file, extra_args):
app = ProxyServer()
app.init(opts)
else:
assert starting or upgrading
from xpra.x11.gtk_x11 import gdk_display_source
assert gdk_display_source
#(now we can access the X11 server)
Expand Down Expand Up @@ -730,7 +744,7 @@ def reaper_quit():
assert opts.start_child, "exit-with-children was specified but start-child is missing!"
if opts.start_child:
assert os.name=="posix", "start-child cannot be used on %s" % os.name
start_children(child_reaper, opts.start_child)
start_children(child_reaper, opts.start_child, (opts.fake_xinerama and not shadowing))

try:
e = app.run()
Expand Down
Loading

0 comments on commit 650ee62

Please sign in to comment.