diff --git a/src/xpra/client/gtk_base/gtk_client_base.py b/src/xpra/client/gtk_base/gtk_client_base.py index cef120862a..ff767cd9e4 100644 --- a/src/xpra/client/gtk_base/gtk_client_base.py +++ b/src/xpra/client/gtk_base/gtk_client_base.py @@ -141,9 +141,9 @@ def show_start_new_command(self, *args): log("show_start_new_command%s current start_new_command=%s, flag=%s", args, self.start_new_command, self.start_new_commands) if self.start_new_command is None: from xpra.client.gtk_base.start_new_command import getStartNewCommand - def run_command_cb(command): - self.send_start_command(command, command, False) - self.start_new_command = getStartNewCommand(run_command_cb) + def run_command_cb(command, sharing=True): + self.send_start_command(command, command, False, sharing) + self.start_new_command = getStartNewCommand(run_command_cb, self.server_supports_sharing) self.start_new_command.show() return self.start_new_command diff --git a/src/xpra/client/gtk_base/start_new_command.py b/src/xpra/client/gtk_base/start_new_command.py index 68f138cf1a..fd43f2d3d2 100755 --- a/src/xpra/client/gtk_base/start_new_command.py +++ b/src/xpra/client/gtk_base/start_new_command.py @@ -29,16 +29,16 @@ _instance = None -def getStartNewCommand(run_callback): +def getStartNewCommand(run_callback, can_share=False): global _instance if _instance is None: - _instance = StartNewCommand(run_callback) + _instance = StartNewCommand(run_callback, can_share) return _instance class StartNewCommand(object): - def __init__(self, run_callback=None): + def __init__(self, run_callback=None, can_share=False): self.run_callback = run_callback self.window = gtk.Window() self.window.connect("destroy", self.close) @@ -68,6 +68,14 @@ def __init__(self, run_callback=None): self.entry.connect('activate', self.run_command) vbox.add(self.entry) + if can_share: + self.share = gtk.CheckButton("Shared", use_underline=False) + #Shared commands will also be shown to other clients + self.share.set_active(True) + vbox.add(self.share) + else: + self.share = False + # Buttons: hbox = gtk.HBox(False, 20) vbox.pack_start(hbox) @@ -134,7 +142,7 @@ def run_command(self, *args): self.hide() command = self.entry.get_text() if self.run_callback: - self.run_callback(command) + self.run_callback(command, self.share is None or self.share.get_active()) def main(): diff --git a/src/xpra/client/ui_client_base.py b/src/xpra/client/ui_client_base.py index fe8c3dc47b..14c18eca94 100644 --- a/src/xpra/client/ui_client_base.py +++ b/src/xpra/client/ui_client_base.py @@ -212,6 +212,7 @@ def __init__(self): self.start_new_commands = False self.server_window_frame_extents = False self.server_is_shadow = False + self.server_supports_sharing = False #what we told the server about our encoding defaults: self.encoding_defaults = {} @@ -988,9 +989,9 @@ def mask_to_names(self, mask): return self.keyboard_helper.mask_to_names(mask) - def send_start_command(self, name, command, ignore): - log("send_start_command(%s, %s, %s)", name, command, ignore) - self.send("start-command", name, command, ignore) + def send_start_command(self, name, command, ignore, sharing=True): + log("send_start_command(%s, %s, %s, %s)", name, command, ignore, sharing) + self.send("start-command", name, command, ignore, sharing) def send_focus(self, wid): @@ -1611,6 +1612,7 @@ def process_ui_capabilities(self): c = self.server_capabilities server_desktop_size = c.intlistget("desktop_size") log("server desktop size=%s", server_desktop_size) + self.server_supports_sharing = c.boolget("sharing") self.server_is_shadow = c.boolget("shadow") if self.can_scale: self.may_adjust_scaling() diff --git a/src/xpra/server/dbus/dbus_server.py b/src/xpra/server/dbus/dbus_server.py index abfa6e486b..30fe567856 100755 --- a/src/xpra/server/dbus/dbus_server.py +++ b/src/xpra/server/dbus/dbus_server.py @@ -199,6 +199,11 @@ def RefreshAllWindows(self): self.server.control_command_refresh(*self.server._id_to_window.keys()) + @dbus.service.method(INTERFACE) + def ResetWindowFilters(self): + self.server.reset_window_filters() + + @dbus.service.method(INTERFACE, in_signature='s') def EnableDebug(self, category): c = ns(category) diff --git a/src/xpra/server/server_base.py b/src/xpra/server/server_base.py index 41274808f6..1bfb53382c 100644 --- a/src/xpra/server/server_base.py +++ b/src/xpra/server/server_base.py @@ -89,6 +89,7 @@ def __init__(self): self._window_to_id = {} self._id_to_window = {} + self.window_filters = [] # Window id 0 is reserved for "not a window" self._max_window_id = 1 @@ -866,6 +867,7 @@ def get_window_id(wid): self._socket_dir, self.main_socket_path, self.dbus_control, self.get_transient_for, self.get_focus, self.get_cursor_data, get_window_id, + self.window_filters, self.supports_mmap, self.av_sync, self.core_encodings, self.encodings, self.default_encoding, self.scaling_control, self.sound_properties, @@ -890,6 +892,9 @@ def get_server_source_class(self): from xpra.server.source import ServerSource return ServerSource + def reset_window_filters(self): + self.window_filters = [] + def parse_hello_ui(self, ss, c, auth_caps, send_ui, share_count): #adds try:except around parse hello ui code: @@ -1481,8 +1486,16 @@ def _process_print(self, proto, packet): def _process_start_command(self, proto, packet): assert self.start_new_commands + log.info("start new command: %s", packet) name, command, ignore = packet[1:4] proc = self.start_child(name, command, ignore) + if len(packet)>=5: + shared = packet[4] + if proc and not shared: + ss = self._server_sources.get(proto) + assert ss + log.info("adding filter: pid=%s for %s", proc.pid, proto) + ss.add_window_filter("window", "pid", "=", proc.pid) log("process_start_command: proc=%s", proc) def _process_info_request(self, proto, packet): diff --git a/src/xpra/server/source.py b/src/xpra/server/source.py index bebd8a7807..22dfce60d3 100644 --- a/src/xpra/server/source.py +++ b/src/xpra/server/source.py @@ -207,6 +207,7 @@ def __init__(self, protocol, disconnect_cb, idle_add, timeout_add, source_remove socket_dir, main_socket_path, dbus_control, get_transient_for, get_focus, get_cursor_data_cb, get_window_id, + window_filters, supports_mmap, av_sync, core_encodings, encodings, default_encoding, scaling_control, sound_properties, @@ -220,6 +221,7 @@ def __init__(self, protocol, disconnect_cb, idle_add, timeout_add, source_remove socket_dir, main_socket_path, dbus_control, get_transient_for, get_focus, get_window_id, + window_filters, supports_mmap, av_sync, core_encodings, encodings, default_encoding, scaling_control, sound_properties, @@ -253,6 +255,7 @@ def __init__(self, protocol, disconnect_cb, idle_add, timeout_add, source_remove self.get_focus = get_focus self.get_cursor_data_cb = get_cursor_data_cb self.get_window_id = get_window_id + self.window_filters = window_filters # mmap: self.supports_mmap = supports_mmap self.mmap = None @@ -343,7 +346,6 @@ def init_vars(self): self.window_sources = {} #WindowSource for each Window ID self.suspended = False - self.window_filters = [] self.uuid = "" self.machine_id = "" @@ -1729,7 +1731,7 @@ def window_metadata(self, wid, window, prop): self.send("window-metadata", wid, metadata) def reset_window_filters(self): - self.window_filters = [] + self.window_filters = [(uuid, f) for uuid, f in self.window_filters if uuid!=self.uuid] def get_window_filter(self, object_name, property_name, operator, value): if object_name!="window": @@ -1743,13 +1745,13 @@ def get_window_filter(self, object_name, property_name, operator, value): def add_window_filter(self, object_name, property_name, operator, value): window_filter = self.get_window_filter(object_name, property_name, operator, value) assert window_filter - self.window_filters.append(window_filter.show) + self.window_filters.append((self.uuid, window_filter.show)) def can_send_window(self, window): - for x in self.window_filters: + for uuid,x in self.window_filters: v = x(window) - if v is True or v is False: - return v + if v is True: + return uuid==self.uuid if self.send_windows and self.system_tray: #common case shortcut return True