Skip to content

Commit

Permalink
#3070 let the server class choose which displays / sessions to return
Browse files Browse the repository at this point in the history
so the proxy servers can return all of them, but desktop / seamless / shadow servers only return the one they manage,
also decode URLs properly and move session loading to the xdg helper,
return icons for categories too
  • Loading branch information
totaam committed Apr 29, 2021
1 parent 3a16a02 commit 5e66bc3
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 31 deletions.
29 changes: 28 additions & 1 deletion xpra/platform/xposix/xdg_helper.py
Expand Up @@ -361,6 +361,23 @@ def do_load_xdg_menu_data():
return menu_data


def load_desktop_sessions():
xsessions_dir = "%s/share/xsessions" % sys.prefix
xsessions = {}
if os.path.exists(xsessions_dir):
from xdg.DesktopEntry import DesktopEntry
for f in os.listdir(xsessions_dir):
filename = os.path.join(xsessions_dir, f)
de = DesktopEntry(filename)
try:
xsessions[de.getName()] = load_xdg_entry(de)
except Exception as e:
log("get_desktop_sessions(%s)", remove_icons, exc_info=True)
log.error("Error loading desktop entry '%s':", filename)
log.error(" %s", e)
return xsessions


def main():
from xpra.platform import program_context
with program_context("XDG-Menu-Helper", "XDG Menu Helper"):
Expand All @@ -379,9 +396,19 @@ def icon_fmt(icondata):
else:
menu = load_xdg_menu_data()
if menu:
print()
print("application menu:")
print_nested_dict(menu, vformat={"IconData" : icon_fmt})
else:
print("no menu data found")
print("no application menu data found")
#try desktop sessions:
sessions = load_desktop_sessions()
if sessions:
print()
print("session menu:")
print_nested_dict(sessions, vformat={"IconData" : icon_fmt})
else:
print("no session menu data found")
return 0

if __name__ == "__main__":
Expand Down
6 changes: 3 additions & 3 deletions xpra/scripts/main.py
Expand Up @@ -3311,10 +3311,10 @@ def get_displays(dotxpra=None, display_names=None):
return displays


def get_xpra_sessions(dotxpra, ignore_state=(DotXpra.UNKNOWN,)):
results = dotxpra.socket_details()
def get_xpra_sessions(dotxpra, ignore_state=(DotXpra.UNKNOWN,), matching_display=None):
results = dotxpra.socket_details(matching_display=matching_display)
log = get_util_logger()
log("get_xpra_sessions(%s) socket_details=%s", dotxpra, results)
log("get_xpra_sessions%s socket_details=%s", (dotxpra, ignore_state, matching_display), results)
sessions = {}
for socket_dir, values in results.items():
for state, display, sockpath in values:
Expand Down
2 changes: 1 addition & 1 deletion xpra/server/http_handler.py
Expand Up @@ -223,7 +223,7 @@ def send_head(self):
content = script(self)
return content
path = self.translate_path(self.path)
if not path:
if not path or not os.path.exists(path):
self.send_error(404, "Path not found")
return None
if os.path.isdir(path):
Expand Down
19 changes: 4 additions & 15 deletions xpra/server/menu_provider.py
Expand Up @@ -4,7 +4,6 @@
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

import sys
import os.path

from gi.repository import GLib
Expand Down Expand Up @@ -173,6 +172,8 @@ def get_menu_icon(self, category_name, app_name):
if not category:
log("get_menu_icon: invalid menu category '%s'", category_name)
return None, None
if app_name is None:
return category.get("IconType"), category.get("IconData")
entries = category.get("Entries")
if not entries:
log("get_menu_icon: no entries for category '%s'", category_name)
Expand All @@ -188,20 +189,8 @@ def get_menu_icon(self, category_name, app_name):
def get_desktop_sessions(self, remove_icons=False):
if not POSIX or OSX:
return None
xsessions_dir = "%s/share/xsessions" % sys.prefix
xsessions = {}
if os.path.exists(xsessions_dir):
from xdg.DesktopEntry import DesktopEntry
from xpra.platform.xposix.xdg_helper import load_xdg_entry
for f in os.listdir(xsessions_dir):
filename = os.path.join(xsessions_dir, f)
de = DesktopEntry(filename)
try:
xsessions[de.getName()] = load_xdg_entry(de)
except Exception as e:
log("get_desktop_sessions(%s)", remove_icons, exc_info=True)
log.error("Error loading desktop entry '%s':", filename)
log.error(" %s", e)
from xpra.platform.xposix.xdg_helper import load_desktop_sessions
xsessions = load_desktop_sessions()
if remove_icons:
xsessions = noicondata(xsessions)
return xsessions
Expand Down
10 changes: 10 additions & 0 deletions xpra/server/server_base.py
Expand Up @@ -185,6 +185,16 @@ def do_cleanup(self):
c.cleanup(self)


