def __init__(self, queue_damage, queue_packet, statistics, wid, batch_config, encoding, encodings, encoding_client_options, mmap, mmap_size): self.queue_damage = queue_damage #callback to add damage data which is ready to compress to the damage processing queue self.queue_packet = queue_packet #callback to add a network packet to the outgoing queue self.wid = wid self.global_statistics = statistics #shared/global statistics from ServerSource self.statistics = WindowPerformanceStatistics() self.encoding = encoding #the current encoding self.encodings = encodings #all the encodings supported by the client self.encoding_client_options = encoding_client_options #does the client support encoding options? self.batch_config = batch_config # mmap: self._mmap = mmap self._mmap_size = mmap_size if self._mmap and self._mmap_size > 0: self._mmap_data_start = ctypes.c_uint.from_buffer(self._mmap, 0) self._mmap_data_end = ctypes.c_uint.from_buffer(self._mmap, 4) # video codecs: self._video_encoder = None self._video_encoder_lock = Lock( ) #to ensure we serialize access to the encoder and its internals self._video_encoder_quality = maxdeque( NRECS ) #keep track of the target encoding_quality: (event time, encoding speed) self._video_encoder_speed = maxdeque( NRECS ) #keep track of the target encoding_speed: (event time, encoding speed) # for managing/cancelling damage requests: self._damage_delayed = None #may store a delayed region when batching in progress self._sequence = 1 #increase with every region we process or delay self._damage_cancelled = 0 #stores the highest _sequence cancelled self._damage_packet_sequence = 1 #increase with every damage packet created
def __init__(self): dotxpra = DotXpra() display = os.environ.get("DISPLAY") from xpra.scripts.config import make_defaults_struct opts = make_defaults_struct() target = dotxpra.socket_path(display) log.info("attempting to connect to socket: %s", target) sock = socket.socket(socket.AF_UNIX) sock.connect(target) conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(), target, "scroll-test") log.info("successfully created our socket connection: %s", conn) self.server = ServerMessenger(conn, opts) self.vscroll_events = maxdeque(1000) self.hscroll_events = maxdeque(1000) browser = WebBrowser() #hook some events: browser.content_tabs.connect("focus-view-title-changed", self.title_changed) vscroll_listeners.append(self.vscroll) hscroll_listeners.append(self.hscroll) #the things we tune: self.quality = -1 self.speed = -1 self.encoding = None self.strict = False
def reset(self): self.client_decode_time = maxdeque(NRECS) #records how long it took the client to decode frames: #(ack_time, no of pixels, decoding_time*1000*1000) self.encoding_stats = maxdeque(NRECS) #encoding: (coding, pixels, bpp, compressed_size, encoding_time) # statistics: self.damage_in_latency = maxdeque(NRECS) #records how long it took for a damage request to be sent #last NRECS: (sent_time, no of pixels, actual batch delay, damage_latency) self.damage_out_latency = maxdeque(NRECS) #records how long it took for a damage request to be processed #last NRECS: (processed_time, no of pixels, actual batch delay, damage_latency) self.damage_send_speed = maxdeque(NRECS) #how long it took to send damage packets (this is not a sustained speed) #last NRECS: (sent_time, no_of_pixels, elapsed_time) self.damage_ack_pending = {} #records when damage packets are sent #so we can calculate the "client_latency" when the client sends #the corresponding ack ("damage-sequence" packet - see "client_ack_damage") self.encoding_totals = {} #for each encoding, how many frames we sent and how many pixels in total self.encoding_pending = {} #damage regions waiting to be picked up by the encoding thread: #for each sequence no: (damage_time, w, h) self.last_damage_event_time = None self.damage_events_count = 0 self.packet_count = 0 #these values are calculated from the values above (see update_averages) self.target_latency = self.DEFAULT_TARGET_LATENCY self.avg_damage_in_latency = self.DEFAULT_DAMAGE_LATENCY self.recent_damage_in_latency = self.DEFAULT_DAMAGE_LATENCY self.avg_damage_out_latency = self.DEFAULT_DAMAGE_LATENCY + self.DEFAULT_NETWORK_LATENCY self.recent_damage_out_latency = self.DEFAULT_DAMAGE_LATENCY + self.DEFAULT_NETWORK_LATENCY self.max_latency = self.DEFAULT_DAMAGE_LATENCY + self.DEFAULT_NETWORK_LATENCY self.avg_decode_speed = None self.recent_decode_speed = None self.avg_send_speed = None self.recent_send_speed = None
def video_encoder_cleanup(self): """ Video encoders (x264 and vpx) require us to run cleanup code to free the memory they use. """ try: self._video_encoder_lock.acquire() if self._video_encoder: self._video_encoder.clean() self._video_encoder = None self._video_encoder_speed = maxdeque(NRECS) self._video_encoder_quality = maxdeque(NRECS) finally: self._video_encoder_lock.release()
def __init__(self): self.always = self.ALWAYS self.max_events = self.MAX_EVENTS self.max_pixels = self.MAX_PIXELS self.time_unit = self.TIME_UNIT self.min_delay = self.MIN_DELAY self.max_delay = self.MAX_DELAY self.delay = self.START_DELAY self.recalculate_delay = self.RECALCULATE_DELAY self.last_delays = maxdeque(64) #the delays we have tried to use (milliseconds) self.last_actual_delays = maxdeque(64) #the delays we actually used (milliseconds) self.last_updated = 0 self.wid = 0
def reset(self): # mmap state: self.mmap_size = 0 self.mmap_bytes_sent = 0 self.mmap_free_size = 0 #how much of the mmap space is left (may be negative if we failed to write the last chunk) # queue statistics: self.damage_data_qsizes = maxdeque( NRECS ) #size of the damage_data_queue before we add a new record to it #(event_time, size) self.damage_packet_qsizes = maxdeque( NRECS ) #size of the damage_packet_queue before we add a new packet to it #(event_time, size) self.damage_packet_qpixels = maxdeque( NRECS ) #number of pixels waiting in the damage_packet_queue for a specific window, #before we add a new packet to it #(event_time, wid, size) self.damage_last_events = maxdeque( NRECS) #records the x11 damage requests as they are received: #(wid, event time, no of pixels) self.client_decode_time = maxdeque( NRECS) #records how long it took the client to decode frames: #(wid, event_time, no of pixels, decoding_time) self.min_client_latency = None #The lowest client latency ever recorded self.client_latency = maxdeque( NRECS ) #how long it took for a packet to get to the client and get the echo back. #(wid, event_time, no of pixels, client_latency) self.client_ping_latency = maxdeque(NRECS) self.server_ping_latency = maxdeque(NRECS) self.client_load = None
def __init__(self): self.always = self.ALWAYS self.max_events = self.MAX_EVENTS self.max_pixels = self.MAX_PIXELS self.time_unit = self.TIME_UNIT self.min_delay = self.MIN_DELAY self.max_delay = self.MAX_DELAY self.delay = self.START_DELAY self.recalculate_delay = self.RECALCULATE_DELAY self.last_delays = maxdeque( 64) #the delays we have tried to use (milliseconds) self.last_actual_delays = maxdeque( 64) #the delays we actually used (milliseconds) self.last_updated = 0 self.wid = 0
def reset(self): self.client_decode_time = maxdeque(NRECS) #records how long it took the client to decode frames: #(ack_time, no of pixels, decoding_time*1000*1000) self.encoding_stats = maxdeque(NRECS) #encoding: (coding, pixels, compressed_size, encoding_time) # statistics: self.damage_in_latency = maxdeque(NRECS) #records how long it took for a damage request to be sent #last NRECS: (sent_time, no of pixels, actual batch delay, damage_latency) self.damage_out_latency = maxdeque(NRECS) #records how long it took for a damage request to be processed #last NRECS: (processed_time, no of pixels, actual batch delay, damage_latency) self.damage_send_speed = maxdeque(NRECS) #how long it took to send damage packets (this is not a sustained speed) #last NRECS: (sent_time, no_of_pixels, elapsed_time) self.damage_ack_pending = {} #records when damage packets are sent #so we can calculate the "client_latency" when the client sends #the corresponding ack ("damage-sequence" packet - see "client_ack_damage") self.encoding_totals = {} #for each encoding, how many frames we sent and how many pixels in total
def __init__(self): self.always = self.ALWAYS self.max_events = self.MAX_EVENTS self.max_pixels = self.MAX_PIXELS self.time_unit = self.TIME_UNIT self.min_delay = self.MIN_DELAY self.max_delay = self.MAX_DELAY self.delay = self.START_DELAY self.last_delays = maxdeque(64) #the delays we have tried to use (milliseconds) self.last_actual_delays = maxdeque(64) #the delays we actually used (milliseconds) self.last_updated = 0 self.wid = 0 #the metrics derived from statistics which we use for calculating the new batch delay: #(see batch delay calculator) self.factors = []
def __init__(self, queue_damage, queue_packet, statistics, wid, batch_config, auto_refresh_delay, encoding, encodings, default_damage_options, encoding_client_options, supports_rgb24zlib, uses_swscale, mmap, mmap_size): self.queue_damage = queue_damage #callback to add damage data which is ready to compress to the damage processing queue self.queue_packet = queue_packet #callback to add a network packet to the outgoing queue self.wid = wid self.global_statistics = statistics #shared/global statistics from ServerSource self.statistics = WindowPerformanceStatistics() self.encoding = encoding #the current encoding self.encodings = encodings #all the encodings supported by the client self.default_damage_options = default_damage_options #default encoding options, like "quality" #may change at runtime (ie: see ServerSource.set_quality) self.encoding_client_options = encoding_client_options #does the client support encoding options? self.supports_rgb24zlib = supports_rgb24zlib #supports rgb24 compression outside network layer (unwrapped) self.uses_swscale = uses_swscale #client uses uses_swscale (has extra limits on sizes) self.batch_config = batch_config #auto-refresh: self.auto_refresh_delay = auto_refresh_delay self.refresh_timer = None self.timeout_timer = None self.expire_timer = None # mmap: self._mmap = mmap self._mmap_size = mmap_size if self._mmap and self._mmap_size > 0: self._mmap_data_start = ctypes.c_uint.from_buffer(self._mmap, 0) self._mmap_data_end = ctypes.c_uint.from_buffer(self._mmap, 4) # video codecs: self._video_encoder = None self._video_encoder_lock = Lock( ) #to ensure we serialize access to the encoder and its internals self._video_encoder_quality = maxdeque( NRECS ) #keep track of the target encoding_quality: (event time, encoding speed) self._video_encoder_speed = maxdeque( NRECS ) #keep track of the target encoding_speed: (event time, encoding speed) # for managing/cancelling damage requests: self._damage_delayed = None #may store a delayed region when batching in progress self._damage_delayed_expired = False #when this is True, the region should have expired #but it is now waiting for the backlog to clear self._sequence = 1 #increase with every region we process or delay self._last_sequence_queued = 0 #the latest sequence we queued for sending (after encoding it) self._damage_cancelled = 0 #stores the highest _sequence cancelled self._damage_packet_sequence = 1 #increase with every damage packet created
def __init__(self): self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("destroy", self.destroy) self.window.set_default_size(540, 800) self.window.set_border_width(20) # Title vbox = gtk.VBox(False, 0) vbox.set_spacing(15) label = gtk.Label("Keyboard State") label.modify_font(pango.FontDescription("sans 13")) vbox.pack_start(label) self.modifiers = gtk.Label() vbox.add(self.modifiers) self.mouse = gtk.Label() vbox.add(self.mouse) self.keys = gtk.Label() fixed = pango.FontDescription('monospace 9') self.keys.modify_font(fixed) vbox.add(self.keys) self.window.add(vbox) self.window.show_all() gobject.timeout_add(100, self.populate_modifiers) self.key_events = maxdeque(maxlen=35) self.window.connect("key-press-event", self.key_press) self.window.connect("key-release-event", self.key_release) self.window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
def __init__(self, client, opts): ClientExtrasBase.__init__(self, client, opts) self.setup_menu() self.setup_tray(opts.tray_icon) self.setup_clipboard_helper(ClipboardProtocolHelper) self._last_key_events = maxdeque(maxlen=5) self._dropped_num_lock_press = False
def __init__(self): self.always = self.ALWAYS self.max_events = self.MAX_EVENTS self.max_pixels = self.MAX_PIXELS self.time_unit = self.TIME_UNIT self.min_delay = self.MIN_DELAY self.max_delay = self.MAX_DELAY self.delay = self.START_DELAY self.last_delays = maxdeque( 64) #the delays we have tried to use (milliseconds) self.last_actual_delays = maxdeque( 64) #the delays we actually used (milliseconds) self.last_updated = 0 self.wid = 0 #the metrics derived from statistics which we use for calculating the new batch delay: #(see batch delay calculator) self.factors = []
def __init__(self): self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("destroy", self.destroy) self.window.set_default_size(640, 300) self.window.set_border_width(20) vbox = gtk.VBox(False, 0) vbox.set_spacing(15) self.log = maxdeque(maxlen=25) for x in range(25): self.log.append("") self.events = gtk.Label() fixed = pango.FontDescription('monospace 9') self.events.modify_font(fixed) #how many clipboards to show: self.clipboards = ["CLIPBOARD", "PRIMARY", "SECONDARY"] if sys.platform.startswith("win"): self.clipboards = ["CLIPBOARD"] tb = TableBuilder() table = tb.get_table() labels = [label("Selection")] labels += [ label("Value"), label("Clear"), label("Targets"), label("Actions") ] tb.add_row(*labels) for selection in self.clipboards: cs = ClipboardInstance(selection, self.add_event) get_actions = gtk.HBox() for x in (cs.get_get_targets_btn, cs.get_target_btn, cs.get_string_btn): get_actions.pack_start(x) tb.add_row(label(selection), cs.value_label, cs.clear_label_btn, cs.get_targets, get_actions) set_actions = gtk.HBox() for x in (cs.set_target_btn, cs.set_string_btn): set_actions.pack_start(x) tb.add_row(None, cs.value_entry, cs.clear_entry_btn, cs.set_targets, set_actions) vbox.pack_start(table) vbox.add(self.events) self.window.add(vbox) self.window.show_all() icon = get_icon("clipboard.png") if icon: self.window.set_icon(icon) try: self.add_event( "ALL", "window=%s, xid=%s" % (self.window, hex(self.window.get_window().xid))) except: self.add_event("ALL", "window=%s" % self.window)
def __init__(self, queue_damage, queue_packet, statistics, wid, batch_config, auto_refresh_delay, encoding, encodings, default_damage_options, encoding_client_options, supports_rgb24zlib, uses_swscale, mmap, mmap_size): self.queue_damage = queue_damage #callback to add damage data which is ready to compress to the damage processing queue self.queue_packet = queue_packet #callback to add a network packet to the outgoing queue self.wid = wid self.global_statistics = statistics #shared/global statistics from ServerSource self.statistics = WindowPerformanceStatistics() self.encoding = encoding #the current encoding self.encodings = encodings #all the encodings supported by the client self.default_damage_options = default_damage_options #default encoding options, like "quality" #may change at runtime (ie: see ServerSource.set_quality) self.encoding_client_options = encoding_client_options #does the client support encoding options? self.supports_rgb24zlib = supports_rgb24zlib #supports rgb24 compression outside network layer (unwrapped) self.uses_swscale = uses_swscale #client uses uses_swscale (has extra limits on sizes) self.batch_config = batch_config #auto-refresh: self.auto_refresh_delay = auto_refresh_delay self.refresh_timer = None self.timeout_timer = None self.expire_timer = None # mmap: self._mmap = mmap self._mmap_size = mmap_size if self._mmap and self._mmap_size>0: self._mmap_data_start = ctypes.c_uint.from_buffer(self._mmap, 0) self._mmap_data_end = ctypes.c_uint.from_buffer(self._mmap, 4) # video codecs: self._video_encoder = None self._video_encoder_lock = Lock() #to ensure we serialize access to the encoder and its internals self._video_encoder_quality = maxdeque(NRECS) #keep track of the target encoding_quality: (event time, encoding speed) self._video_encoder_speed = maxdeque(NRECS) #keep track of the target encoding_speed: (event time, encoding speed) # for managing/cancelling damage requests: self._damage_delayed = None #may store a delayed region when batching in progress self._damage_delayed_expired = False #when this is True, the region should have expired #but it is now waiting for the backlog to clear self._sequence = 1 #increase with every region we process or delay self._last_sequence_queued = 0 #the latest sequence we queued for sending (after encoding it) self._damage_cancelled = 0 #stores the highest _sequence cancelled self._damage_packet_sequence = 1 #increase with every damage packet created
def __init__(self, *args): log.info("DebugInfoClientWindow.__init__(%s)", args) TopBarClientWindow.__init__(self, *args) if self._has_custom_decorations: self.log_buffer = maxdeque(100) self.capture_log = True self.debug = lambda *x: self._add_log_event("debug", *x) self.info = lambda *x: self._add_log_event("info", *x) self.warn = lambda *x: self._add_log_event("warn", *x) self.error = lambda *x: self._add_log_event("error", *x)
def __init__(self, *args): log.info("DebugInfoClientWindow.__init__(%s)", args) TopBarClientWindow.__init__(self, *args) if self._has_custom_decorations: self.log_buffer = maxdeque(100) self.capture_log = True self.debug = lambda *x : self._add_log_event("debug", *x) self.info = lambda *x : self._add_log_event("info", *x) self.warn = lambda *x : self._add_log_event("warn", *x) self.error = lambda *x : self._add_log_event("error", *x)
def reset(self): self.client_decode_time = maxdeque( NRECS) #records how long it took the client to decode frames: #(ack_time, no of pixels, decoding_time*1000*1000) self.encoding_stats = maxdeque( NRECS ) #encoding: (coding, pixels, bpp, compressed_size, encoding_time) # statistics: self.damage_in_latency = maxdeque( NRECS) #records how long it took for a damage request to be sent #last NRECS: (sent_time, no of pixels, actual batch delay, damage_latency) self.damage_out_latency = maxdeque( NRECS ) #records how long it took for a damage request to be processed #last NRECS: (processed_time, no of pixels, actual batch delay, damage_latency) self.damage_send_speed = maxdeque( NRECS ) #how long it took to send damage packets (this is not a sustained speed) #last NRECS: (sent_time, no_of_pixels, elapsed_time) self.damage_ack_pending = {} #records when damage packets are sent #so we can calculate the "client_latency" when the client sends #the corresponding ack ("damage-sequence" packet - see "client_ack_damage") self.encoding_totals = { } #for each encoding, how many frames we sent and how many pixels in total self.encoding_pending = { } #damage regions waiting to be picked up by the encoding thread: #for each sequence no: (damage_time, w, h) self.last_damage_event_time = None self.damage_events_count = 0 self.packet_count = 0 #these values are calculated from the values above (see update_averages) self.target_latency = self.DEFAULT_TARGET_LATENCY self.avg_damage_in_latency = self.DEFAULT_DAMAGE_LATENCY self.recent_damage_in_latency = self.DEFAULT_DAMAGE_LATENCY self.avg_damage_out_latency = self.DEFAULT_DAMAGE_LATENCY + self.DEFAULT_NETWORK_LATENCY self.recent_damage_out_latency = self.DEFAULT_DAMAGE_LATENCY + self.DEFAULT_NETWORK_LATENCY self.max_latency = self.DEFAULT_DAMAGE_LATENCY + self.DEFAULT_NETWORK_LATENCY self.avg_decode_speed = None self.recent_decode_speed = None self.avg_send_speed = None self.recent_send_speed = None
def init_context(self, width, height, src_format, encoding, quality, speed, scaling, options): self.encoding = encoding self.width = width self.height = height self.quality = quality self.speed = speed self.scaling = scaling self.src_format = src_format self.last_frame_times = maxdeque(200) self.frames = 0 self.time = 0
def __init__(self): self.enabled = self.ENABLED self.always = self.ALWAYS self.max_events = self.MAX_EVENTS self.max_pixels = self.MAX_PIXELS self.time_unit = self.TIME_UNIT self.min_delay = self.MIN_DELAY self.max_delay = self.MAX_DELAY self.delay = self.START_DELAY self.recalculate_delay = self.RECALCULATE_DELAY self.last_delays = maxdeque(64) self.last_updated = 0 self.wid = 0
def reset(self): # mmap state: self.mmap_size = 0 self.mmap_bytes_sent = 0 self.mmap_free_size = 0 #how much of the mmap space is left (may be negative if we failed to write the last chunk) # queue statistics: self.damage_data_qsizes = maxdeque( NRECS ) #size of the damage_data_queue before we add a new record to it #(event_time, size) self.damage_packet_qsizes = maxdeque( NRECS ) #size of the damage_packet_queue before we add a new packet to it #(event_time, size) self.damage_packet_qpixels = maxdeque( NRECS ) #number of pixels waiting in the damage_packet_queue for a specific window, #before we add a new packet to it #(event_time, wid, size) self.damage_last_events = maxdeque( NRECS) #records the x11 damage requests as they are received: #(wid, event time, no of pixels) self.client_decode_time = maxdeque( NRECS) #records how long it took the client to decode frames: #(wid, event_time, no of pixels, decoding_time*1000*1000) self.client_latency = maxdeque( NRECS ) #how long it took for a packet to get to the client and get the echo back. #(wid, event_time, no of pixels, client_latency) self.client_ping_latency = maxdeque( NRECS) #time it took to get a ping_echo back from the client: #(event_time, elapsed_time_in_seconds) self.server_ping_latency = maxdeque( NRECS ) #time it took for the client to get a ping_echo back from us: #(event_time, elapsed_time_in_seconds) self.client_load = None self.damage_events_count = 0 self.packet_count = 0 #these values are calculated from the values above (see update_averages) self.min_client_latency = self.DEFAULT_LATENCY self.avg_client_latency = self.DEFAULT_LATENCY self.recent_client_latency = self.DEFAULT_LATENCY self.min_client_ping_latency = self.DEFAULT_LATENCY self.avg_client_ping_latency = self.DEFAULT_LATENCY self.recent_client_ping_latency = self.DEFAULT_LATENCY self.min_server_ping_latency = self.DEFAULT_LATENCY self.avg_server_ping_latency = self.DEFAULT_LATENCY self.recent_server_ping_latency = self.DEFAULT_LATENCY
def reset(self): self.client_decode_time = maxdeque( NRECS ) #records how long it took the client to decode frames: (ack_time, no of pixels, decoding_time) self.encoding_stats = maxdeque( NRECS) #encoding: (coding, pixels, compressed_size, encoding_time) # statistics: self.damage_in_latency = maxdeque( NRECS) #records how long it took for a damage request to be sent #last NRECS: (sent_time, no of pixels, actual batch delay, damage_latency) self.damage_out_latency = maxdeque( NRECS ) #records how long it took for a damage request to be processed #last NRECS: (processed_time, no of pixels, actual batch delay, damage_latency) self.damage_send_speed = maxdeque( NRECS ) #how long it took to send damage packets (this is not a sustained speed) #last NRECS: (sent_time, no_of_pixels, elapsed_time) self.damage_ack_pending = {} #records when damage packets are sent #so we can calculate the "client_latency" when the client sends #the corresponding ack ("damage-sequence" packet - see "client_ack_damage") self.last_packet_send_stats = None #used by _damage_send_speed self.last_client_delta = 0, 0 #records how far behind the client was last time we checked
def reset(self): self.client_decode_time = maxdeque( NRECS) #records how long it took the client to decode frames: #(ack_time, no of pixels, decoding_time*1000*1000) self.encoding_stats = maxdeque( NRECS) #encoding: (coding, pixels, compressed_size, encoding_time) # statistics: self.damage_in_latency = maxdeque( NRECS) #records how long it took for a damage request to be sent #last NRECS: (sent_time, no of pixels, actual batch delay, damage_latency) self.damage_out_latency = maxdeque( NRECS ) #records how long it took for a damage request to be processed #last NRECS: (processed_time, no of pixels, actual batch delay, damage_latency) self.damage_send_speed = maxdeque( NRECS ) #how long it took to send damage packets (this is not a sustained speed) #last NRECS: (sent_time, no_of_pixels, elapsed_time) self.damage_ack_pending = {} #records when damage packets are sent #so we can calculate the "client_latency" when the client sends #the corresponding ack ("damage-sequence" packet - see "client_ack_damage") self.encoding_totals = { } #for each encoding, how many frames we sent and how many pixels in total
def __init__(self, menu, tooltip, icon_filename, size_changed_cb, click_cb, mouseover_cb, exit_cb): self.menu = menu self.tooltip = tooltip self.size_changed_cb = size_changed_cb self.click_cb = click_cb self.mouseover_cb = mouseover_cb self.exit_cb = exit_cb self.tray_widget = None self.default_icon_filename = icon_filename self.default_icon_extension = "png" self.default_icon_name = "xpra.png" #some implementations need this for guessing the geometry (see recalculate_geometry): self.geometry_guess = None self.tray_event_locations = maxdeque(512)
class ClientExtras(ClientExtrasBase): def __init__(self, client, opts): ClientExtrasBase.__init__(self, client, opts) try: from xpra.platform.gdk_clipboard import TranslatedClipboardProtocolHelper self.setup_clipboard_helper(TranslatedClipboardProtocolHelper) except ImportError, e: log.error( "GDK Translated Clipboard failed to load: %s - using default fallback", e) self.setup_clipboard_helper(DefaultClipboardProtocolHelper) self.setup_menu() self.setup_tray(opts.no_tray, opts.notifications, opts.tray_icon) self._last_key_events = maxdeque(maxlen=5)
def __init__(self): self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("destroy", self.destroy) self.window.set_default_size(640, 300) self.window.set_border_width(20) vbox = gtk.VBox(False, 0) vbox.set_spacing(15) self.log = maxdeque(maxlen=25) for x in range(25): self.log.append("") self.events = gtk.Label() fixed = pango.FontDescription('monospace 9') self.events.modify_font(fixed) #how many clipboards to show: self.clipboards = ["CLIPBOARD", "PRIMARY", "SECONDARY"] if sys.platform.startswith("win"): self.clipboards = ["CLIPBOARD"] tb = TableBuilder() table = tb.get_table() labels = [label("Selection")] labels += [label("Value"), label("Clear"), label("Targets"), label("Actions")] tb.add_row(*labels) for selection in self.clipboards: cs = ClipboardInstance(selection, self.add_event) get_actions = gtk.HBox() for x in (cs.get_get_targets_btn, cs.get_target_btn, cs.get_string_btn): get_actions.pack_start(x) tb.add_row(label(selection), cs.value_label, cs.clear_label_btn, cs.get_targets, get_actions) set_actions = gtk.HBox() for x in (cs.set_target_btn, cs.set_string_btn): set_actions.pack_start(x) tb.add_row(None, cs.value_entry, cs.clear_entry_btn, cs.set_targets, set_actions) vbox.pack_start(table) vbox.add(self.events) self.window.add(vbox) self.window.show_all() icon = get_icon("clipboard.png") if icon: self.window.set_icon(icon) try: self.add_event("ALL", "window=%s, xid=%s" % (self.window, hex(self.window.get_window().xid))) except: self.add_event("ALL", "window=%s" % self.window)
def reset(self): # mmap state: self.mmap_size = 0 self.mmap_bytes_sent = 0 self.mmap_free_size = 0 #how much of the mmap space is left (may be negative if we failed to write the last chunk) # queue statistics: self.damage_data_qsizes = maxdeque( NRECS ) #size of the damage_data_queue before we add a new record to it #(event_time, size) self.damage_packet_qsizes = maxdeque( NRECS ) #size of the damage_packet_queue before we add a new packet to it #(event_time, size) self.damage_packet_qpixels = maxdeque( NRECS ) #number of pixels waiting in the damage_packet_queue for a specific window, #before we add a new packet to it #(event_time, wid, size) self.damage_last_events = maxdeque( NRECS) #records the x11 damage requests as they are received: #(wid, event time, no of pixels) self.client_decode_time = maxdeque( NRECS) #records how long it took the client to decode frames: #(wid, event_time, no of pixels, decoding_time*1000*1000) self.min_client_latency = None #The lowest client latency ever recorded: the time it took #from the moment the damage packet got sent until we got the ack packet #(but not including time spent decoding on the client) self.client_latency = maxdeque( NRECS ) #how long it took for a packet to get to the client and get the echo back. #(wid, event_time, no of pixels, client_latency) self.avg_client_latency = None self.client_ping_latency = maxdeque( NRECS) #time it took to get a ping_echo back from the client: #(event_time, elapsed_time_in_seconds) self.server_ping_latency = maxdeque( NRECS ) #time it took for the client to get a ping_echo back from us: #(event_time, elapsed_time_in_seconds) self.client_load = None
def reset(self): # mmap state: self.mmap_size = 0 self.mmap_bytes_sent = 0 self.mmap_free_size = 0 #how much of the mmap space is left (may be negative if we failed to write the last chunk) # queue statistics: self.damage_data_qsizes = maxdeque(NRECS) #size of the damage_data_queue before we add a new record to it #(event_time, size) self.damage_packet_qsizes = maxdeque(NRECS) #size of the damage_packet_queue before we add a new packet to it #(event_time, size) self.damage_packet_qpixels = maxdeque(NRECS) #number of pixels waiting in the damage_packet_queue for a specific window, #before we add a new packet to it #(event_time, wid, size) self.damage_last_events = maxdeque(NRECS) #records the x11 damage requests as they are received: #(wid, event time, no of pixels) self.client_decode_time = maxdeque(NRECS) #records how long it took the client to decode frames: #(wid, event_time, no of pixels, decoding_time) self.min_client_latency = None #The lowest client latency ever recorded self.client_latency = maxdeque(NRECS) #how long it took for a packet to get to the client and get the echo back. #(wid, event_time, no of pixels, client_latency) self.client_ping_latency = maxdeque(NRECS) self.server_ping_latency = maxdeque(NRECS) self.client_load = None
def reset(self): # mmap state: self.mmap_size = 0 self.mmap_bytes_sent = 0 self.mmap_free_size = 0 #how much of the mmap space is left (may be negative if we failed to write the last chunk) # queue statistics: self.damage_data_qsizes = maxdeque(NRECS) #size of the damage_data_queue before we add a new record to it #(event_time, size) self.damage_packet_qsizes = maxdeque(NRECS) #size of the damage_packet_queue before we add a new packet to it #(event_time, size) self.damage_packet_qpixels = maxdeque(NRECS) #number of pixels waiting in the damage_packet_queue for a specific window, #before we add a new packet to it #(event_time, wid, size) self.damage_last_events = maxdeque(NRECS) #records the x11 damage requests as they are received: #(wid, event time, no of pixels) self.client_decode_time = maxdeque(NRECS) #records how long it took the client to decode frames: #(wid, event_time, no of pixels, decoding_time*1000*1000) self.client_latency = maxdeque(NRECS) #how long it took for a packet to get to the client and get the echo back. #(wid, event_time, no of pixels, client_latency) self.client_ping_latency = maxdeque(NRECS) #time it took to get a ping_echo back from the client: #(event_time, elapsed_time_in_seconds) self.server_ping_latency = maxdeque(NRECS) #time it took for the client to get a ping_echo back from us: #(event_time, elapsed_time_in_seconds) self.client_load = None self.damage_events_count = 0 self.packet_count = 0 #these values are calculated from the values above (see update_averages) self.min_client_latency = self.DEFAULT_LATENCY self.avg_client_latency = self.DEFAULT_LATENCY self.recent_client_latency = self.DEFAULT_LATENCY self.min_client_ping_latency = self.DEFAULT_LATENCY self.avg_client_ping_latency = self.DEFAULT_LATENCY self.recent_client_ping_latency = self.DEFAULT_LATENCY self.min_server_ping_latency = self.DEFAULT_LATENCY self.avg_server_ping_latency = self.DEFAULT_LATENCY self.recent_server_ping_latency = self.DEFAULT_LATENCY
def do_video_encoder_cleanup(self): self._video_encoder.clean() self._video_encoder = None self._video_encoder_speed = maxdeque(NRECS) self._video_encoder_quality = maxdeque(NRECS)
def init_counters(self): self.avg_batch_delay = maxdeque(N_SAMPLES+4) self.avg_damage_out_latency = maxdeque(N_SAMPLES+4) self.avg_ping_latency = maxdeque(N_SAMPLES+4) self.avg_decoding_latency = maxdeque(N_SAMPLES+4) self.avg_total = maxdeque(N_SAMPLES+4)
def __init__(self, conn, opts): XpraClientBase.__init__(self, opts) self.start_time = time.time() self._window_to_id = {} self._id_to_window = {} self.title = opts.title self.readonly = opts.readonly self.session_name = opts.session_name self.compression_level = opts.compression_level self.auto_refresh_delay = opts.auto_refresh_delay self.max_bandwidth = opts.max_bandwidth if self.max_bandwidth > 0.0 and self.jpegquality == 0: """ jpegquality was not set, use a better start value """ self.jpegquality = 50 self.mmap_enabled = False self.server_start_time = -1 self.server_platform = "" self.server_actual_desktop_size = None self.server_randr = False self.pixel_counter = maxdeque(maxlen=100) self.server_latency = maxdeque(maxlen=100) self.server_load = None self.client_latency = maxdeque(maxlen=100) self.toggle_cursors_bell_notify = False self.toggle_keyboard_sync = False self.bell_enabled = True self.cursors_enabled = True self.notifications_enabled = True self.clipboard_enabled = False self.window_configure = False self.mmap = None self.mmap_token = None self.mmap_file = None self.mmap_size = 0 self.last_ping_echoed_time = 0 self._client_extras = ClientExtras(self, opts) self.clipboard_enabled = not self.readonly and opts.clipboard and self._client_extras.supports_clipboard( ) self.supports_mmap = opts.mmap and ( "rgb24" in ENCODINGS) and self._client_extras.supports_mmap() if self.supports_mmap: try: import mmap import tempfile import uuid from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP mmap_dir = os.getenv("TMPDIR", "/tmp") if not os.path.exists(mmap_dir): raise Exception("TMPDIR %s does not exist!" % mmap_dir) #create the mmap file, the mkstemp that is called via NamedTemporaryFile ensures #that the file is readable and writable only by the creating user ID temp = tempfile.NamedTemporaryFile(prefix="xpra.", suffix=".mmap", dir=mmap_dir) #keep a reference to it so it does not disappear! self._mmap_temp_file = temp self.mmap_file = temp.name fd = temp.file.fileno() #set the group permissions and gid if the mmap-group option is specified if opts.mmap_group and type( conn.target) == str and os.path.exists(conn.target): s = os.stat(conn.target) os.fchown(fd, -1, s.st_gid) os.fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) self.mmap_size = max( 4096, mmap.PAGESIZE) * 32 * 1024 #generally 128MB log("using mmap file %s, fd=%s, size=%s", self.mmap_file, fd, self.mmap_size) os.lseek(fd, self.mmap_size - 1, os.SEEK_SET) assert os.write(fd, '\x00') os.lseek(fd, 0, os.SEEK_SET) self.mmap = mmap.mmap(fd, length=self.mmap_size) #write the 16 byte token one byte at a time - no endianness self.mmap_token = uuid.uuid4().int log.debug("mmap_token=%s", self.mmap_token) v = self.mmap_token for i in range(0, 16): poke = ctypes.c_ubyte.from_buffer(self.mmap, 512 + i) poke.value = v % 256 v = v >> 8 assert v == 0 except Exception, e: log.error("failed to setup mmap: %s", e) self.supports_mmap = False self.clean_mmap() self.mmap = None self.mmap_file = None self.mmap_size = 0
def __init__(self, client, session_name, window_icon_pixbuf, conn, get_pixbuf): gtk.Window.__init__(self) self.client = client self.session_name = session_name self.connection = conn self.last_populate_time = 0 self.last_populate_statistics = 0 self.is_closed = False self.get_pixbuf = get_pixbuf self.set_title(self.session_name or "Session Info") self.set_destroy_with_parent(True) self.set_resizable(True) self.set_decorated(True) if window_icon_pixbuf: self.set_icon(window_icon_pixbuf) if is_gtk3(): self.set_position(gtk.WindowPosition.CENTER) else: self.set_position(gtk.WIN_POS_CENTER) #tables on the left in a vbox with buttons at the top: self.tab_box = gtk.VBox(False, 0) self.tab_button_box = gtk.HBox(True, 0) self.tabs = [] #pairs of button, table self.populate_cb = None self.tab_box.pack_start(self.tab_button_box, expand=False, fill=True, padding=0) #Package Table: tb = self.table_tab("package.png", "Software", self.populate_package) #title row: tb.attach(title_box(""), 0, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Client"), 1, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Server"), 2, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.inc() scaps = self.client.server_capabilities from xpra.__init__ import __version__ tb.new_row("Xpra", label(__version__), label(self.client._remote_version or "unknown")) cl_rev, cl_ch, cl_date = "unknown", "", "" try: from xpra.build_info import BUILD_DATE as cl_date, REVISION as cl_rev, LOCAL_MODIFICATIONS as cl_ch except: pass tb.new_row("Revision", label(cl_rev), label(self.client._remote_revision or "unknown")) tb.new_row("Local Changes", label(cl_ch), label(scaps.get("local_modifications", "unknown"))) tb.new_row("Build date", label(cl_date), label(scaps.get("build_date", "unknown"))) def make_version_str(version): if version and type(version) in (tuple, list): version = ".".join([str(x) for x in version]) return version or "unknown" def server_version_info(prop_name): return make_version_str(scaps.get(prop_name)) def client_version_info(prop_name): info = "unknown" if hasattr(gtk, prop_name): info = make_version_str(getattr(gtk, prop_name)) return info if is_gtk3(): tb.new_row("PyGobject", label(gobject._version)) tb.new_row("Client GDK", label(gdk._version)) tb.new_row("GTK", label(gtk._version), label(server_version_info("gtk_version"))) else: tb.new_row("PyGTK", label(client_version_info("pygtk_version")), label(server_version_info("pygtk_version"))) tb.new_row("GTK", label(client_version_info("gtk_version")), label(server_version_info("gtk_version"))) tb.new_row("Python", label(platform.python_version()), label(server_version_info("python_version"))) cl_gst_v, cl_pygst_v = "", "" from xpra.scripts.main import HAS_SOUND if HAS_SOUND: try: from xpra.sound.gstreamer_util import gst_version as cl_gst_v, pygst_version as cl_pygst_v except: pass tb.new_row("GStreamer", label(make_version_str(cl_gst_v)), label(server_version_info("gst_version"))) tb.new_row("pygst", label(make_version_str(cl_pygst_v)), label(server_version_info("pygst_version"))) tb.new_row( "OpenGL", label( make_version_str(self.client.opengl_props.get("opengl", "n/a"))), label("n/a")) tb.new_row( "OpenGL Vendor", label(make_version_str(self.client.opengl_props.get("vendor", ""))), label("n/a")) tb.new_row( "PyOpenGL", label( make_version_str( self.client.opengl_props.get("pyopengl", "n/a"))), label("n/a")) # Features Table: tb = self.table_tab("features.png", "Features", self.populate_features) randr_box = gtk.HBox(False, 20) self.server_randr_label = label() self.server_randr_icon = gtk.Image() randr_box.add(self.server_randr_icon) randr_box.add(self.server_randr_label) tb.new_row("RandR Support", randr_box) self.server_encodings_label = label() tb.new_row("Server Encodings", self.server_encodings_label) self.client_encodings_label = label() tb.new_row("Client Encodings", self.client_encodings_label) self.server_mmap_icon = gtk.Image() tb.new_row("Memory Mapped Transfers", self.server_mmap_icon) self.server_clipboard_icon = gtk.Image() tb.new_row("Clipboard", self.server_clipboard_icon) self.server_notifications_icon = gtk.Image() tb.new_row("Notification Forwarding", self.server_notifications_icon) self.server_bell_icon = gtk.Image() tb.new_row("Bell Forwarding", self.server_bell_icon) self.server_cursors_icon = gtk.Image() tb.new_row("Cursor Forwarding", self.server_cursors_icon) speaker_box = gtk.HBox(False, 20) self.server_speaker_icon = gtk.Image() speaker_box.add(self.server_speaker_icon) self.speaker_codec_label = label() speaker_box.add(self.speaker_codec_label) tb.new_row("Speaker Forwarding", speaker_box) self.server_speaker_codecs_label = label() tb.new_row("Server Codecs", self.server_speaker_codecs_label) self.client_speaker_codecs_label = label() tb.new_row("Client Codecs", self.client_speaker_codecs_label) microphone_box = gtk.HBox(False, 20) self.server_microphone_icon = gtk.Image() microphone_box.add(self.server_microphone_icon) self.microphone_codec_label = label() microphone_box.add(self.microphone_codec_label) tb.new_row("Microphone Forwarding", microphone_box) self.server_microphone_codecs_label = label() tb.new_row("Server Codecs", self.server_microphone_codecs_label) self.client_microphone_codecs_label = label() tb.new_row("Client Codecs", self.client_microphone_codecs_label) # Connection Table: tb = self.table_tab("connect.png", "Connection", self.populate_connection) tb.new_row("Server Endpoint", label(self.connection.target)) if self.client.server_display: tb.new_row("Server Display", label(self.client.server_display)) if "hostname" in scaps: tb.new_row("Server Hostname", label(scaps.get("hostname"))) if self.client.server_platform: tb.new_row("Server Platform", label(self.client.server_platform)) self.server_load_label = label() tb.new_row("Server Load", self.server_load_label, label_text="Average over 1, 5 and 15 minutes") self.session_started_label = label() tb.new_row("Session Started", self.session_started_label) self.session_connected_label = label() tb.new_row("Session Connected", self.session_connected_label) self.input_packets_label = label() tb.new_row("Packets Received", self.input_packets_label) self.input_bytes_label = label() tb.new_row("Bytes Received", self.input_bytes_label) self.output_packets_label = label() tb.new_row("Packets Sent", self.output_packets_label) self.output_bytes_label = label() tb.new_row("Bytes Sent", self.output_bytes_label) self.compression_label = label() tb.new_row("Compression Level", self.compression_label) self.connection_type_label = label() tb.new_row("Connection Type", self.connection_type_label) self.input_encryption_label = label() tb.new_row("Input Encryption", self.input_encryption_label) self.output_encryption_label = label() tb.new_row("Output Encryption", self.output_encryption_label) # Details: tb = self.table_tab("browse.png", "Statistics", self.populate_statistics) tb.widget_xalign = 1.0 tb.attach(title_box(""), 0, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Latest"), 1, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Minimum"), 2, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Average"), 3, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("90 percentile"), 4, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Maximum"), 5, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.inc() def maths_labels(): return label(), label(), label(), label(), label() self.server_latency_labels = maths_labels() tb.add_row(label("Server Latency (ms)"), *self.server_latency_labels) self.client_latency_labels = maths_labels() tb.add_row(label("Client Latency (ms)"), *self.client_latency_labels) if self.client.windows_enabled: if self.client.server_info_request: self.batch_labels = maths_labels() tb.add_row(label("Batch Delay (ms)"), *self.batch_labels) self.damage_labels = maths_labels() tb.add_row(label("Damage Latency (ms)"), *self.damage_labels) self.regions_per_second_labels = maths_labels() tb.add_row(label("Regions/s"), *self.regions_per_second_labels) self.regions_sizes_labels = maths_labels() tb.add_row(label("Pixels/region"), *self.regions_sizes_labels) self.pixels_per_second_labels = maths_labels() tb.add_row(label("Pixels/s"), *self.pixels_per_second_labels) self.windows_managed_label = label() tb.new_row("Regular Windows", self.windows_managed_label), self.transient_managed_label = label() tb.new_row("Transient Windows", self.transient_managed_label), self.trays_managed_label = label() tb.new_row("Trays Managed", self.trays_managed_label), if self.client.opengl_enabled: self.opengl_label = label() tb.new_row("OpenGL Windows", self.opengl_label), self.graph_box = gtk.VBox(False, 10) self.add_tab("statistics.png", "Graphs", self.populate_graphs, self.graph_box) bandwidth_label = "Number of bytes measured by the networks sockets" if SHOW_PIXEL_STATS: bandwidth_label += ",\nand number of pixels rendered" self.bandwidth_graph = self.add_graph_button(bandwidth_label, self.save_graphs) self.latency_graph = self.add_graph_button( "The time it takes to send an echo packet and get the reply", self.save_graphs) self.pixel_in_data = maxdeque(N_SAMPLES + 4) self.net_in_data = maxdeque(N_SAMPLES + 4) self.net_out_data = maxdeque(N_SAMPLES + 4) self.set_border_width(15) self.add(self.tab_box) if not is_gtk3(): self.set_geometry_hints(self.tab_box) def window_deleted(*args): self.is_closed = True self.connect('delete_event', window_deleted) self.show_tab(self.tabs[0][1]) self.set_size_request(-1, 480) self.populate() self.populate_all() gobject.timeout_add(1000, self.populate) gobject.timeout_add(100, self.populate_tab) self.connect("realize", self.populate_graphs) add_close_accel(self, self.destroy)
def __init__(self, conn, opts): XpraClientBase.__init__(self, opts) self.start_time = time.time() self._window_to_id = {} self._id_to_window = {} title = opts.title if opts.title_suffix is not None: title = "@title@ %s" % opts.title_suffix self.title = title self.readonly = opts.readonly self.session_name = opts.session_name self.compression_level = opts.compression_level self.auto_refresh_delay = opts.auto_refresh_delay self.max_bandwidth = opts.max_bandwidth if self.max_bandwidth>0.0 and self.jpegquality==0: """ jpegquality was not set, use a better start value """ self.jpegquality = 50 self.server_capabilities = {} self.mmap_enabled = False self.server_start_time = -1 self.server_platform = "" self.server_actual_desktop_size = None self.server_desktop_size = None self.server_randr = False self.pixel_counter = maxdeque(maxlen=100) self.server_latency = maxdeque(maxlen=100) self.server_load = None self.client_latency = maxdeque(maxlen=100) self.toggle_cursors_bell_notify = False self.bell_enabled = True self.cursors_enabled = True self.notifications_enabled = True self.clipboard_enabled = False self.mmap = None self.mmap_token = None self.mmap_file = None self.mmap_size = 0 self._client_extras = ClientExtras(self, opts) self.clipboard_enabled = not self.readonly and opts.clipboard and self._client_extras.supports_clipboard() self.supports_mmap = opts.mmap and ("rgb24" in ENCODINGS) and self._client_extras.supports_mmap() if self.supports_mmap: try: import mmap import tempfile import uuid from stat import S_IRUSR,S_IWUSR,S_IRGRP,S_IWGRP mmap_dir = os.getenv("TMPDIR", "/tmp") if not os.path.exists(mmap_dir): raise Exception("TMPDIR %s does not exist!" % mmap_dir) #create the mmap file, the mkstemp that is called via NamedTemporaryFile ensures #that the file is readable and writable only by the creating user ID temp = tempfile.NamedTemporaryFile(prefix="xpra.", suffix=".mmap", dir=mmap_dir) #keep a reference to it so it does not disappear! self._mmap_temp_file = temp self.mmap_file = temp.name fd = temp.file.fileno() #set the group permissions and gid if the mmap-group option is specified if opts.mmap_group and type(conn.target)==str and os.path.exists(conn.target): s = os.stat(conn.target) os.fchown(fd, -1, s.st_gid) os.fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) self.mmap_size = max(4096, mmap.PAGESIZE)*32*1024 #generally 128MB log("using mmap file %s, fd=%s, size=%s", self.mmap_file, fd, self.mmap_size) os.lseek(fd, self.mmap_size-1, os.SEEK_SET) assert os.write(fd, '\x00') os.lseek(fd, 0, os.SEEK_SET) self.mmap = mmap.mmap(fd, length=self.mmap_size) #write the 16 byte token one byte at a time - no endianness self.mmap_token = uuid.uuid4().int log.debug("mmap_token=%s", self.mmap_token) v = self.mmap_token for i in range(0,16): poke = ctypes.c_ubyte.from_buffer(self.mmap, 512+i) poke.value = v % 256 v = v>>8 assert v==0 except Exception, e: log.error("failed to setup mmap: %s", e) self.supports_mmap = False self.clean_mmap() self.mmap = None self.mmap_file = None self.mmap_size = 0
def __init__(self, client, session_name, window_icon_pixbuf, conn, get_pixbuf): gtk.Window.__init__(self) self.client = client self.session_name = session_name self.connection = conn self.last_populate_time = 0 self.last_populate_statistics = 0 self.is_closed = False self.get_pixbuf = get_pixbuf if self.session_name == "Xpra": title = "Session Info" else: title = "%s: Session Info" % self.session_name self.set_title(title) self.set_destroy_with_parent(True) self.set_resizable(True) self.set_decorated(True) if window_icon_pixbuf: self.set_icon(window_icon_pixbuf) if is_gtk3(): self.set_position(gtk.WindowPosition.CENTER) else: self.set_position(gtk.WIN_POS_CENTER) # tables on the left in a vbox with buttons at the top: self.tab_box = gtk.VBox(False, 0) self.tab_button_box = gtk.HBox(True, 0) self.tabs = [] # pairs of button, table self.populate_cb = None self.tab_box.pack_start(self.tab_button_box, expand=False, fill=True, padding=0) # Package Table: tb = self.table_tab("package.png", "Software", self.populate_package) # title row: tb.attach(title_box(""), 0, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Client"), 1, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Server"), 2, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.inc() def make_os_str(sys_platform, platform_release, platform_platform, platform_linux_distribution): s = platform_name(sys_platform, platform_release) if ( platform_linux_distribution and len(platform_linux_distribution) == 3 and len(platform_linux_distribution[0]) > 0 ): s += "\n%s" % (" ".join(platform_linux_distribution)) elif platform_platform: s += "\n%s" % platform_platform return s LOCAL_PLATFORM_NAME = make_os_str( sys.platform, python_platform.release(), python_platform.platform(), python_platform.linux_distribution() ) SERVER_PLATFORM_NAME = make_os_str( self.client._remote_platform, self.client._remote_platform_release, self.client._remote_platform_platform, self.client._remote_platform_linux_distribution, ) tb.new_row("Operating System", label(LOCAL_PLATFORM_NAME), label(SERVER_PLATFORM_NAME)) scaps = self.client.server_capabilities from xpra.__init__ import __version__ tb.new_row("Xpra", label(__version__), label(self.client._remote_version or "unknown")) cl_rev, cl_ch, cl_date = "unknown", "", "" try: from xpra.build_info import BUILD_DATE as cl_date from xpra.src_info import REVISION as cl_rev, LOCAL_MODIFICATIONS as cl_ch except: pass def make_version_str(version): if version and type(version) in (tuple, list): version = ".".join([str(x) for x in version]) return version or "unknown" def server_info(*prop_names): for x in prop_names: v = scaps.get(x) if v is not None: return v return None def server_version_info(*prop_names): return make_version_str(server_info(*prop_names)) tb.new_row("Revision", label(cl_rev), label(make_version_str(self.client._remote_revision))) tb.new_row( "Local Changes", label(cl_ch), label(server_version_info("build.local_modifications", "local_modifications")), ) tb.new_row("Build date", label(cl_date), label(server_info("build_date", "build.date"))) def client_version_info(prop_name): info = "unknown" if hasattr(gtk, prop_name): info = make_version_str(getattr(gtk, prop_name)) return info if is_gtk3(): tb.new_row("PyGobject", label(gobject._version)) tb.new_row("Client GDK", label(gdk._version)) tb.new_row("GTK", label(gtk._version), label(server_version_info("gtk_version"))) else: tb.new_row( "PyGTK", label(client_version_info("pygtk_version")), label(server_version_info("pygtk.version", "pygtk_version")), ) tb.new_row( "GTK", label(client_version_info("gtk_version")), label(server_version_info("gtk.version", "gtk_version")), ) tb.new_row( "Python", label(python_platform.python_version()), label(server_version_info("server.python.version", "python_version")), ) cl_gst_v, cl_pygst_v = "", "" if HAS_SOUND: try: from xpra.sound.gstreamer_util import gst_version as cl_gst_v, pygst_version as cl_pygst_v except: pass tb.new_row( "GStreamer", label(make_version_str(cl_gst_v)), label(server_version_info("sound.gst.version", "gst_version")), ) tb.new_row( "pygst", label(make_version_str(cl_pygst_v)), label(server_version_info("sound.pygst.version", "pygst_version")), ) tb.new_row("OpenGL", label(make_version_str(self.client.opengl_props.get("opengl", "n/a"))), label("n/a")) tb.new_row("OpenGL Vendor", label(make_version_str(self.client.opengl_props.get("vendor", ""))), label("n/a")) tb.new_row("PyOpenGL", label(make_version_str(self.client.opengl_props.get("pyopengl", "n/a"))), label("n/a")) # Features Table: tb = self.table_tab("features.png", "Features", self.populate_features) randr_box = gtk.HBox(False, 20) self.server_randr_label = label() self.server_randr_icon = gtk.Image() randr_box.add(self.server_randr_icon) randr_box.add(self.server_randr_label) tb.new_row("RandR Support", randr_box) opengl_box = gtk.HBox(False, 20) self.client_opengl_label = label() self.client_opengl_label.set_line_wrap(True) self.client_opengl_icon = gtk.Image() opengl_box.add(self.client_opengl_icon) opengl_box.add(self.client_opengl_label) tb.new_row("Client OpenGL", opengl_box) self.opengl_buffering = label() tb.new_row("OpenGL Buffering", self.opengl_buffering) self.server_encodings_label = label() tb.new_row("Server Encodings", self.server_encodings_label) self.client_encodings_label = label() tb.new_row("Client Encodings", self.client_encodings_label) self.server_mmap_icon = gtk.Image() tb.new_row("Memory Mapped Transfers", self.server_mmap_icon) self.server_clipboard_icon = gtk.Image() tb.new_row("Clipboard", self.server_clipboard_icon) self.server_notifications_icon = gtk.Image() tb.new_row("Notification Forwarding", self.server_notifications_icon) self.server_bell_icon = gtk.Image() tb.new_row("Bell Forwarding", self.server_bell_icon) self.server_cursors_icon = gtk.Image() tb.new_row("Cursor Forwarding", self.server_cursors_icon) speaker_box = gtk.HBox(False, 20) self.server_speaker_icon = gtk.Image() speaker_box.add(self.server_speaker_icon) self.speaker_codec_label = label() speaker_box.add(self.speaker_codec_label) tb.new_row("Speaker Forwarding", speaker_box) self.server_speaker_codecs_label = label() tb.new_row("Server Codecs", self.server_speaker_codecs_label) self.client_speaker_codecs_label = label() tb.new_row("Client Codecs", self.client_speaker_codecs_label) microphone_box = gtk.HBox(False, 20) self.server_microphone_icon = gtk.Image() microphone_box.add(self.server_microphone_icon) self.microphone_codec_label = label() microphone_box.add(self.microphone_codec_label) tb.new_row("Microphone Forwarding", microphone_box) self.server_microphone_codecs_label = label() tb.new_row("Server Codecs", self.server_microphone_codecs_label) self.client_microphone_codecs_label = label() tb.new_row("Client Codecs", self.client_microphone_codecs_label) # Connection Table: tb = self.table_tab("connect.png", "Connection", self.populate_connection) tb.new_row("Server Endpoint", label(self.connection.target)) if self.client.server_display: tb.new_row("Server Display", label(self.client.server_display)) if "hostname" in scaps: tb.new_row("Server Hostname", label(scaps.get("hostname"))) if self.client.server_platform: tb.new_row("Server Platform", label(self.client.server_platform)) self.server_load_label = label() tb.new_row("Server Load", self.server_load_label, label_tooltip="Average over 1, 5 and 15 minutes") self.session_started_label = label() tb.new_row("Session Started", self.session_started_label) self.session_connected_label = label() tb.new_row("Session Connected", self.session_connected_label) self.input_packets_label = label() tb.new_row("Packets Received", self.input_packets_label) self.input_bytes_label = label() tb.new_row("Bytes Received", self.input_bytes_label) self.output_packets_label = label() tb.new_row("Packets Sent", self.output_packets_label) self.output_bytes_label = label() tb.new_row("Bytes Sent", self.output_bytes_label) self.compression_label = label() tb.new_row("Compression Level", self.compression_label) self.connection_type_label = label() tb.new_row("Connection Type", self.connection_type_label) self.input_encryption_label = label() tb.new_row("Input Encryption", self.input_encryption_label) self.output_encryption_label = label() tb.new_row("Output Encryption", self.output_encryption_label) self.speaker_label = label() self.speaker_details = label(font="monospace 10") tb.new_row("Speaker", self.speaker_label, self.speaker_details) self.microphone_label = label() tb.new_row("Microphone", self.microphone_label) # Details: tb = self.table_tab("browse.png", "Statistics", self.populate_statistics) tb.widget_xalign = 1.0 tb.attach(title_box(""), 0, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Latest"), 1, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Minimum"), 2, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Average"), 3, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("90 percentile"), 4, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.attach(title_box("Maximum"), 5, xoptions=gtk.EXPAND | gtk.FILL, xpadding=0) tb.inc() def maths_labels(): return label(), label(), label(), label(), label() self.server_latency_labels = maths_labels() tb.add_row(label("Server Latency (ms)"), *self.server_latency_labels) self.client_latency_labels = maths_labels() tb.add_row(label("Client Latency (ms)"), *self.client_latency_labels) if self.client.windows_enabled: if self.client.server_info_request: self.batch_labels = maths_labels() tb.add_row(label("Batch Delay (ms)"), *self.batch_labels) self.damage_labels = maths_labels() tb.add_row(label("Damage Latency (ms)"), *self.damage_labels) self.quality_labels = maths_labels() tb.add_row(label("Encoding Quality (pct)"), *self.quality_labels) self.speed_labels = maths_labels() tb.add_row(label("Encoding Speed (pct)"), *self.speed_labels) self.decoding_labels = maths_labels() tb.add_row(label("Decoding Latency (ms)"), *self.decoding_labels) self.regions_per_second_labels = maths_labels() tb.add_row(label("Regions/s"), *self.regions_per_second_labels) self.regions_sizes_labels = maths_labels() tb.add_row(label("Pixels/region"), *self.regions_sizes_labels) self.pixels_per_second_labels = maths_labels() tb.add_row(label("Pixels/s"), *self.pixels_per_second_labels) self.windows_managed_label = label() tb.new_row("Regular Windows", self.windows_managed_label), self.transient_managed_label = label() tb.new_row("Transient Windows", self.transient_managed_label), self.trays_managed_label = label() tb.new_row("Trays Managed", self.trays_managed_label), if self.client.client_supports_opengl: self.opengl_label = label() tb.new_row("OpenGL Windows", self.opengl_label), self.graph_box = gtk.VBox(False, 10) self.add_tab("statistics.png", "Graphs", self.populate_graphs, self.graph_box) bandwidth_label = "Number of bytes measured by the networks sockets" if SHOW_PIXEL_STATS: bandwidth_label += ",\nand number of pixels rendered" self.bandwidth_graph = self.add_graph_button(bandwidth_label, self.save_graphs) self.latency_graph = self.add_graph_button( "The time it takes to send an echo packet and get the reply", self.save_graphs ) self.pixel_in_data = maxdeque(N_SAMPLES + 4) self.net_in_bytecount = maxdeque(N_SAMPLES + 4) self.net_out_bytecount = maxdeque(N_SAMPLES + 4) self.set_border_width(15) self.add(self.tab_box) if not is_gtk3(): self.set_geometry_hints(self.tab_box) def window_deleted(*args): self.is_closed = True self.connect("delete_event", window_deleted) self.show_tab(self.tabs[0][1]) self.set_size_request(-1, 480) self.populate() self.populate_all() gobject.timeout_add(1000, self.populate) gobject.timeout_add(100, self.populate_tab) self.connect("realize", self.populate_graphs) add_close_accel(self, self.destroy)
def main(): import time import sys assert len(sys.argv) == 2, "usage: %s :DISPLAY" % sys.argv[0] display = sys.argv[1] from xpra.scripts.config import make_defaults_struct opts = make_defaults_struct() from xpra.dotxpra import DotXpra target = DotXpra().socket_path(display) print("will attempt to connect to socket: %s" % target) import socket sock = socket.socket(socket.AF_UNIX) sock.connect(target) from xpra.net.bytestreams import SocketConnection conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(), target, "scroll-test") print("socket connection=%s" % conn) app = ServerMessenger(conn, opts) window = ScrolledWindowExample() from xpra.deque import maxdeque vscroll_events = maxdeque(1000) hscroll_events = maxdeque(1000) def vscroll(scrollbar, scrolltype, value): #print("vscroll(%s) n=%s" % ((scrollbar, scrolltype, value), len(vscroll_events))) now = time.time() needs_reset = False if len(vscroll_events) > 0: #get the previous event t, _ = vscroll_events[-1] #print("last vscroll event was %sms ago" % (now-t)) if now - t < 1: #last event was less than a second ago print("lowering quality to jpeg @ 1%!") app.send("command_request", "encoding", "jpeg", "strict") app.send("command_request", "quality", 1, "*") app.send("command_request", "speed", 100, "*") needs_reset = True vscroll_events.append((now, value)) if needs_reset: def may_reset_quality(*args): #if no new events since, reset quality: t, _ = vscroll_events[-1] if now == t: print("resetting quality to h264") app.send("command_request", "encoding", "h264", "nostrict") app.send("command_request", "quality", -1, "*") #means auto app.send("command_request", "speed", -1, "*") #means auto gobject.timeout_add(1000, may_reset_quality) def hscroll(scrollbar, scrolltype, value): print("hscroll(%s)" % (scrollbar, scrolltype, value)) hscroll_events.append((time.time(), value)) window.vscroll.connect("change-value", vscroll) window.hscroll.connect("change-value", hscroll) try: app.run() finally: app.cleanup()
def __init__(self, conn, opts): XpraClientBase.__init__(self, opts) self.start_time = time.time() self._window_to_id = {} self._id_to_window = {} self._ui_events = 0 self.title = opts.title self.readonly = opts.readonly self.session_name = opts.session_name self.compression_level = opts.compression_level self.auto_refresh_delay = opts.auto_refresh_delay self.max_bandwidth = opts.max_bandwidth if self.max_bandwidth>0.0 and self.jpegquality==0: """ jpegquality was not set, use a better start value """ self.jpegquality = 50 self.dpi = int(opts.dpi) #statistics: self.server_start_time = -1 self.server_platform = "" self.server_actual_desktop_size = None self.server_randr = False self.pixel_counter = maxdeque(maxlen=100) self.server_latency = maxdeque(maxlen=100) self.server_load = None self.client_latency = maxdeque(maxlen=100) self.last_ping_echoed_time = 0 #features: self.toggle_cursors_bell_notify = False self.toggle_keyboard_sync = False self.window_configure = False self._client_extras = ClientExtras(self, opts) self.client_supports_notifications = opts.notifications and self._client_extras.can_notify() self.client_supports_clipboard = opts.clipboard and self._client_extras.supports_clipboard() and not self.readonly self.client_supports_cursors = opts.cursors self.client_supports_bell = opts.bell self.client_supports_sharing = opts.sharing self.notifications_enabled = self.client_supports_notifications self.clipboard_enabled = self.client_supports_clipboard self.cursors_enabled = self.client_supports_cursors self.bell_enabled = self.client_supports_bell #mmap: self.mmap_enabled = False self.mmap = None self.mmap_token = None self.mmap_file = None self.mmap_size = 0 self.supports_mmap = opts.mmap and ("rgb24" in ENCODINGS) and self._client_extras.supports_mmap() if self.supports_mmap: self.init_mmap(opts.mmap_group, conn.filename) self.init_packet_handlers() self.ready(conn) #keyboard: self.keyboard_sync = opts.keyboard_sync self.key_repeat_delay = -1 self.key_repeat_interval = -1 self.keys_pressed = {} self._remote_version = None self._keymap_changing = False try: self._keymap = gdk.keymap_get_default() except: self._keymap = None self._do_keys_changed() self.key_shortcuts = self.parse_shortcuts(opts.key_shortcuts) log.info("xpra client version %s" % __version__) self.send_hello() if self._keymap: self._keymap.connect("keys-changed", self._keys_changed) self._focused = None def compute_receive_bandwidth(delay): bytecount = self._protocol.input_bytecount bw = ((bytecount - self.last_input_bytecount) / 1024) * 1000 / delay self.last_input_bytecount = bytecount; log.debug("Bandwidth is ", bw, "kB/s, max ", self.max_bandwidth, "kB/s") q = self.jpegquality if bw > self.max_bandwidth: q -= 10 elif bw < self.max_bandwidth: q += 5 q = max(10, min(95 ,q)) self.send_jpeg_quality(q) return True if (self.max_bandwidth): self.last_input_bytecount = 0 gobject.timeout_add(2000, compute_receive_bandwidth, 2000) if opts.send_pings: gobject.timeout_add(1000, self.send_ping) else: gobject.timeout_add(20*1000, self.send_ping)
def __init__(self, conn, opts): XpraClientBase.__init__(self, opts) self.start_time = time.time() self._window_to_id = {} self._id_to_window = {} self.title = opts.title self.readonly = opts.readonly self.session_name = opts.session_name self.compression_level = opts.compression_level self.auto_refresh_delay = opts.auto_refresh_delay self.max_bandwidth = opts.max_bandwidth if self.max_bandwidth > 0.0 and self.jpegquality == 0: """ jpegquality was not set, use a better start value """ self.jpegquality = 50 self.dpi = int(opts.dpi) #statistics: self.server_start_time = -1 self.server_platform = "" self.server_actual_desktop_size = None self.server_randr = False self.pixel_counter = maxdeque(maxlen=100) self.server_latency = maxdeque(maxlen=100) self.server_load = None self.client_latency = maxdeque(maxlen=100) self.last_ping_echoed_time = 0 #features: self.toggle_cursors_bell_notify = False self.toggle_keyboard_sync = False self.window_configure = False self._client_extras = ClientExtras(self, opts) self.client_supports_notifications = opts.notifications and self._client_extras.can_notify( ) self.client_supports_clipboard = opts.clipboard and self._client_extras.supports_clipboard( ) and not self.readonly self.client_supports_cursors = opts.cursors self.client_supports_bell = opts.bell self.notifications_enabled = self.client_supports_notifications self.clipboard_enabled = self.client_supports_clipboard self.cursors_enabled = self.client_supports_cursors self.bell_enabled = self.client_supports_bell #mmap: self.mmap_enabled = False self.mmap = None self.mmap_token = None self.mmap_file = None self.mmap_size = 0 self.supports_mmap = opts.mmap and ( "rgb24" in ENCODINGS) and self._client_extras.supports_mmap() if self.supports_mmap: self.init_mmap(opts.mmap_group, conn.filename) self.init_packet_handlers() self.ready(conn) #keyboard: self.keyboard_sync = opts.keyboard_sync self.key_repeat_delay = -1 self.key_repeat_interval = -1 self.keys_pressed = {} self._remote_version = None self._keymap_changing = False try: self._keymap = gdk.keymap_get_default() except: self._keymap = None self._do_keys_changed() self.key_shortcuts = self.parse_shortcuts(opts.key_shortcuts) self.send_hello() if self._keymap: self._keymap.connect("keys-changed", self._keys_changed) self._focused = None def compute_receive_bandwidth(delay): bytecount = self._protocol.input_bytecount bw = ( (bytecount - self.last_input_bytecount) / 1024) * 1000 / delay self.last_input_bytecount = bytecount log.debug("Bandwidth is ", bw, "kB/s, max ", self.max_bandwidth, "kB/s") q = self.jpegquality if bw > self.max_bandwidth: q -= 10 elif bw < self.max_bandwidth: q += 5 q = max(10, min(95, q)) self.send_jpeg_quality(q) return True if (self.max_bandwidth): self.last_input_bytecount = 0 gobject.timeout_add(2000, compute_receive_bandwidth, 2000) if opts.send_pings: gobject.timeout_add(1000, self.send_ping) else: gobject.timeout_add(20 * 1000, self.send_ping)
class SessionInfo(gtk.Window): def __init__(self, client, session_name, window_icon_pixbuf, conn, get_pixbuf): gtk.Window.__init__(self) self.client = client self.session_name = session_name self.connection = conn self.last_populate_time = 0 self.last_populate_statistics = 0 self.is_closed = False self.get_pixbuf = get_pixbuf if not self.session_name or self.session_name=="Xpra": title = "Session Info" else: title = "%s: Session Info" % self.session_name self.set_title(title) self.set_destroy_with_parent(True) self.set_resizable(True) self.set_decorated(True) if window_icon_pixbuf: self.set_icon(window_icon_pixbuf) self.set_position(WIN_POS_CENTER) #tables on the left in a vbox with buttons at the top: self.tab_box = gtk.VBox(False, 0) self.tab_button_box = gtk.HBox(True, 0) self.tabs = [] #pairs of button, table self.populate_cb = None self.tab_box.pack_start(self.tab_button_box, expand=False, fill=True, padding=0) #Package Table: tb, _ = self.table_tab("package.png", "Software", self.populate_package) #title row: tb.attach(title_box(""), 0, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Client"), 1, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Server"), 2, xoptions=EXPAND|FILL, xpadding=0) tb.inc() def make_os_str(*args): s = os_info(*args) return "\n".join(s) distro = "" if hasattr(python_platform, "linux_distribution"): distro = python_platform.linux_distribution() LOCAL_PLATFORM_NAME = make_os_str(sys.platform, python_platform.release(), python_platform.platform(), distro) SERVER_PLATFORM_NAME = make_os_str(self.client._remote_platform, self.client._remote_platform_release, self.client._remote_platform_platform, self.client._remote_platform_linux_distribution) tb.new_row("Operating System", label(LOCAL_PLATFORM_NAME), label(SERVER_PLATFORM_NAME)) scaps = self.client.server_capabilities from xpra.__init__ import __version__ tb.new_row("Xpra", label(__version__), label(self.client._remote_version or "unknown")) cl_rev, cl_ch, cl_date = "unknown", "", "" try: from xpra.build_info import BUILD_DATE as cl_date, BUILD_TIME as cl_time from xpra.src_info import REVISION as cl_rev, LOCAL_MODIFICATIONS as cl_ch #@UnresolvedImport except: pass def make_version_str(version): if version and type(version) in (tuple, list): version = ".".join([str(x) for x in version]) return version or "unknown" def server_info(*prop_names): for x in prop_names: v = scaps.capsget(x) if v is not None: return v if self.client.server_last_info: v = self.client.server_last_info.get(x) if v is not None: return v return None def server_version_info(*prop_names): return make_version_str(server_info(*prop_names)) def make_revision_str(rev, changes): if not changes: return rev return "%s (%s changes)" % (rev, changes) def make_datetime(date, time): if not time: return date return "%s %s" % (date, time) tb.new_row("Revision", label(make_revision_str(cl_rev, cl_ch)), label(make_revision_str(self.client._remote_revision, server_version_info("build.local_modifications", "local_modifications")))) tb.new_row("Build date", label(make_datetime(cl_date, cl_time)), label(make_datetime(server_info("build_date", "build.date"), server_info("build.time")))) gtk_version_info = get_gtk_version_info() def client_vinfo(prop, fallback="unknown"): k = "%s.version" % prop return label(make_version_str(gtk_version_info.get(k, fallback))) tb.new_row("Glib", client_vinfo("glib"), label(server_version_info("glib.version"))) tb.new_row("Gobject", client_vinfo("gobject"), label(server_version_info("gobject.version", "pygtk_version"))) tb.new_row("PyGTK", client_vinfo("pygtk", ""), label(server_version_info("pygtk.version", "pygtk_version"))) tb.new_row("GTK", client_vinfo("gtk"), label(server_version_info("gtk.version", "gtk_version"))) tb.new_row("GDK", client_vinfo("gdk"), label(server_version_info("gdk.version", "gdk_version"))) tb.new_row("Cairo", client_vinfo("cairo"), label(server_version_info("cairo.version", "cairo_version"))) tb.new_row("Pango", client_vinfo("pango"), label(server_version_info("pango.version", "cairo_version"))) tb.new_row("Python", label(python_platform.python_version()), label(server_version_info("server.python.version", "python_version", "python.version"))) cl_gst_v, cl_pygst_v = "", "" try: from xpra.sound.gstreamer_util import gst_version as cl_gst_v, pygst_version as cl_pygst_v except Exception, e: log("cannot load gstreamer: %s", e) tb.new_row("GStreamer", label(make_version_str(cl_gst_v)), label(server_version_info("sound.gst.version", "gst_version"))) tb.new_row("pygst", label(make_version_str(cl_pygst_v)), label(server_version_info("sound.pygst.version", "pygst_version"))) tb.new_row("OpenGL", label(make_version_str(self.client.opengl_props.get("opengl", "n/a"))), label("n/a")) tb.new_row("OpenGL Vendor", label(make_version_str(self.client.opengl_props.get("vendor", ""))), label("n/a")) tb.new_row("PyOpenGL", label(make_version_str(self.client.opengl_props.get("pyopengl", "n/a"))), label("n/a")) # Features Table: vbox = self.vbox_tab("features.png", "Features", self.populate_features) #add top table: tb = TableBuilder(rows=1, columns=2) table = tb.get_table() al = gtk.Alignment(xalign=0.5, yalign=0.5, xscale=0.0, yscale=1.0) al.add(table) vbox.pack_start(al, expand=True, fill=False, padding=10) #top table contents: randr_box = gtk.HBox(False, 20) self.server_randr_label = label() self.server_randr_icon = gtk.Image() randr_box.add(self.server_randr_icon) randr_box.add(self.server_randr_label) tb.new_row("RandR Support", randr_box) opengl_box = gtk.HBox(False, 20) self.client_opengl_label = label() self.client_opengl_label.set_line_wrap(True) self.client_opengl_icon = gtk.Image() opengl_box.add(self.client_opengl_icon) opengl_box.add(self.client_opengl_label) tb.new_row("Client OpenGL", opengl_box) self.opengl_buffering = label() tb.new_row("OpenGL Buffering", self.opengl_buffering) self.server_mmap_icon = gtk.Image() tb.new_row("Memory Mapped Transfers", self.server_mmap_icon) self.server_clipboard_icon = gtk.Image() tb.new_row("Clipboard", self.server_clipboard_icon) self.server_notifications_icon = gtk.Image() tb.new_row("Notification Forwarding", self.server_notifications_icon) self.server_bell_icon = gtk.Image() tb.new_row("Bell Forwarding", self.server_bell_icon) self.server_cursors_icon = gtk.Image() tb.new_row("Cursor Forwarding", self.server_cursors_icon) speaker_box = gtk.HBox(False, 20) self.server_speaker_icon = gtk.Image() speaker_box.add(self.server_speaker_icon) self.speaker_codec_label = label() speaker_box.add(self.speaker_codec_label) tb.new_row("Speaker Forwarding", speaker_box) microphone_box = gtk.HBox(False, 20) self.server_microphone_icon = gtk.Image() microphone_box.add(self.server_microphone_icon) self.microphone_codec_label = label() microphone_box.add(self.microphone_codec_label) tb.new_row("Microphone Forwarding", microphone_box) #add bottom table: tb = TableBuilder(rows=1, columns=3) table = tb.get_table() vbox.pack_start(table, expand=True, fill=True, padding=20) #bottom table headings: tb.attach(title_box(""), 0, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Client"), 1, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Server"), 2, xoptions=EXPAND|FILL, xpadding=0) tb.inc() #bottom table contents: self.client_encodings_label = label() self.client_encodings_label.set_line_wrap(True) self.client_encodings_label.set_size_request(250, -1) self.server_encodings_label = label() self.server_encodings_label.set_line_wrap(True) self.server_encodings_label.set_size_request(250, -1) tb.new_row("Encodings", self.client_encodings_label, self.server_encodings_label) self.client_speaker_codecs_label = label() self.server_speaker_codecs_label = label() tb.new_row("Speaker Codecs", self.client_speaker_codecs_label, self.server_speaker_codecs_label) self.client_microphone_codecs_label = label() self.server_microphone_codecs_label = label() tb.new_row("Microphone Codecs", self.client_microphone_codecs_label, self.server_microphone_codecs_label) self.client_packet_encoders_label = label() self.server_packet_encoders_label = label() tb.new_row("Packet Encoders", self.client_packet_encoders_label, self.server_packet_encoders_label) self.client_packet_compressors_label = label() self.server_packet_compressors_label = label() tb.new_row("Packet Compressors", self.client_packet_compressors_label, self.server_packet_compressors_label) # Connection Table: tb, _ = self.table_tab("connect.png", "Connection", self.populate_connection) tb.new_row("Server Endpoint", label(self.connection.target)) if self.client.server_display: tb.new_row("Server Display", label(self.client.server_display)) hostname = scaps.strget("hostname") if hostname: tb.new_row("Server Hostname", label(hostname)) if self.client.server_platform: tb.new_row("Server Platform", label(self.client.server_platform)) self.server_load_label = label() tb.new_row("Server Load", self.server_load_label, label_tooltip="Average over 1, 5 and 15 minutes") self.session_started_label = label() tb.new_row("Session Started", self.session_started_label) self.session_connected_label = label() tb.new_row("Session Connected", self.session_connected_label) self.input_packets_label = label() tb.new_row("Packets Received", self.input_packets_label) self.input_bytes_label = label() tb.new_row("Bytes Received", self.input_bytes_label) self.output_packets_label = label() tb.new_row("Packets Sent", self.output_packets_label) self.output_bytes_label = label() tb.new_row("Bytes Sent", self.output_bytes_label) self.compression_label = label() tb.new_row("Compression + Encoding", self.compression_label) self.connection_type_label = label() tb.new_row("Connection Type", self.connection_type_label) self.input_encryption_label = label() tb.new_row("Input Encryption", self.input_encryption_label) self.output_encryption_label = label() tb.new_row("Output Encryption", self.output_encryption_label) self.speaker_label = label() self.speaker_details = label(font="monospace 10") tb.new_row("Speaker", self.speaker_label, self.speaker_details) self.microphone_label = label() tb.new_row("Microphone", self.microphone_label) # Details: tb, stats_box = self.table_tab("browse.png", "Statistics", self.populate_statistics) tb.widget_xalign = 1.0 tb.attach(title_box(""), 0, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Latest"), 1, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Minimum"), 2, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Average"), 3, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("90 percentile"), 4, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Maximum"), 5, xoptions=EXPAND|FILL, xpadding=0) tb.inc() def maths_labels(): return label(), label(), label(), label(), label() self.server_latency_labels = maths_labels() tb.add_row(label("Server Latency (ms)", "The time it takes for the server to respond to pings"), *self.server_latency_labels) self.client_latency_labels = maths_labels() tb.add_row(label("Client Latency (ms)", "The time it takes for the client to respond to pings, as measured by the server"), *self.client_latency_labels) if self.client.windows_enabled: if self.client.server_info_request: self.batch_labels = maths_labels() tb.add_row(label("Batch Delay (ms)", "How long the server waits for new screen updates to accumulate before processing them"), *self.batch_labels) self.damage_labels = maths_labels() tb.add_row(label("Damage Latency (ms)", "The time it takes to compress a frame and pass it to the OS network layer"), *self.damage_labels) self.quality_labels = maths_labels() tb.add_row(label("Encoding Quality (pct)"), *self.quality_labels) self.speed_labels = maths_labels() tb.add_row(label("Encoding Speed (pct)"), *self.speed_labels) self.decoding_labels = maths_labels() tb.add_row(label("Decoding Latency (ms)", "How long it takes the client to decode a screen update"), *self.decoding_labels) self.regions_per_second_labels = maths_labels() tb.add_row(label("Regions/s", "The number of screen updates per second (includes both partial and full screen updates)"), *self.regions_per_second_labels) self.regions_sizes_labels = maths_labels() tb.add_row(label("Pixels/region", "The number of pixels per screen update"), *self.regions_sizes_labels) self.pixels_per_second_labels = maths_labels() tb.add_row(label("Pixels/s", "The number of pixels processed per second"), *self.pixels_per_second_labels) #Window count stats: wtb = TableBuilder() stats_box.add(wtb.get_table()) #title row: wtb.attach(title_box(""), 0, xoptions=EXPAND|FILL, xpadding=0) wtb.attach(title_box("Regular"), 1, xoptions=EXPAND|FILL, xpadding=0) wtb.attach(title_box("Transient"), 2, xoptions=EXPAND|FILL, xpadding=0) wtb.attach(title_box("Trays"), 3, xoptions=EXPAND|FILL, xpadding=0) if self.client.client_supports_opengl: wtb.attach(title_box("OpenGL"), 4, xoptions=EXPAND|FILL, xpadding=0) wtb.inc() wtb.attach(label("Windows:"), 0, xoptions=EXPAND|FILL, xpadding=0) self.windows_managed_label = label() wtb.attach(self.windows_managed_label, 1) self.transient_managed_label = label() wtb.attach(self.transient_managed_label, 2) self.trays_managed_label = label() wtb.attach(self.trays_managed_label, 3) if self.client.client_supports_opengl: self.opengl_label = label() wtb.attach(self.opengl_label, 4) #add encoder info: etb = TableBuilder() stats_box.add(etb.get_table()) self.encoder_info_box = gtk.HBox(spacing=4) etb.new_row("Window Encoders", self.encoder_info_box) if not is_gtk3(): #needs porting to cairo... self.graph_box = gtk.VBox(False, 10) self.add_tab("statistics.png", "Graphs", self.populate_graphs, self.graph_box) bandwidth_label = "Bandwidth used" if SHOW_PIXEL_STATS: bandwidth_label += ",\nand number of pixels rendered" self.bandwidth_graph = self.add_graph_button(bandwidth_label, self.save_graphs) self.connect("realize", self.populate_graphs) self.latency_graph = self.add_graph_button(None, self.save_graphs) self.pixel_in_data = maxdeque(N_SAMPLES+4) self.net_in_bytecount = maxdeque(N_SAMPLES+4) self.net_out_bytecount = maxdeque(N_SAMPLES+4) self.set_border_width(15) self.add(self.tab_box) if not is_gtk3(): self.set_geometry_hints(self.tab_box) def window_deleted(*args): self.is_closed = True self.connect('delete_event', window_deleted) self.show_tab(self.tabs[0][2]) self.set_size_request(-1, 480) self.init_counters() self.populate() self.populate_all() gobject.timeout_add(1000, self.populate) gobject.timeout_add(100, self.populate_tab) add_close_accel(self, self.destroy)
def main(): if "-v" in sys.argv or "--verbose" in sys.argv: log.enable_debug() sslog.enable_debug() log("main()") def refresh_cb(window, regions): log("refresh_cb(%s, %s)", window, regions) r = VideoSubregion(gobject.timeout_add, gobject.source_remove, refresh_cb, 150) ww = 1024 wh = 768 log.info("* checking that we need some events") last_damage_events = [] for x in range(MIN_EVENTS): last_damage_events.append((0, 0, 0, 1, 1)) r.identify_video_subregion(ww, wh, MIN_EVENTS, last_damage_events) assert r.rectangle is None vr = (time.time(), 100, 100, 320, 240) log.info("* easiest case: all updates in one region") last_damage_events = [] for _ in range(50): last_damage_events.append(vr) r.identify_video_subregion(ww, wh, 50, last_damage_events) assert r.rectangle assert r.rectangle==rectangle(*vr[1:]) log.info("* checking that empty damage events does not cause errors") r.reset() r.identify_video_subregion(ww, wh, 0, []) assert r.rectangle is None log.info("* checking that full window is not a region") vr = (time.time(), 0, 0, ww, wh) last_damage_events = [] for _ in range(50): last_damage_events.append(vr) r.identify_video_subregion(ww, wh, 50, last_damage_events) assert r.rectangle is None log.info("* checking that regions covering the whole window give the same result") last_damage_events = maxdeque(150) for x in range(4): for y in range(4): vr = (time.time(), ww*x/4, wh*y/4, ww/4, wh/4) last_damage_events.append(vr) last_damage_events.append(vr) last_damage_events.append(vr) r.identify_video_subregion(ww, wh, 150, last_damage_events) assert r.rectangle is None vr = (time.time(), ww/4, wh/4, ww/2, wh/2) log.info("* mixed with region using 1/5 of window and 1/3 of updates: %s", vr) for _ in range(30): last_damage_events.append(vr) r.identify_video_subregion(ww, wh, 200, last_damage_events) assert r.rectangle is not None log.info("* info=%s", r.get_info()) log.info("* checking that two video regions with the same characteristics get merged") last_damage_events = maxdeque(150) r.reset() v1 = (time.time(), 100, 100, 320, 240) v2 = (time.time(), 500, 500, 320, 240) for _ in range(50): last_damage_events.append(v1) last_damage_events.append(v2) r.identify_video_subregion(ww, wh, 100, last_damage_events) m = merge_all([rectangle(*v1[1:]), rectangle(*v2[1:])]) assert r.rectangle==m, "expected %s but got %s" % (m, r.rectangle) log.info("* but not if they are too far apart") last_damage_events = maxdeque(150) r.reset() v1 = (time.time(), 20, 20, 320, 240) v2 = (time.time(), ww-20-320, wh-240-20, 320, 240) for _ in range(50): last_damage_events.append(v1) last_damage_events.append(v2) r.identify_video_subregion(ww, wh, 100, last_damage_events) assert r.rectangle is None
def main(): import time import sys assert len(sys.argv)==2, "usage: %s :DISPLAY" % sys.argv[0] display = sys.argv[1] from xpra.scripts.config import make_defaults_struct opts = make_defaults_struct() from xpra.dotxpra import DotXpra target = DotXpra().socket_path(display) print("will attempt to connect to socket: %s" % target) import socket sock = socket.socket(socket.AF_UNIX) sock.connect(target) from xpra.net.bytestreams import SocketConnection conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(), target, "scroll-test") print("socket connection=%s" % conn) app = ServerMessenger(conn, opts) window = ScrolledWindowExample() from xpra.deque import maxdeque vscroll_events = maxdeque(1000) hscroll_events = maxdeque(1000) def vscroll(scrollbar, scrolltype, value): #print("vscroll(%s) n=%s" % ((scrollbar, scrolltype, value), len(vscroll_events))) now = time.time() needs_reset = False if len(vscroll_events)>0: #get the previous event t, _ = vscroll_events[-1] #print("last vscroll event was %sms ago" % (now-t)) if now-t<1: #last event was less than a second ago print("lowering quality to jpeg @ 1%!") app.send("command_request", "encoding", "jpeg", "strict") app.send("command_request", "quality", 1, "*") app.send("command_request", "speed", 100, "*") needs_reset = True vscroll_events.append((now, value)) if needs_reset: def may_reset_quality(*args): #if no new events since, reset quality: t, _ = vscroll_events[-1] if now==t: print("resetting quality to h264") app.send("command_request", "encoding", "h264", "nostrict") app.send("command_request", "quality", -1, "*") #means auto app.send("command_request", "speed", -1, "*") #means auto gobject.timeout_add(1000, may_reset_quality) def hscroll(scrollbar, scrolltype, value): print("hscroll(%s)" % (scrollbar, scrolltype, value)) hscroll_events.append((time.time(), value)) window.vscroll.connect("change-value", vscroll) window.hscroll.connect("change-value", hscroll) try: app.run() finally: app.cleanup()