Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Virtual Me2Me implementation. This script runs and manages the processes | 6 # Virtual Me2Me implementation. This script runs and manages the processes |
| 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop | 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop |
| 8 # session, and Host process. | 8 # session, and Host process. |
| 9 # This script is intended to run continuously as a background daemon | 9 # This script is intended to run continuously as a background daemon |
| 10 # process, running under an ordinary (non-root) user account. | 10 # process, running under an ordinary (non-root) user account. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 import time | 35 import time |
| 36 import uuid | 36 import uuid |
| 37 | 37 |
| 38 LOG_FILE_ENV_VAR = "CHROME_REMOTE_DESKTOP_LOG_FILE" | 38 LOG_FILE_ENV_VAR = "CHROME_REMOTE_DESKTOP_LOG_FILE" |
| 39 | 39 |
| 40 # This script has a sensible default for the initial and maximum desktop size, | 40 # This script has a sensible default for the initial and maximum desktop size, |
| 41 # which can be overridden either on the command-line, or via a comma-separated | 41 # which can be overridden either on the command-line, or via a comma-separated |
| 42 # list of sizes in this environment variable. | 42 # list of sizes in this environment variable. |
| 43 DEFAULT_SIZES_ENV_VAR = "CHROME_REMOTE_DESKTOP_DEFAULT_DESKTOP_SIZES" | 43 DEFAULT_SIZES_ENV_VAR = "CHROME_REMOTE_DESKTOP_DEFAULT_DESKTOP_SIZES" |
| 44 | 44 |
| 45 # By default, this script launches Xvfb as the virtual X display. When this | |
| 46 # environment variable is set, the script will instead launch an instance of | |
| 47 # Xorg using the dummy display driver and void input device. | |
|
Jamie
2016/05/07 00:05:47
Add instructions here on how to install dummy and
rkjnsn
2016/05/09 16:58:34
It's obvious now that you mention it.
| |
| 48 USE_XORG_ENV_VAR = "CHROME_REMOTE_DESKTOP_USE_XORG" | |
| 49 | |
| 45 # By default, provide a maximum size that is large enough to support clients | 50 # By default, provide a maximum size that is large enough to support clients |
| 46 # with large or multiple monitors. This is a comma-separated list of | 51 # with large or multiple monitors. This is a comma-separated list of |
| 47 # resolutions that will be made available if the X server supports RANDR. These | 52 # resolutions that will be made available if the X server supports RANDR. These |
| 48 # defaults can be overridden in ~/.profile. | 53 # defaults can be overridden in ~/.profile. |
| 49 DEFAULT_SIZES = "1600x1200,3840x2560" | 54 DEFAULT_SIZES = "1600x1200,3840x2560" |
| 50 | 55 |
| 51 # If RANDR is not available, use a smaller default size. Only a single | 56 # If RANDR is not available, use a smaller default size. Only a single |
| 52 # resolution is supported in this case. | 57 # resolution is supported in this case. |
| 53 DEFAULT_SIZE_NO_RANDR = "1600x1200" | 58 DEFAULT_SIZE_NO_RANDR = "1600x1200" |
| 54 | 59 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 95 # session file exist. | 100 # session file exist. |
| 96 if (os.path.isdir(CONFIG_DIR) or os.path.isfile(SESSION_FILE_PATH) or | 101 if (os.path.isdir(CONFIG_DIR) or os.path.isfile(SESSION_FILE_PATH) or |
| 97 os.path.isfile(SYSTEM_SESSION_FILE_PATH)): | 102 os.path.isfile(SYSTEM_SESSION_FILE_PATH)): |
| 98 return True | 103 return True |
| 99 | 104 |
| 100 # The host has been tested only on Ubuntu. | 105 # The host has been tested only on Ubuntu. |
| 101 distribution = platform.linux_distribution() | 106 distribution = platform.linux_distribution() |
| 102 return (distribution[0]).lower() == 'ubuntu' | 107 return (distribution[0]).lower() == 'ubuntu' |
| 103 | 108 |
| 104 | 109 |
| 105 def get_randr_supporting_x_server(): | 110 def locate_xvfb_randr(): |
| 106 """Returns a path to an X server that supports the RANDR extension, if this | 111 """Returns a path to our RANDR-supporting Xvfb server, if it is found on the |
| 107 is found on the system. Otherwise returns None.""" | 112 system. Otherwise returns None.""" |
| 108 | 113 |
| 109 xvfb = "/usr/bin/Xvfb-randr" | 114 xvfb = "/usr/bin/Xvfb-randr" |
| 110 if os.path.exists(xvfb): | 115 if os.path.exists(xvfb): |
| 111 return xvfb | 116 return xvfb |
| 112 | 117 |
| 113 xvfb = os.path.join(SCRIPT_DIR, "Xvfb-randr") | 118 xvfb = os.path.join(SCRIPT_DIR, "Xvfb-randr") |
| 114 if os.path.exists(xvfb): | 119 if os.path.exists(xvfb): |
| 115 return xvfb | 120 return xvfb |
| 116 | 121 |
| 117 return None | 122 return None |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 231 | 236 |
| 232 class Desktop: | 237 class Desktop: |
| 233 """Manage a single virtual desktop""" | 238 """Manage a single virtual desktop""" |
| 234 | 239 |
| 235 def __init__(self, sizes): | 240 def __init__(self, sizes): |
| 236 self.x_proc = None | 241 self.x_proc = None |
| 237 self.session_proc = None | 242 self.session_proc = None |
| 238 self.host_proc = None | 243 self.host_proc = None |
| 239 self.child_env = None | 244 self.child_env = None |
| 240 self.sizes = sizes | 245 self.sizes = sizes |
| 246 self.xorg_conf = None | |
| 241 self.pulseaudio_pipe = None | 247 self.pulseaudio_pipe = None |
| 242 self.server_supports_exact_resize = False | 248 self.server_supports_exact_resize = False |
| 243 self.host_ready = False | 249 self.host_ready = False |
| 244 self.ssh_auth_sockname = None | 250 self.ssh_auth_sockname = None |
| 245 g_desktops.append(self) | 251 g_desktops.append(self) |
| 246 | 252 |
| 247 @staticmethod | 253 @staticmethod |
| 248 def get_unused_display_number(): | 254 def get_unused_display_number(): |
| 249 """Return a candidate display number for which there is currently no | 255 """Return a candidate display number for which there is currently no |
| 250 X Server lock file""" | 256 X Server lock file""" |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 349 self.child_env["PULSE_STATE_PATH"] = pulse_path | 355 self.child_env["PULSE_STATE_PATH"] = pulse_path |
| 350 self.child_env["PULSE_SINK"] = sink_name | 356 self.child_env["PULSE_SINK"] = sink_name |
| 351 self.pulseaudio_pipe = pipe_name | 357 self.pulseaudio_pipe = pipe_name |
| 352 | 358 |
| 353 return True | 359 return True |
| 354 | 360 |
| 355 def _setup_gnubby(self): | 361 def _setup_gnubby(self): |
| 356 self.ssh_auth_sockname = ("/tmp/chromoting.%s.ssh_auth_sock" % | 362 self.ssh_auth_sockname = ("/tmp/chromoting.%s.ssh_auth_sock" % |
| 357 os.environ["USER"]) | 363 os.environ["USER"]) |
| 358 | 364 |
| 365 def _launch_xvfb(self, display, x_auth_file, extra_x_args): | |
| 366 max_width = max([width for width, height in self.sizes]) | |
| 367 max_height = max([height for width, height in self.sizes]) | |
| 368 | |
| 369 xvfb = locate_xvfb_randr() | |
| 370 if xvfb: | |
| 371 self.server_supports_exact_resize = True | |
| 372 else: | |
| 373 xvfb = "Xvfb" | |
| 374 self.server_supports_exact_resize = False | |
| 375 | |
| 376 logging.info("Starting %s on display :%d" % (xvfb, display)) | |
| 377 screen_option = "%dx%dx24" % (max_width, max_height) | |
| 378 self.x_proc = subprocess.Popen( | |
| 379 [xvfb, ":%d" % display, | |
| 380 "-auth", x_auth_file, | |
| 381 "-nolisten", "tcp", | |
| 382 "-noreset", | |
| 383 "-screen", "0", screen_option | |
| 384 ] + extra_x_args) | |
| 385 if not self.x_proc.pid: | |
| 386 raise Exception("Could not start Xvfb.") | |
| 387 | |
| 388 def _launch_xorg(self, display, x_auth_file, extra_x_args): | |
| 389 config_file = tempfile.NamedTemporaryFile( | |
| 390 prefix="chrome_remote_desktop_", suffix=".conf", delete=False) | |
| 391 config_file.write( | |
| 392 # This causes X to load the default GLX module, even if a proprietary | |
| 393 # one is installed in a different directory. | |
| 394 'Section "Files"\n' | |
| 395 ' ModulePath "/usr/lib/xorg/modules"\n' | |
| 396 'EndSection\n' | |
| 397 '\n' | |
| 398 # Suppress device probing, which happens by default. | |
| 399 'Section "ServerFlags"\n' | |
| 400 ' Option "AutoAddDevices" "false"\n' | |
| 401 ' Option "AutoEnableDevices" "false"\n' | |
| 402 ' Option "DontVTSwitch" "true"\n' | |
| 403 ' Option "PciForceNone" "true"\n' | |
| 404 'EndSection\n' | |
| 405 '\n' | |
| 406 'Section "InputDevice"\n' | |
| 407 ' Identifier "Chrome Remote Desktop Input"\n' | |
| 408 ' Option "CoreKeyboard" "true"\n' | |
| 409 ' Option "CorePointer" "true"\n' | |
| 410 ' Driver "void"\n' | |
| 411 'EndSection\n' | |
| 412 '\n' | |
| 413 'Section "Device"\n' | |
| 414 ' Identifier "Chrome Remote Desktop Videocard"\n' | |
| 415 ' Driver "dummy"\n' | |
| 416 ' VideoRam 1048576\n' | |
|
Jamie
2016/05/07 00:05:47
I think it's worth defining named constants for th
rkjnsn
2016/05/09 16:58:34
That requires me to have a good reason for why the
| |
| 417 'EndSection\n' | |
| 418 '\n' | |
| 419 'Section "Monitor"\n' | |
| 420 ' Identifier "Chrome Remote Desktop Monitor"\n' | |
| 421 ' HorizSync 3.3\n' | |
| 422 ' VertRefresh 0.1\n' | |
| 423 '{modelines}' | |
| 424 'EndSection\n' | |
| 425 '\n' | |
| 426 'Section "Screen"\n' | |
| 427 ' Identifier "Chrome Remote Desktop Screen"\n' | |
| 428 ' Device "Chrome Remote Desktop Videocard"\n' | |
| 429 ' Monitor "Chrome Remote Desktop Monitor"\n' | |
| 430 ' DefaultDepth 24\n' | |
| 431 ' SubSection "Display"\n' | |
| 432 ' Viewport 0 0\n' | |
| 433 ' Depth 24\n' | |
| 434 ' Modes {modes}\n' | |
| 435 ' EndSubSection\n' | |
| 436 'EndSection\n' | |
| 437 '\n' | |
| 438 'Section "ServerLayout"\n' | |
| 439 ' Identifier "Chrome Remote Desktop Layout"\n' | |
| 440 ' Screen "Chrome Remote Desktop Screen"\n' | |
| 441 ' InputDevice "Chrome Remote Desktop Input"\n' | |
| 442 'EndSection\n'.format( | |
| 443 modelines="".join( | |
| 444 ' Modeline "{0}x{1}" 108.9 {0} 32998 32999 33000 ' | |
| 445 '{1} 32998 32999 33000\n'.format(w, h) for w, h in self.sizes), | |
| 446 modes=" ".join('"{0},{1}"'.format(w, h) for w, h in self.sizes))) | |
| 447 config_file.close() | |
|
Jamie
2016/05/07 00:05:47
Would using "with" be more Pythonic than explicitl
rkjnsn
2016/05/09 16:58:33
Probably. Will do.
| |
| 448 | |
| 449 # For now, we don't support exact resize with Xorg+dummy | |
| 450 self.server_supports_exact_resize = False | |
| 451 self.xorg_conf = config_file.name | |
| 452 | |
| 453 logging.info("Starting Xorg on display :%d" % display) | |
| 454 # We use the child environment so the Xorg server picks up the Mesa libGL | |
| 455 # instead of any proprietary versions that may be installed, thanks to | |
| 456 # LD_LIBRARY_PATH. | |
| 457 # TODO(rkjnsn): Perhaps we want to pass the rest of our environment through | |
| 458 # instead of using the clean one we create for the session so that the user | |
| 459 # can pass environment variables to Xorg like they could for Xvfb. | |
|
Jamie
2016/05/07 00:05:47
I don't think we need this TODO. It seems unlikely
rkjnsn
2016/05/09 16:58:33
Acknowledged.
| |
| 460 self.x_proc = subprocess.Popen( | |
| 461 ["Xorg", ":%d" % display, | |
| 462 "-auth", x_auth_file, | |
| 463 "-nolisten", "tcp", | |
| 464 "-noreset", | |
| 465 # Log to stderr instead of a file so the output ends up in our main | |
| 466 # log file | |
|
Jamie
2016/05/07 00:05:47
How does specifying the logfile as /dev/null log t
rkjnsn
2016/05/09 16:58:33
Ah, yes. I was worried this might not be clear. By
Jamie
2016/05/10 00:37:09
I completely missed the -verbose flag. Please move
| |
| 467 "-logfile", "/dev/null", "-verbose", "3", | |
| 468 "-config", config_file.name | |
| 469 ] + extra_x_args, env=self.child_env) | |
| 470 if not self.x_proc.pid: | |
| 471 raise Exception("Could not start Xorg.") | |
| 472 | |
| 359 def _launch_x_server(self, extra_x_args): | 473 def _launch_x_server(self, extra_x_args): |
| 360 x_auth_file = os.path.expanduser("~/.Xauthority") | 474 x_auth_file = os.path.expanduser("~/.Xauthority") |
| 361 self.child_env["XAUTHORITY"] = x_auth_file | 475 self.child_env["XAUTHORITY"] = x_auth_file |
| 362 devnull = open(os.devnull, "r+") | 476 devnull = open(os.devnull, "r+") |
| 363 display = self.get_unused_display_number() | 477 display = self.get_unused_display_number() |
| 364 | 478 |
| 365 # Run "xauth add" with |child_env| so that it modifies the same XAUTHORITY | 479 # Run "xauth add" with |child_env| so that it modifies the same XAUTHORITY |
| 366 # file which will be used for the X session. | 480 # file which will be used for the X session. |
| 367 ret_code = subprocess.call("xauth add :%d . `mcookie`" % display, | 481 ret_code = subprocess.call("xauth add :%d . `mcookie`" % display, |
| 368 env=self.child_env, shell=True) | 482 env=self.child_env, shell=True) |
| 369 if ret_code != 0: | 483 if ret_code != 0: |
| 370 raise Exception("xauth failed with code %d" % ret_code) | 484 raise Exception("xauth failed with code %d" % ret_code) |
| 371 | 485 |
| 372 max_width = max([width for width, height in self.sizes]) | |
| 373 max_height = max([height for width, height in self.sizes]) | |
| 374 | |
| 375 xvfb = get_randr_supporting_x_server() | |
| 376 if xvfb: | |
| 377 self.server_supports_exact_resize = True | |
| 378 else: | |
| 379 xvfb = "Xvfb" | |
| 380 self.server_supports_exact_resize = False | |
| 381 | |
| 382 # Disable the Composite extension iff the X session is the default | 486 # Disable the Composite extension iff the X session is the default |
| 383 # Unity-2D, since it uses Metacity which fails to generate DAMAGE | 487 # Unity-2D, since it uses Metacity which fails to generate DAMAGE |
| 384 # notifications correctly. See crbug.com/166468. | 488 # notifications correctly. See crbug.com/166468. |
| 385 x_session = choose_x_session() | 489 x_session = choose_x_session() |
| 386 if (len(x_session) == 2 and | 490 if (len(x_session) == 2 and |
| 387 x_session[1] == "/usr/bin/gnome-session --session=ubuntu-2d"): | 491 x_session[1] == "/usr/bin/gnome-session --session=ubuntu-2d"): |
| 388 extra_x_args.extend(["-extension", "Composite"]) | 492 extra_x_args.extend(["-extension", "Composite"]) |
| 389 | 493 |
| 390 logging.info("Starting %s on display :%d" % (xvfb, display)) | 494 if USE_XORG_ENV_VAR in os.environ: |
| 391 screen_option = "%dx%dx24" % (max_width, max_height) | 495 self._launch_xorg(display, x_auth_file, extra_x_args) |
| 392 self.x_proc = subprocess.Popen( | 496 else: |
| 393 [xvfb, ":%d" % display, | 497 self._launch_xvfb(display, x_auth_file, extra_x_args) |
| 394 "-auth", x_auth_file, | |
| 395 "-nolisten", "tcp", | |
| 396 "-noreset", | |
| 397 "-screen", "0", screen_option | |
| 398 ] + extra_x_args) | |
| 399 if not self.x_proc.pid: | |
| 400 raise Exception("Could not start Xvfb.") | |
| 401 | 498 |
| 402 self.child_env["DISPLAY"] = ":%d" % display | 499 self.child_env["DISPLAY"] = ":%d" % display |
| 403 self.child_env["CHROME_REMOTE_DESKTOP_SESSION"] = "1" | 500 self.child_env["CHROME_REMOTE_DESKTOP_SESSION"] = "1" |
| 404 | 501 |
| 405 # Use a separate profile for any instances of Chrome that are started in | 502 # Use a separate profile for any instances of Chrome that are started in |
| 406 # the virtual session. Chrome doesn't support sharing a profile between | 503 # the virtual session. Chrome doesn't support sharing a profile between |
| 407 # multiple DISPLAYs, but Chrome Sync allows for a reasonable compromise. | 504 # multiple DISPLAYs, but Chrome Sync allows for a reasonable compromise. |
| 408 chrome_profile = os.path.join(CONFIG_DIR, "chrome-profile") | 505 chrome_profile = os.path.join(CONFIG_DIR, "chrome-profile") |
| 409 self.child_env["CHROME_USER_DATA_DIR"] = chrome_profile | 506 self.child_env["CHROME_USER_DATA_DIR"] = chrome_profile |
| 410 | 507 |
| 411 # Set SSH_AUTH_SOCK to the file name to listen on. | 508 # Set SSH_AUTH_SOCK to the file name to listen on. |
| 412 if self.ssh_auth_sockname: | 509 if self.ssh_auth_sockname: |
| 413 self.child_env["SSH_AUTH_SOCK"] = self.ssh_auth_sockname | 510 self.child_env["SSH_AUTH_SOCK"] = self.ssh_auth_sockname |
| 414 | 511 |
| 415 # Wait for X to be active. | 512 # Wait for X to be active. |
| 416 for _test in range(20): | 513 for _test in range(20): |
| 417 retcode = subprocess.call("xdpyinfo", env=self.child_env, stdout=devnull) | 514 retcode = subprocess.call("xdpyinfo", env=self.child_env, stdout=devnull) |
| 418 if retcode == 0: | 515 if retcode == 0: |
| 419 break | 516 break |
| 420 time.sleep(0.5) | 517 time.sleep(0.5) |
| 421 if retcode != 0: | 518 if retcode != 0: |
| 422 raise Exception("Could not connect to Xvfb.") | 519 raise Exception("Could not connect to X server.") |
| 423 else: | 520 else: |
| 424 logging.info("Xvfb is active.") | 521 logging.info("X server is active.") |
| 425 | 522 |
| 426 # The remoting host expects the server to use "evdev" keycodes, but Xvfb | 523 # The remoting host expects the server to use "evdev" keycodes, but Xvfb |
| 427 # starts configured to use the "base" ruleset, resulting in XKB configuring | 524 # starts configured to use the "base" ruleset, resulting in XKB configuring |
| 428 # for "xfree86" keycodes, and screwing up some keys. See crbug.com/119013. | 525 # for "xfree86" keycodes, and screwing up some keys. See crbug.com/119013. |
| 429 # Reconfigure the X server to use "evdev" keymap rules. The X server must | 526 # Reconfigure the X server to use "evdev" keymap rules. The X server must |
| 430 # be started with -noreset otherwise it'll reset as soon as the command | 527 # be started with -noreset otherwise it'll reset as soon as the command |
| 431 # completes, since there are no other X clients running yet. | 528 # completes, since there are no other X clients running yet. |
| 432 retcode = subprocess.call("setxkbmap -rules evdev", env=self.child_env, | 529 retcode = subprocess.call("setxkbmap -rules evdev", env=self.child_env, |
| 433 shell=True) | 530 shell=True) |
| 434 if retcode != 0: | 531 if retcode != 0: |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 824 # Close the temporary file-descriptors. | 921 # Close the temporary file-descriptors. |
| 825 os.close(devnull_fd) | 922 os.close(devnull_fd) |
| 826 os.close(log_fd) | 923 os.close(log_fd) |
| 827 | 924 |
| 828 | 925 |
| 829 def cleanup(): | 926 def cleanup(): |
| 830 logging.info("Cleanup.") | 927 logging.info("Cleanup.") |
| 831 | 928 |
| 832 global g_desktops | 929 global g_desktops |
| 833 for desktop in g_desktops: | 930 for desktop in g_desktops: |
| 834 for proc, name in [(desktop.x_proc, "Xvfb"), | 931 for proc, name in [(desktop.x_proc, "X server"), |
| 835 (desktop.session_proc, "session"), | 932 (desktop.session_proc, "session"), |
| 836 (desktop.host_proc, "host")]: | 933 (desktop.host_proc, "host")]: |
| 837 if proc is not None: | 934 if proc is not None: |
| 838 logging.info("Terminating " + name) | 935 logging.info("Terminating " + name) |
| 839 try: | 936 try: |
| 840 psutil_proc = psutil.Process(proc.pid) | 937 psutil_proc = psutil.Process(proc.pid) |
| 841 psutil_proc.terminate() | 938 psutil_proc.terminate() |
| 842 | 939 |
| 843 # Use a short timeout, to avoid delaying service shutdown if the | 940 # Use a short timeout, to avoid delaying service shutdown if the |
| 844 # process refuses to die for some reason. | 941 # process refuses to die for some reason. |
| 845 psutil_proc.wait(timeout=10) | 942 psutil_proc.wait(timeout=10) |
| 846 except psutil.TimeoutExpired: | 943 except psutil.TimeoutExpired: |
| 847 logging.error("Timed out - sending SIGKILL") | 944 logging.error("Timed out - sending SIGKILL") |
| 848 psutil_proc.kill() | 945 psutil_proc.kill() |
| 849 except psutil.Error: | 946 except psutil.Error: |
| 850 logging.error("Error terminating process") | 947 logging.error("Error terminating process") |
| 948 if desktop.xorg_conf is not None: | |
| 949 os.remove(desktop.xorg_conf) | |
| 851 | 950 |
| 852 g_desktops = [] | 951 g_desktops = [] |
| 853 if ParentProcessLogger.instance(): | 952 if ParentProcessLogger.instance(): |
| 854 ParentProcessLogger.instance().release_parent(False) | 953 ParentProcessLogger.instance().release_parent(False) |
| 855 | 954 |
| 856 class SignalHandler: | 955 class SignalHandler: |
| 857 """Reload the config file on SIGHUP. Since we pass the configuration to the | 956 """Reload the config file on SIGHUP. Since we pass the configuration to the |
| 858 host processes via stdin, they can't reload it, so terminate them. They will | 957 host processes via stdin, they can't reload it, so terminate them. They will |
| 859 be relaunched automatically with the new config.""" | 958 be relaunched automatically with the new config.""" |
| 860 | 959 |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1041 def main(): | 1140 def main(): |
| 1042 EPILOG = """This script is not intended for use by end-users. To configure | 1141 EPILOG = """This script is not intended for use by end-users. To configure |
| 1043 Chrome Remote Desktop, please install the app from the Chrome | 1142 Chrome Remote Desktop, please install the app from the Chrome |
| 1044 Web Store: https://chrome.google.com/remotedesktop""" | 1143 Web Store: https://chrome.google.com/remotedesktop""" |
| 1045 parser = optparse.OptionParser( | 1144 parser = optparse.OptionParser( |
| 1046 usage="Usage: %prog [options] [ -- [ X server options ] ]", | 1145 usage="Usage: %prog [options] [ -- [ X server options ] ]", |
| 1047 epilog=EPILOG) | 1146 epilog=EPILOG) |
| 1048 parser.add_option("-s", "--size", dest="size", action="append", | 1147 parser.add_option("-s", "--size", dest="size", action="append", |
| 1049 help="Dimensions of virtual desktop. This can be specified " | 1148 help="Dimensions of virtual desktop. This can be specified " |
| 1050 "multiple times to make multiple screen resolutions " | 1149 "multiple times to make multiple screen resolutions " |
| 1051 "available (if the Xvfb server supports this).") | 1150 "available (if the X server supports this).") |
| 1052 parser.add_option("-f", "--foreground", dest="foreground", default=False, | 1151 parser.add_option("-f", "--foreground", dest="foreground", default=False, |
| 1053 action="store_true", | 1152 action="store_true", |
| 1054 help="Don't run as a background daemon.") | 1153 help="Don't run as a background daemon.") |
| 1055 parser.add_option("", "--start", dest="start", default=False, | 1154 parser.add_option("", "--start", dest="start", default=False, |
| 1056 action="store_true", | 1155 action="store_true", |
| 1057 help="Start the host.") | 1156 help="Start the host.") |
| 1058 parser.add_option("-k", "--stop", dest="stop", default=False, | 1157 parser.add_option("-k", "--stop", dest="stop", default=False, |
| 1059 action="store_true", | 1158 action="store_true", |
| 1060 help="Stop the daemon currently running.") | 1159 help="Stop the daemon currently running.") |
| 1061 parser.add_option("", "--get-status", dest="get_status", default=False, | 1160 parser.add_option("", "--get-status", dest="get_status", default=False, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1175 watch_for_resolution_changes(options.watch_resolution) | 1274 watch_for_resolution_changes(options.watch_resolution) |
| 1176 return 0 | 1275 return 0 |
| 1177 | 1276 |
| 1178 if not options.start: | 1277 if not options.start: |
| 1179 # If no modal command-line options specified, print an error and exit. | 1278 # If no modal command-line options specified, print an error and exit. |
| 1180 print(EPILOG, file=sys.stderr) | 1279 print(EPILOG, file=sys.stderr) |
| 1181 return 1 | 1280 return 1 |
| 1182 | 1281 |
| 1183 # If a RANDR-supporting Xvfb is not available, limit the default size to | 1282 # If a RANDR-supporting Xvfb is not available, limit the default size to |
| 1184 # something more sensible. | 1283 # something more sensible. |
| 1185 if get_randr_supporting_x_server(): | 1284 if USE_XORG_ENV_VAR not in os.environ and locate_xvfb_randr(): |
| 1186 default_sizes = DEFAULT_SIZES | 1285 default_sizes = DEFAULT_SIZES |
| 1187 else: | 1286 else: |
| 1188 default_sizes = DEFAULT_SIZE_NO_RANDR | 1287 default_sizes = DEFAULT_SIZE_NO_RANDR |
| 1189 | 1288 |
| 1190 # Collate the list of sizes that XRANDR should support. | 1289 # Collate the list of sizes that XRANDR should support. |
| 1191 if not options.size: | 1290 if not options.size: |
| 1192 if DEFAULT_SIZES_ENV_VAR in os.environ: | 1291 if DEFAULT_SIZES_ENV_VAR in os.environ: |
| 1193 default_sizes = os.environ[DEFAULT_SIZES_ENV_VAR] | 1292 default_sizes = os.environ[DEFAULT_SIZES_ENV_VAR] |
| 1194 options.size = default_sizes.split(",") | 1293 options.size = default_sizes.split(",") |
| 1195 | 1294 |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1376 else: | 1475 else: |
| 1377 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) | 1476 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) |
| 1378 elif os.WIFSIGNALED(status): | 1477 elif os.WIFSIGNALED(status): |
| 1379 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) | 1478 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) |
| 1380 | 1479 |
| 1381 | 1480 |
| 1382 if __name__ == "__main__": | 1481 if __name__ == "__main__": |
| 1383 logging.basicConfig(level=logging.DEBUG, | 1482 logging.basicConfig(level=logging.DEBUG, |
| 1384 format="%(asctime)s:%(levelname)s:%(message)s") | 1483 format="%(asctime)s:%(levelname)s:%(message)s") |
| 1385 sys.exit(main()) | 1484 sys.exit(main()) |
| OLD | NEW |