######################################################################
# override http scripts to expose just the current session / display
def get_displays(self):
from xpra.scripts.main import get_displays #pylint: disable=import-outside-toplevel
return get_displays(self.dotxpra, display_names=(os.environ.get("DISPLAY"), ))

def get_xpra_sessions(self):
from xpra.scripts.main import get_xpra_sessions #pylint: disable=import-outside-toplevel
return get_xpra_sessions(self.dotxpra, matching_display=os.environ.get("DISPLAY"))

######################################################################
# shutdown / exit commands:
def _process_exit_server(self, _proto, _packet):
Expand Down
38 changes: 27 additions & 11 deletions xpra/server/server_core.py
Expand Up @@ -13,6 +13,7 @@
import signal
import platform
import threading
from urllib.parse import urlparse, parse_qsl, unquote
from weakref import WeakKeyDictionary
from time import sleep, time
from threading import Thread, Lock
Expand Down Expand Up @@ -1439,17 +1440,21 @@ def http_err(self, handler, code=500):
handler.send_response(code)
return None

def http_query_dict(self, path):
return dict(parse_qsl(urlparse(path).query))

def send_json_response(self, handler, data):
import json #pylint: disable=import-outside-toplevel
return self.send_http_response(handler, json.dumps(data), "application/json")

def send_icon(self, handler, icon_type, icon_data):
if not icon_data:
icon_data = load_binary_file(get_icon_filename("transparent.png"))
icon_filename = get_icon_filename("noicon.png")
icon_data = load_binary_file(icon_filename)
icon_type = "png"
httplog("using fallback transparent icon")
mime_type = "application/octet-stream"
if icon_type in ("png", "jpeg", "svg", "webp"):
if icon_type in ("png", "jpeg", "svg", "webp", "svg"):
mime_type = "image/%s" % icon_type
return self.send_http_response(handler, icon_data, mime_type)

Expand All @@ -1465,42 +1470,53 @@ def http_menu_icon_request(self, handler):
def invalid_path():
httplog("invalid menu-icon request path '%s'", handler.path)
return self.http_err(404)
parts = handler.path.split("/MenuIcon/", 1)
parts = unquote(handler.path).split("/MenuIcon/", 1)
#ie: "/menu-icon/a/b" -> ['', 'a/b']
if len(parts)<2:
return invalid_path()
path = parts[1].split("/")
#ie: "a/b" -> ['a', 'b']
category_name = path[0]
if len(path)<2:
return invalid_path()
category_name, app_name = path[:2]
#only the category is present
app_name = None
else:
app_name = path[1]
httplog("http_menu_icon_request: category_name=%s, app_name=%s", category_name, app_name)
icon_type, icon_data = self.menu_provider.get_menu_icon(category_name, app_name)
return self.send_icon(handler, icon_type, icon_data)

def http_desktop_menu_icon_request(self, handler):
def invalid_path():
httplog("invalid menu-icon request path '%s'", handler.path)
return self.http_err(handler, 404)
parts = handler.path.split("/DesktopMenuIcon/", 1)
parts = unquote(handler.path).split("/DesktopMenuIcon/", 1)
#ie: "/menu-icon/wmname" -> ['', 'sessionname']
if len(parts)<2:
return invalid_path()
#in case the sessionname is followed by a slash:
sessionname = parts[1].split("/")[0]
httplog("http_desktop_menu_icon_request: sessionname=%s", sessionname)
icon_type, icon_data = self.menu_provider.get_desktop_menu_icon(sessionname)
return self.send_icon(handler, icon_type, icon_data)

def http_displays_request(self, handler):
from xpra.scripts.main import get_displays
displays = get_displays()
displays = self.get_displays()
log("http_displays_request displays=%s", displays)
return self.send_json_response(handler, displays)

def get_displays(self):
from xpra.scripts.main import get_displays #pylint: disable=import-outside-toplevel
return get_displays(self.dotxpra)

def http_sessions_request(self, handler):
from xpra.scripts.main import get_xpra_sessions
sessions = get_xpra_sessions(self.dotxpra)
sessions = self.get_xpra_sessions()
return self.send_json_response(handler, sessions)

def get_xpra_sessions(self):
from xpra.scripts.main import get_xpra_sessions #pylint: disable=import-outside-toplevel
return get_xpra_sessions(self.dotxpra)

def http_info_request(self, handler):
return self.send_json_response(handler, self.get_http_info())

Expand Down Expand Up @@ -1561,7 +1577,7 @@ def start_tcp_proxy(self, conn, frominfo):
sock.settimeout(1)

#now start forwarding:
from xpra.scripts.fdproxy import XpraProxy
from xpra.scripts.fdproxy import XpraProxy #pylint: disable=import-outside-toplevel
p = XpraProxy(frominfo, conn, tcp_server_connection, self.tcp_proxy_quit)
self._tcp_proxy_clients.append(p)
proxylog.info("client connection from %s forwarded to proxy server on %s:%s", frominfo, host, port)
Expand Down

0 comments on commit 5e66bc3

Please sign in to comment.