xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #486: info-namespace-v2.patch

File info-namespace-v2.patch, 111.0 KB (added by Antoine Martin, 5 years ago)

updated patch

  • xpra/child_reaper.py

     
    1212import os, sys
    1313import signal
    1414
    15 from xpra.util import updict
    1615from xpra.log import Logger
    1716log = Logger("server", "util")
    1817
     
    186185
    187186    def get_info(self):
    188187        iv = list(self._proc_info)
    189         info = {"children"          : len(iv),
    190                 "children.dead"     : len([x for x in iv if x.dead]),
    191                 "children.ignored"  : len([x for x in iv if x.ignore])}
     188        info = {"children"  : {""           : len(iv),
     189                               "dead"       : len([x for x in iv if x.dead]),
     190                               "ignored"    : len([x for x in iv if x.ignore])}}
    192191        pi = sorted(self._proc_info, key=lambda x: x.pid, reverse=True)
     192        cinfo = {}
    193193        for i, procinfo in enumerate(pi):
    194             d = dict((k,getattr(procinfo,k)) for k in ("name", "command", "ignore", "forget", "returncode", "dead", "pid"))
    195             updict(info, "child[%i]" % i, d)
     194            d = {}
     195            for k in ("name", "command", "ignore", "forget", "returncode", "dead", "pid"):
     196                v = getattr(procinfo, k)
     197                if v is None:
     198                    continue
     199                d[k] = v
     200            cinfo[i] = d
     201        info["child"] = cinfo
    196202        return info
  • xpra/client/gl/gtk_compat.py

     
    2727
    2828    def get_info():
    2929        return {
    30                 "gdkgl.version"         : GdkGLExt._version,
    31                 "gtkgl.version"         : GtkGLExt._version,
     30                "gdkgl"     : {"version"    : GdkGLExt._version},
     31                "gtkgl"     : {"version"    : GtkGLExt._version},
    3232                }
    3333    gdkgl = GdkGLExt
    3434    gtkgl = GtkGLExt
     
    7474        return None
    7575
    7676    def get_info():
     77        def v(x):
     78            return {"version" : x}
    7779        return {
    78                  "pygdkglext.version"   : gdkgl.pygdkglext_version,
    79                  "gtkglext.version"     : gtkgl.gtkglext_version,
    80                  "gdkglext.version"     : gdkgl.gdkglext_version,
    81                  "gdkgl.version"        : gdkgl.query_version()
     80                 "pygdkglext"   : v(gdkgl.pygdkglext_version),
     81                 "gtkglext"     : v(gtkgl.gtkglext_version),
     82                 "gdkglext"     : v(gdkgl.gdkglext_version),
     83                 "gdkgl"        : v(gdkgl.query_version())
    8284                 }
    8385
    8486    class GLContextManager(object):
  • xpra/client/gtk_base/bug_report.py

     
    1818
    1919from xpra.gtk_common.gtk_util import gtk_main, add_close_accel, scaled_image, pixbuf_new_from_file, get_display_info, \
    2020                                    JUSTIFY_LEFT, WIN_POS_CENTER, STATE_NORMAL, FILE_CHOOSER_ACTION_SAVE, choose_file, get_gtk_version_info
    21 from xpra.util import nonl, updict, strtobytes
     21from xpra.util import nonl, strtobytes
    2222from xpra.log import Logger
    2323log = Logger("util")
    2424
     
    136136                    "env"           : os.environ,
    137137                    "config"        : read_xpra_defaults(),
    138138                    }.items():
    139                 updict(d, k, v)
     139                d[k] = v
    140140            return d
    141141        get_screenshot, take_screenshot_fn = None, None
    142142        #screenshot: may have OS-specific code
  • xpra/client/gtk_base/session_info.py

     
    6767    elapsed = now-startt
    6868    return int(total/elapsed), total_n/elapsed, mins, avgs, maxs
    6969
     70def dictlook(d, k, fallback=None):
     71    #deal with old-style non-namespaced dicts first:
     72    #"batch.delay.avg"
     73    if d is None:
     74        return fallback
     75    v = d.get(k)
     76    if v is not None:
     77        return v
     78    parts = k.split(".")
     79    #["batch", "delay", "avg"]
     80    v = d
     81    for p in parts:
     82        try:
     83            v = v.get(p)
     84        except:
     85            return fallback
     86    return v
    7087
     88
    7189class SessionInfo(gtk.Window):
    7290
    7391    def __init__(self, client, session_name, window_icon_pixbuf, conn, get_pixbuf):
     
    135153            return version or "unknown"
    136154        def server_info(*prop_names):
    137155            for x in prop_names:
    138                 v = scaps.capsget(x)
     156                v = dictlook(scaps, x)
    139157                if v is not None:
    140158                    return v
    141                 if self.client.server_last_info:
    142                     v = self.client.server_last_info.get(x)
     159                v = dictlook(self.client.server_last_info, x)
    143160                if v is not None:
    144161                    return v
    145162            return None
     
    160177        gtk_version_info = get_gtk_version_info()
    161178        def client_vinfo(prop, fallback="unknown"):
    162179            k = "%s.version" % prop
    163             return label(make_version_str(gtk_version_info.get(k, fallback)))
     180            return label(make_version_str(dictlook(gtk_version_info, k, fallback)))
    164181        def server_vinfo(prop):
    165182            k = "%s.version" % prop
    166183            fk = "%s_version" % prop
     
    521538            info = ss.get_info()
    522539            if info:
    523540                info = typedict(info)
    524                 self.sound_out_queue_cur.append(info.intget("queue.cur"))
    525                 self.sound_out_queue_min.append(info.intget("queue.min"))
    526                 self.sound_out_queue_max.append(info.intget("queue.max"))
     541                def intlookup(k):
     542                    return int(dictlook(info, k, 0))
     543                self.sound_out_queue_cur.append(intlookup("queue.cur"))
     544                self.sound_out_queue_min.append(intlookup("queue.min"))
     545                self.sound_out_queue_max.append(intlookup("queue.max"))
    527546        return not self.is_closed
    528547
    529548    def populate(self, *args):
     
    574593        if self.client.server_last_info:
    575594            #populate running averages for graphs:
    576595            def getavg(name):
    577                 return self.client.server_last_info.get("%s.avg" % name)
     596                return dictlook(self.client.server_last_info, "%s.avg" % name)
    578597            def addavg(l, name):
    579598                v = getavg(name)
    580599                if v:
     
    780799            return ""
    781800        altv = ""
    782801        if alt:
    783             altv = self.client.server_last_info.get((alt+"."+suffix).encode(), "")
    784         return self.client.server_last_info.get((prefix+"."+suffix).encode(), altv)
     802            altv = dictlook(self.client.server_last_info, (alt+"."+suffix).encode(), "")
     803        return dictlook(self.client.server_last_info, (prefix+"."+suffix).encode(), altv)
    785804
    786805    def values_from_info(self, prefix, alt=None):
    787806        def getv(suffix):
     
    799818            values = []
    800819            for wid in self.client._window_to_id.values():
    801820                for window_prop in window_props:
    802                     v = self.client.server_last_info.get("window[%s].%s.%s" % (wid, window_prop, suffix))
     821                    v = dictlook(self.client.server_last_info, "window[%s].%s.%s" % (wid, window_prop, suffix))
    803822                    if v is not None:
    804823                        values.append(v)
    805824                        break
     
    903922            #remove all the current labels:
    904923            for x in self.encoder_info_box.get_children():
    905924                self.encoder_info_box.remove(x)
    906             window_encoder_stats = {}
    907925            if self.client.server_last_info:
    908                 #We are interested in data like:
    909                 #window[1].encoder=x264
    910                 #window[1].encoder.frames=1
    911                 #window[1].encoder.fps=25
    912                 for k,v in self.client.server_last_info.items():
    913                     k = bytestostr(k)
    914                     if not k.startswith("window["):
    915                         continue
    916                     pos = k.find("].encoder")
    917                     if pos<=0:
    918                         continue
    919                     try:
    920                         wid_str = k[len("window["):pos]     #ie: "1"
    921                         wid = int(wid_str)
    922                     except:
    923                         #wid_str may be invalid, ie:
    924                         #window[1].pipeline_option[1].encoder=video_spec(xpra.codecs.enc_x264.encoder.Encoder)
    925                         # -> wid_str= "1].pipeline_option[1"
    926                         continue
    927                     ekey = k[(pos+len("].encoder")):]   #ie: "" or ".frames"
    928                     if ekey.startswith("."):
    929                         ekey = ekey[1:]
    930                     if ekey=="build_config":
    931                         continue
    932                     window_encoder_stats.setdefault(wid, {})[ekey] = v
    933                 #print("window_encoder_stats=%s" % window_encoder_stats)
     926                window_encoder_stats = self.get_window_encoder_stats()
     927                #log("window_encoder_stats=%s", window_encoder_stats)
    934928                for wid, props in window_encoder_stats.items():
    935929                    l = label("%s (%s)" % (wid, bytestostr(props.get(""))))
    936930                    l.show()
     
    939933                    self.encoder_info_box.add(l)
    940934        return True
    941935
     936    def get_window_encoder_stats(self):
     937        window_encoder_stats = {}
     938        #new-style server with namespace:
     939        window_dict = self.client.server_last_info.get("window")
     940        log.warn("window_dict=%s", window_dict)
     941        if window_dict and isinstance(window_dict, dict):
     942            for k,v in window_dict.items():
     943                try:
     944                    wid = int(k)
     945                    encoder_stats = v.get("encoder")
     946                    if encoder_stats:
     947                        window_encoder_stats[wid] = encoder_stats
     948                except:
     949                    pass
     950            return window_encoder_stats
     951        #fallback code, we are interested in string data like:
     952        #window[1].encoder=x264
     953        #window[1].encoder.frames=1
     954        #window[1].encoder.fps=25
     955        for k,v in self.client.server_last_info.items():
     956            k = bytestostr(k)
     957            if not k.startswith("window["):
     958                continue
     959            pos = k.find("].encoder")
     960            if pos<=0:
     961                continue
     962            try:
     963                wid_str = k[len("window["):pos]     #ie: "1"
     964                wid = int(wid_str)
     965            except:
     966                #wid_str may be invalid, ie:
     967                #window[1].pipeline_option[1].encoder=video_spec(xpra.codecs.enc_x264.encoder.Encoder)
     968                # -> wid_str= "1].pipeline_option[1"
     969                continue
     970            ekey = k[(pos+len("].encoder")):]   #ie: "" or ".frames"
     971            if ekey.startswith("."):
     972                ekey = ekey[1:]
     973            if ekey=="build_config":
     974                continue
     975            window_encoder_stats.setdefault(wid, {})[ekey] = v
     976        return window_encoder_stats
     977
     978
    942979    def populate_graphs(self, *args):
    943980        if self.client.server_info_request:
    944981            self.client.send_info_request()
  • xpra/client/ui_client_base.py

     
    14041404            "windows"                   : self.windows_enabled,
    14051405            "show-desktop"              : True,
    14061406            "system_tray"               : self.client_supports_system_tray,
     1407            "info-namespace"            : True,
    14071408            #window meta data and handling:
    14081409            "generic_window_types"      : True,
    14091410            "server-window-move-resize" : True,
     
    24202421            ss.add_data(data, metadata)
    24212422        if self.av_sync and self.server_av_sync:
    24222423            info = ss.get_info()
    2423             queue_used = info.get("queue.cur")
     2424            queue_used = info.get("queue.cur") or info.get("queue", {}).get("cur")
    24242425            if queue_used is None:
    24252426                return
    24262427            delta = (self.queue_used_sent or 0)-queue_used
  • xpra/clipboard/clipboard_base.py

     
    2323from xpra.gtk_common.gtk_util import GetClipboard, PROPERTY_CHANGE_MASK
    2424from xpra.gtk_common.nested_main import NestedMainLoop
    2525from xpra.net.compression import Uncompressed
    26 from xpra.util import csv
     26from xpra.util import csv, updict
    2727
    2828
    2929MIN_CLIPBOARD_COMPRESSION_SIZE = 512
     
    9191                "want_targets"  : self._want_targets,
    9292                }
    9393        for clipboard, proxy in self._clipboard_proxies.items():
    94             for k,v in proxy.get_info().items():
    95                 info["%s.%s" % (clipboard, k)] = v
     94            info[clipboard] = proxy.get_info()
    9695        return info
    9796
    9897    def cleanup(self):
     
    463462                "enabled"       : self._enabled,
    464463                "greedy_client" : self._greedy_client,
    465464                "blocked_owner_change" : self._block_owner_change,
    466                 "event.selection_request"   : self._selection_request_events,
    467                 "event.selection_get"       : self._selection_get_events,
    468                 "event.selection_clear"     : self._selection_clear_events,
    469                 "event.got_token"           : self._got_token_events,
    470                 "event.sent_token"          : self._sent_token_events,
    471                 "event.get_contents"        : self._get_contents_events,
    472                 "event.request_contents"    : self._request_contents_events,
    473465                }
     466        updict(info, "event", {
     467                "selection_request"     : self._selection_request_events,
     468                "selection_get"         : self._selection_get_events,
     469                "selection_clear"       : self._selection_clear_events,
     470                "got_token"             : self._got_token_events,
     471                "sent_token"            : self._sent_token_events,
     472                "get_contents"          : self._get_contents_events,
     473                "request_contents"      : self._request_contents_events})
    474474        return info
    475475
    476476    def cleanup(self):
  • xpra/codecs/csc_opencl/colorspace_converter.py

     
    1313import pyopencl             #@UnresolvedImport
    1414from pyopencl import mem_flags  #@UnresolvedImport
    1515
    16 from xpra.util import updict, engs
     16from xpra.util import engs
    1717from xpra.os_util import _memoryview
    1818
    1919PREFERRED_DEVICE_TYPE = os.environ.get("XPRA_OPENCL_DEVICE_TYPE", "GPU")
     
    486486            "version.cl_header"     : pyopencl.get_cl_header_version(),
    487487            "opengl"                : pyopencl.have_gl(),
    488488            #"kernels"               : KERNELS_DEFS.keys()
     489            "pyopencl"              : get_pyopencl_info(),
    489490            }
    490     updict(info, "pyopencl", get_pyopencl_info())
    491491    if selected_platform:
    492         updict(info, "platform", {
     492        info["platform"] = {
    493493            "name"          : selected_platform.name,
    494494            "vendor"        : selected_platform.vendor,
    495495            "devices"       : len(selected_platform.get_devices()),
    496             })
     496            }
    497497    if selected_device:
    498         if hasattr(selected_device, "opencl_c_version"):
    499             info["device.opencl_c_version"] = getattr(selected_device, "opencl_c_version")
    500         updict(info, "device", {
     498        dinfo = {
    501499            "type"                      : device_type(selected_device),
    502500            "name"                      : selected_device.name.strip(),
    503501            "version"                   : selected_device.version,
     
    504502            "max_work_group_size"       : selected_device.max_work_group_size,
    505503            "max_work_item_dimensions"  : selected_device.max_work_item_dimensions,
    506504            "max_work_item_sizes"       : selected_device.max_work_item_sizes,
    507             "max-size"                  : selected_device_max_size})
     505            "max-size"                  : selected_device_max_size}
     506        if hasattr(selected_device, "opencl_c_version"):
     507            dinfo["opencl_c_version"] = getattr(selected_device, "opencl_c_version")
     508        info["device"] = dinfo
    508509    return info
    509510
    510511
  • xpra/codecs/enc_ffmpeg/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
  • xpra/codecs/enc_ffmpeg/encoder.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2012-2014 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6import weakref
     7from xpra.log import Logger
     8log = Logger("decoder", "ffmpeg")
     9
     10from xpra.codecs.codec_constants import get_subsampling_divs
     11from xpra.codecs.image_wrapper import ImageWrapper
     12from xpra.codecs.libav_common.av_log cimport override_logger, restore_logger #@UnresolvedImport
     13from xpra.util import bytestostr
     14
     15
     16ctypedef unsigned long size_t
     17ctypedef unsigned char uint8_t
     18
     19
     20cdef extern from "../../buffers/buffers.h":
     21    object memory_as_pybuffer(void* ptr, Py_ssize_t buf_len, int readonly)
     22    int    object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len)
     23    int get_buffer_api_version()
     24
     25cdef extern from "string.h":
     26    void * memcpy(void * destination, void * source, size_t num) nogil
     27    void * memset(void * ptr, int value, size_t num) nogil
     28    void free(void * ptr) nogil
     29
     30
     31cdef extern from "../../inline.h":
     32    pass
     33
     34cdef extern from "../../buffers/memalign.h":
     35    void *xmemalign(size_t size)
     36
     37
     38cdef extern from "libavutil/mem.h":
     39    void av_free(void *ptr)
     40
     41cdef extern from "libavutil/error.h":
     42    int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
     43
     44cdef extern from "libavcodec/version.h":
     45    int LIBAVCODEC_VERSION_MAJOR
     46    int LIBAVCODEC_VERSION_MINOR
     47    int LIBAVCODEC_VERSION_MICRO
     48
     49#why can't we define this inside the avcodec.h section? (beats me)
     50ctypedef unsigned int AVCodecID
     51ctypedef long AVPixelFormat
     52
     53
     54cdef extern from "libavutil/pixfmt.h":
     55    AVPixelFormat AV_PIX_FMT_NONE
     56    AVPixelFormat AV_PIX_FMT_YUV420P
     57
     58cdef extern from "libavcodec/avcodec.h":
     59    int CODEC_FLAG2_FAST
     60
     61    ctypedef struct AVFrame:
     62        uint8_t **data
     63        int *linesize
     64        int format
     65        void *opaque
     66    ctypedef struct AVCodec:
     67        pass
     68    ctypedef struct AVDictionary:
     69        pass
     70    ctypedef struct AVPacket:
     71        uint8_t *data
     72        int      size
     73
     74    ctypedef struct AVCodecContext:
     75        int width
     76        int height
     77        AVPixelFormat pix_fmt
     78        int thread_safe_callbacks
     79        int thread_count
     80        int thread_type
     81        int flags
     82        int flags2
     83        int refcounted_frames
     84
     85    AVCodecID AV_CODEC_ID_H264
     86    AVCodecID AV_CODEC_ID_H265
     87    AVCodecID AV_CODEC_ID_VP8
     88    AVCodecID AV_CODEC_ID_VP9
     89    AVCodecID AV_CODEC_ID_MPEG4
     90
     91    #init and free:
     92    void avcodec_register_all()
     93    AVCodec *avcodec_find_decoder(AVCodecID id)
     94    AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
     95    int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
     96    AVFrame* av_frame_alloc()
     97    void av_frame_free(AVFrame **frame)
     98    int avcodec_close(AVCodecContext *avctx)
     99
     100    #actual decoding:
     101    void av_init_packet(AVPacket *pkt) nogil
     102    void avcodec_get_frame_defaults(AVFrame *frame) nogil
     103    int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
     104                                int *got_picture_ptr, const AVPacket *avpkt) nogil
     105
     106    void av_frame_unref(AVFrame *frame) nogil
     107
     108
     109FORMAT_TO_ENUM = {
     110            "YUV420P"   : AV_PIX_FMT_YUV420P,
     111            "YUV422P"   : AV_PIX_FMT_YUV422P,
     112            "YUV444P"   : AV_PIX_FMT_YUV444P,
     113            "RGB"       : AV_PIX_FMT_RGB24,
     114            "XRGB"      : AV_PIX_FMT_0RGB,
     115            "BGRX"      : AV_PIX_FMT_BGR0,
     116            "ARGB"      : AV_PIX_FMT_ARGB,
     117            "BGRA"      : AV_PIX_FMT_BGRA,
     118            "GBRP"      : AV_PIX_FMT_GBRP,
     119            }
     120
     121COLORSPACES = FORMAT_TO_ENUM.keys()
     122ENUM_TO_FORMAT = {}
     123for pix_fmt, av_enum in FORMAT_TO_ENUM.items():
     124    ENUM_TO_FORMAT[av_enum] = pix_fmt
     125
     126def get_version():
     127    return (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO)
     128
     129avcodec_register_all()
     130CODECS = []
     131if avcodec_find_decoder(AV_CODEC_ID_H264)!=NULL:
     132    CODECS.append("h264")
     133if avcodec_find_decoder(AV_CODEC_ID_VP8)!=NULL:
     134    CODECS.append("vp8")
     135if avcodec_find_decoder(AV_CODEC_ID_VP9)!=NULL:
     136    CODECS.append("vp9")
     137if avcodec_find_decoder(AV_CODEC_ID_H265)!=NULL:
     138    CODECS.append("h265")
     139if avcodec_find_decoder(AV_CODEC_ID_MPEG4)!=NULL:
     140    CODECS.append("mpeg4")
     141log("enc_ffmpeg.init_module: CODECS=%s", CODECS)
     142
     143
     144def init_module():
     145    log("enc_ffmpeg.init_module()")
     146    override_logger()
     147
     148def cleanup_module():
     149    log("enc_ffmpeg.cleanup_module()")
     150    restore_logger()
     151
     152def get_type():
     153    return "ffmpeg"
     154
     155def get_info():
     156    f = {}
     157    for e in get_encodings():
     158        f["formats.%s" % e] = get_input_colorspaces(e)
     159    return  {"version"      : get_version(),
     160             "encodings"    : get_encodings(),
     161             "buffer_api"   : get_buffer_api_version(),
     162             "formats"      : f,
     163             }
     164
     165def get_encodings():
     166    global CODECS
     167    return CODECS
     168
     169def get_input_colorspaces(encoding):
     170    return ["YUV420P"]
     171
     172def get_output_colorspace(encoding, csc):
     173    if encoding not in CODECS:
     174        return ""
     175    return "YUV420P"
     176
     177
     178cdef void clear_frame(AVFrame *frame):
     179    assert frame!=NULL, "frame is not set!"
     180    for i in range(4):
     181        frame.data[i] = NULL
     182
     183
     184cdef class AVFrameWrapper:
     185    """
     186        Wraps an AVFrame so we can free it
     187        once both xpra and avcodec are done with it.
     188    """
     189    cdef AVCodecContext *avctx
     190    cdef AVFrame *frame
     191    cdef int xpra_freed
     192
     193    cdef set_context(self, AVCodecContext *avctx, AVFrame *frame):
     194        self.avctx = avctx
     195        self.frame = frame
     196        log("%s.set_context(%#x, %#x)", self, <unsigned long> avctx, <unsigned long> frame)
     197
     198    def __dealloc__(self):
     199        #By the time this wrapper is garbage collected,
     200        #we must have freed it!
     201        assert self.frame==NULL and self.avctx==NULL, "frame was freed by both, but not actually freed!"
     202
     203    def __str__(self):
     204        if self.frame==NULL:
     205            return "AVFrameWrapper(NULL)"
     206        return "AVFrameWrapper(%#x)" % <unsigned long> self.frame
     207
     208    def xpra_free(self):
     209        log("%s.xpra_free()", self)
     210        self.free()
     211
     212    cdef free(self):
     213        log("%s.free() context=%#x, frame=%#x", self, <unsigned long> self.avctx, <unsigned long> self.frame)
     214        if self.avctx!=NULL and self.frame!=NULL:
     215            av_frame_unref(self.frame)
     216            self.frame = NULL
     217            self.avctx = NULL
     218
     219
     220class AVImageWrapper(ImageWrapper):
     221    """
     222        Wrapper which allows us to call xpra_free on the decoder
     223        when the image is freed, or once we have made a copy of the pixels.
     224    """
     225
     226    def __repr__(self):                          #@DuplicatedSignature
     227        return ImageWrapper.__repr__(self)+"-(%s)" % self.av_frame
     228
     229    def free(self):                             #@DuplicatedSignature
     230        log("AVImageWrapper.free()")
     231        ImageWrapper.free(self)
     232        self.xpra_free_frame()
     233
     234    def clone_pixel_data(self):
     235        log("AVImageWrapper.clone_pixel_data()")
     236        ImageWrapper.clone_pixel_data(self)
     237        self.xpra_free_frame()
     238
     239    def xpra_free_frame(self):
     240        av_frame = self.av_frame
     241        log("AVImageWrapper.xpra_free_frame() av_frame=%s", av_frame)
     242        if av_frame:
     243            self.av_frame = None
     244            av_frame.xpra_free()
     245
     246
     247cdef class Encoder:
     248    """
     249        This wraps the AVCodecContext and its configuration,
     250        also tracks AVFrames.
     251        It also handles reconstructing a single ImageWrapper
     252        constructed from 3-pass decoding (see plane_sizes).
     253    """
     254    cdef AVCodec *codec
     255    cdef AVCodecContext *codec_ctx
     256    cdef AVPixelFormat pix_fmt
     257    cdef AVPixelFormat actual_pix_fmt
     258    cdef object colorspace
     259    cdef object weakref_images
     260    cdef AVFrame *av_frame
     261    #this is the actual number of images we have returned
     262    cdef unsigned long frames
     263    cdef int width
     264    cdef int height
     265    cdef object encoding
     266
     267    cdef object __weakref__
     268
     269    def init_context(self, encoding, int width, int height, colorspace):
     270        cdef int r
     271        cdef int i
     272        assert encoding in CODECS
     273        self.encoding = encoding
     274        self.width = width
     275        self.height = height
     276        assert colorspace in COLORSPACES, "invalid colorspace: %s" % colorspace
     277        self.colorspace = ""
     278        for x in COLORSPACES:
     279            if x==colorspace:
     280                self.colorspace = x
     281                break
     282        if not self.colorspace:
     283            log.error("invalid pixel format: %s", colorspace)
     284            return  False
     285        self.pix_fmt = FORMAT_TO_ENUM.get(colorspace, AV_PIX_FMT_NONE)
     286        if self.pix_fmt==AV_PIX_FMT_NONE:
     287            log.error("invalid pixel format: %s", colorspace)
     288            return  False
     289        self.actual_pix_fmt = self.pix_fmt
     290
     291        avcodec_register_all()
     292
     293        cdef AVCodecID CodecID
     294        if self.encoding=="h264":
     295            CodecID = AV_CODEC_ID_H264
     296        elif self.encoding=="h265":
     297            CodecID = AV_CODEC_ID_H265
     298        elif self.encoding=="vp8":
     299            CodecID = AV_CODEC_ID_VP8
     300        elif self.encoding=="vp9":
     301            CodecID = AV_CODEC_ID_VP9
     302        elif self.encoding=="mpeg4":
     303            CodecID = AV_CODEC_ID_MPEG4
     304        else:
     305            raise Exception("invalid codec; %s" % self.encoding)
     306        self.codec = avcodec_find_decoder(CodecID)
     307        if self.codec==NULL:
     308            log.error("codec %s not found!" % self.encoding)
     309            return  False
     310
     311        #from here on, we have to call clean_decoder():
     312        self.codec_ctx = avcodec_alloc_context3(self.codec)
     313        if self.codec_ctx==NULL:
     314            log.error("failed to allocate codec context!")
     315            self.clean_decoder()
     316            return  False
     317
     318        self.codec_ctx.refcounted_frames = 1
     319        self.codec_ctx.width = width
     320        self.codec_ctx.height = height
     321        self.codec_ctx.pix_fmt = self.pix_fmt
     322        #self.codec_ctx.get_buffer2 = avcodec_get_buffer2
     323        #self.codec_ctx.release_buffer = avcodec_release_buffer
     324        self.codec_ctx.thread_safe_callbacks = 1
     325        self.codec_ctx.thread_type = 2      #FF_THREAD_SLICE: allow more than one thread per frame
     326        self.codec_ctx.thread_count = 0     #auto
     327        self.codec_ctx.flags2 |= CODEC_FLAG2_FAST   #may cause "no deblock across slices" - which should be fine
     328        r = avcodec_open2(self.codec_ctx, self.codec, NULL)
     329        if r<0:
     330            log.error("could not open codec: %s", self.av_error_str(r))
     331            self.clean_decoder()
     332            return  False
     333        #up to 3 AVFrame objects used:
     334        self.av_frame = av_frame_alloc()
     335        if self.av_frame==NULL:
     336            log.error("could not allocate an AVFrame for decoding")
     337            self.clean_decoder()
     338            return  False
     339        self.frames = 0
     340        #to keep track of images not freed yet:
     341        #(we want a weakref.WeakSet() but this is python2.7+ only..)
     342        self.weakref_images = []
     343        #register this decoder in the global dictionary:
     344        log("dec_avcodec.Decoder.init_context(%s, %s, %s) self=%s", width, height, colorspace, self.get_info())
     345        return True
     346
     347    def clean(self):
     348        self.clean_decoder()
     349        self.codec = NULL
     350        self.pix_fmt = 0
     351        self.actual_pix_fmt = 0
     352        self.colorspace = ""
     353        self.weakref_images = []
     354        self.av_frame = NULL                        #should be redundant
     355        self.frames = 0
     356        self.width = 0
     357        self.height = 0
     358        self.encoding = ""
     359
     360
     361    def clean_decoder(self):
     362        cdef int r, i
     363        log("%s.clean_decoder()", self)
     364        #we may have images handed out, ensure we don't reference any memory
     365        #that needs to be freed using avcodec_release_buffer(..)
     366        #as this requires the context to still be valid!
     367        #copying the pixels should ensure we free the AVFrameWrapper associated with it:
     368        if self.weakref_images:
     369            images = [y for y in [x() for x in self.weakref_images] if y is not None]
     370            self.weakref_images = []
     371            log("clean_decoder() cloning pixels for images still in use: %s", images)
     372            for img in images:
     373                if not img.freed:
     374                    img.clone_pixel_data()
     375
     376        if self.av_frame!=NULL:
     377            log("clean_decoder() freeing AVFrame: %#x", <unsigned long> self.av_frame)
     378            av_frame_free(&self.av_frame)
     379            #redundant: self.frame = NULL
     380
     381        cdef unsigned long ctx_key          #@DuplicatedSignature
     382        log("clean_decoder() freeing AVCodecContext: %#x", <unsigned long> self.codec_ctx)
     383        if self.codec_ctx!=NULL:
     384            r = avcodec_close(self.codec_ctx)
     385            if r!=0:
     386                log.warn("error closing decoder context %#x: %s", <unsigned long> self.codec_ctx, self.av_error_str(r))
     387            av_free(self.codec_ctx)
     388            self.codec_ctx = NULL
     389        log("clean_decoder() done")
     390
     391    cdef av_error_str(self, errnum):
     392        cdef char[128] err_str
     393        cdef int i = 0
     394        if av_strerror(errnum, err_str, 128)==0:
     395            while i<128 and err_str[i]!=0:
     396                i += 1
     397            return bytestostr(err_str[:i])
     398        return str(errnum)
     399
     400    def __repr__(self):                      #@DuplicatedSignature
     401        if self.is_closed():
     402            return "dec_avcodec.Decoder(*closed*)"
     403        return "dec_avcodec.Decoder(%s)" % self.get_info()
     404
     405    def get_info(self):                      #@DuplicatedSignature
     406        info = {"version"   : get_version(),
     407                "encoding"  : self.encoding,
     408                "formats"   : get_input_colorspaces(self.encoding),
     409                "type"      : self.get_type(),
     410                "frames"    : self.frames,
     411                "width"     : self.width,
     412                "height"    : self.height,
     413                }
     414        if self.colorspace:
     415            info["colorspace"] = self.colorspace
     416            info["actual_colorspace"] = self.get_actual_colorspace()
     417        if not self.is_closed():
     418            info["decoder_width"] = self.codec_ctx.width
     419            info["decoder_height"] = self.codec_ctx.height
     420        else:
     421            info["closed"] = True
     422        return info
     423
     424    def is_closed(self):
     425        return self.codec_ctx==NULL
     426
     427    def __dealloc__(self):                          #@DuplicatedSignature
     428        self.clean()
     429
     430    def get_width(self):
     431        return self.width
     432
     433    def get_height(self):
     434        return self.height
     435
     436    def get_encoding(self):
     437        return self.encoding
     438
     439    def get_type(self):                             #@DuplicatedSignature
     440        return "avcodec"
     441
     442    def decompress_image(self, input, options):
     443        cdef unsigned char * padded_buf = NULL
     444        cdef const unsigned char * buf = NULL
     445        cdef Py_ssize_t buf_len = 0
     446        cdef int size
     447        cdef int len = 0
     448        cdef int nplanes
     449        cdef int got_picture
     450        cdef AVPacket avpkt
     451        cdef unsigned long frame_key                #@DuplicatedSignature
     452        cdef AVFrameWrapper framewrapper
     453        cdef AVFrame *av_frame
     454        cdef object img
     455        assert self.codec_ctx!=NULL, "no codec context! (not initialized or already closed)"
     456        assert self.codec!=NULL
     457
     458        #copy the whole input buffer into a padded C buffer:
     459        assert object_as_buffer(input, <const void**> &buf, &buf_len)==0
     460        padded_buf = <unsigned char *> xmemalign(buf_len+128)
     461        memcpy(padded_buf, buf, buf_len)
     462        memset(padded_buf+buf_len, 0, 128)
     463
     464        #note: plain RGB output, will redefine those:
     465        out = []
     466        strides = []
     467        outsize = 0
     468
     469        #ensure we can detect if the frame buffer got allocated:
     470        clear_frame(self.av_frame)
     471        #now safe to run without gil:
     472        with nogil:
     473            av_init_packet(&avpkt)
     474            avpkt.data = <uint8_t *> (padded_buf)
     475            avpkt.size = buf_len
     476            len = avcodec_decode_video2(self.codec_ctx, self.av_frame, &got_picture, &avpkt)
     477        if len<0:
     478            av_frame_unref(self.av_frame)
     479            log("%s.decompress_image(%s:%s, %s) avcodec_decode_video2 failure: %s", self, type(input), buf_len, options, self.av_error_str(len))
     480            log.error("avcodec_decode_video2 %s decoding failure:", self.encoding)
     481            log.error(" %s", self.av_error_str(len))
     482            return None
     483        if len==0:
     484            av_frame_unref(self.av_frame)
     485            log("%s.decompress_image(%s:%s, %s) avcodec_decode_video2 failed to decode the stream", self, type(input), buf_len, options)
     486            log.error("avcodec_decode_video2 %s decoding failure - no stream", self.encoding)
     487            return None
     488
     489        if self.actual_pix_fmt!=self.av_frame.format:
     490            if self.av_frame.format==-1:
     491                log.error("avcodec error decoding %i bytes of %s data", buf_len, self.encoding)
     492                log.error(" frame %i", self.frames)
     493                log.error(" options=%s", options)
     494                log.error(" decoder state:")
     495                for k,v in self.get_info().items():
     496                    log.error("  %s = %s", k, v)
     497                return None
     498            self.actual_pix_fmt = self.av_frame.format
     499            if self.actual_pix_fmt not in ENUM_TO_FORMAT:
     500                av_frame_unref(self.av_frame)
     501                log.error("unknown output pixel format: %s, expected %s (%s)", self.actual_pix_fmt, self.pix_fmt, self.colorspace)
     502                return None
     503            log("avcodec actual output pixel format is %s (%s), expected %s (%s)", self.actual_pix_fmt, self.get_actual_colorspace(), self.pix_fmt, self.colorspace)
     504
     505        cs = self.get_actual_colorspace()
     506        if cs.endswith("P"):
     507            divs = get_subsampling_divs(cs)
     508            nplanes = 3
     509            for i in range(3):
     510                _, dy = divs[i]
     511                if dy==1:
     512                    height = self.codec_ctx.height
     513                elif dy==2:
     514                    height = (self.codec_ctx.height+1)>>1
     515                else:
     516                    av_frame_unref(self.av_frame)
     517                    raise Exception("invalid height divisor %s" % dy)
     518                stride = self.av_frame.linesize[i]
     519                size = height * stride
     520                outsize += size
     521
     522                out.append(memory_as_pybuffer(<void *>self.av_frame.data[i], size, True))
     523                strides.append(stride)
     524                log("decompress_image() read back yuv plane %s: %s bytes", i, size)
     525        else:
     526            #RGB mode: "out" is a single buffer
     527            strides = self.av_frame.linesize[0]+self.av_frame.linesize[1]+self.av_frame.linesize[2]
     528            outsize = self.codec_ctx.height * strides
     529            out = memory_as_pybuffer(<void *>self.av_frame.data[0], outsize, True)
     530            nplanes = 0
     531            log("decompress_image() read back rgb buffer: %s bytes", outsize)
     532
     533        #FIXME: we could lose track of framewrappers if an error occurs before the end:
     534        framewrapper = AVFrameWrapper()
     535        framewrapper.set_context(self.codec_ctx, self.av_frame)
     536
     537        if outsize==0:
     538            av_frame_unref(self.av_frame)
     539            raise Exception("output size is zero!")
     540
     541        free(padded_buf)
     542        assert self.codec_ctx.width>=self.width, "codec width is smaller than our width: %s<%s" % (self.codec_ctx.width, self.width)
     543        assert self.codec_ctx.height>=self.height, "codec height is smaller than our height: %s<%s" % (self.codec_ctx.height, self.height)
     544        img = AVImageWrapper(0, 0, self.width, self.height, out, cs, 24, strides, nplanes, thread_safe=False)
     545        img.av_frame = framewrapper
     546        self.frames += 1
     547        #add to weakref list after cleaning it up:
     548        self.weakref_images = [x for x in self.weakref_images if x() is not None]
     549        self.weakref_images.append(weakref.ref(img))
     550        log("%s.decompress_image(%s:%s, %s)=%s", self, type(input), buf_len, options, img)
     551        return img
     552
     553
     554    def get_colorspace(self):
     555        return self.colorspace
     556
     557    def get_actual_colorspace(self):
     558        return ENUM_TO_FORMAT.get(self.actual_pix_fmt, "unknown/invalid")
     559
     560
     561def selftest(full=False):
     562    global CODECS
     563    from xpra.codecs.codec_checks import testdecoder
     564    from xpra.codecs.dec_avcodec2 import decoder
     565    global CODECS
     566    CODECS = testdecoder(decoder, full)
  • xpra/codecs/mkv/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
  • xpra/codecs/mkv/muxer.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6import time
     7import os
     8
     9from xpra.log import Logger
     10log = Logger("encoder", "mkv")
     11
     12from libc.stdint cimport int64_t
     13
     14cdef extern from "string.h":
     15    void *memset(void *ptr, int value, size_t num) nogil
     16    void free(void *ptr) nogil
     17
     18cdef extern from "../../buffers/memalign.h":
     19    void *xmemalign(size_t size)
     20
     21cdef extern from "../../buffers/buffers.h":
     22    int object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len)
     23    int get_buffer_api_version()
     24
     25
     26cdef extern from "libmkv.h":
     27    pass
     28
     29cdef class Muxer:
     30    cdef object __weakref__
     31
     32#init_context(w, h, src_format, encoding, quality, speed, scaling, options)
     33    def init_context(self, int width, int height, src_format, dst_formats, encoding, int quality, int speed, scaling, options):    #@DuplicatedSignature
     34        pass
  • xpra/codecs/nvenc4/encoder.pyx

     
    1616from pycuda.driver import memcpy_htod
    1717from pycuda.compiler import compile
    1818
    19 from xpra.util import AtomicInteger, updict, engs, csv, pver
     19from xpra.util import AtomicInteger, engs, csv, pver
    2020from xpra.os_util import _memoryview
    2121from xpra.codecs.cuda_common.cuda_context import init_all_devices, get_devices, select_device, \
    2222                get_cuda_info, get_pycuda_info, device_info, reset_state, \
     
    15871587                "bitrate"           : self.target_bitrate,
    15881588                "quality"           : self.quality,
    15891589                "speed"             : self.speed,
    1590                 "lossless"          : self.lossless,
    1591                 "lossless.supported": LOSSLESS_ENABLED,
    1592                 "lossless.threshold": LOSSLESS_THRESHOLD,
    1593                 "yuv444.supported"  : YUV444_ENABLED,
    1594                 "yuv444.threshold"  : YUV444_THRESHOLD,
     1590                "lossless"  : {
     1591                               ""          : self.lossless,
     1592                               "supported" : LOSSLESS_ENABLED,
     1593                               "threshold" : LOSSLESS_THRESHOLD
     1594                    },
     1595                "yuv444" : {
     1596                            "supported" : YUV444_ENABLED,
     1597                            "threshold" : YUV444_THRESHOLD,
     1598                            },
     1599                "cuda-device"   : self.cuda_device_info,
     1600                "cuda"          : self.cuda_info,
     1601                "pycuda"        : self.pycuda_info,
    15951602                })
    15961603        if self.scaling!=(1,1):
    15971604            info.update({
     
    15981605                "input_width"       : self.input_width,
    15991606                "input_height"      : self.input_height,
    16001607                "scaling"           : self.scaling})
    1601         updict(info, "cuda", self.cuda_device_info)
    1602         updict(info, "cuda", self.cuda_info)
    1603         updict(info, "pycuda", self.pycuda_info)
    16041608        if self.src_format:
    16051609            info["src_format"] = self.src_format
    16061610        if self.pixel_format:
  • xpra/codecs/nvenc5/encoder.pyx

     
    1616from pycuda.driver import memcpy_htod
    1717from pycuda.compiler import compile
    1818
    19 from xpra.util import AtomicInteger, updict, engs, csv, pver
     19from xpra.util import AtomicInteger, engs, csv, pver
    2020from xpra.os_util import _memoryview
    2121from xpra.codecs.cuda_common.cuda_context import init_all_devices, get_devices, select_device, \
    2222                get_cuda_info, get_pycuda_info, device_info, reset_state, \
     
    16251625                "bitrate"           : self.target_bitrate,
    16261626                "quality"           : self.quality,
    16271627                "speed"             : self.speed,
    1628                 "lossless"          : self.lossless,
    1629                 "lossless.supported": LOSSLESS_ENABLED,
    1630                 "lossless.threshold": LOSSLESS_THRESHOLD,
    1631                 "yuv444.supported"  : YUV444_ENABLED,
    1632                 "yuv444.threshold"  : YUV444_THRESHOLD,
     1628                "lossless"  : {
     1629                               ""          : self.lossless,
     1630                               "supported" : LOSSLESS_ENABLED,
     1631                               "threshold" : LOSSLESS_THRESHOLD
     1632                    },
     1633                "yuv444" : {
     1634                            "supported" : YUV444_ENABLED,
     1635                            "threshold" : YUV444_THRESHOLD,
     1636                            },
     1637                "cuda-device"   : self.cuda_device_info,
     1638                "cuda"          : self.cuda_info,
     1639                "pycuda"        : self.pycuda_info,
    16331640                })
    16341641        if self.scaling!=(1,1):
    16351642            info.update({
     
    16361643                "input_width"       : self.input_width,
    16371644                "input_height"      : self.input_height,
    16381645                "scaling"           : self.scaling})
    1639         updict(info, "cuda", self.cuda_device_info)
    1640         updict(info, "cuda", self.cuda_info)
    1641         updict(info, "pycuda", self.pycuda_info)
    16421646        if self.src_format:
    16431647            info["src_format"] = self.src_format
    16441648        if self.pixel_format:
  • xpra/codecs/nvenc6/encoder.pyx

     
    1616from pycuda.driver import memcpy_htod
    1717from pycuda.compiler import compile
    1818
    19 from xpra.util import AtomicInteger, updict, engs, csv, pver
     19from xpra.util import AtomicInteger, engs, csv, pver
    2020from xpra.os_util import _memoryview
    2121from xpra.codecs.cuda_common.cuda_context import init_all_devices, get_devices, select_device, \
    2222                get_cuda_info, get_pycuda_info, device_info, reset_state, \
     
    16961696                "bitrate"           : self.target_bitrate,
    16971697                "quality"           : self.quality,
    16981698                "speed"             : self.speed,
    1699                 "lossless"          : self.lossless,
    1700                 "lossless.supported": LOSSLESS_ENABLED,
    1701                 "lossless.threshold": LOSSLESS_THRESHOLD,
    1702                 "yuv444.supported"  : YUV444_ENABLED,
    1703                 "yuv444.threshold"  : YUV444_THRESHOLD,
     1699                "lossless"  : {
     1700                               ""          : self.lossless,
     1701                               "supported" : LOSSLESS_ENABLED,
     1702                               "threshold" : LOSSLESS_THRESHOLD
     1703                    },
     1704                "yuv444" : {
     1705                            "supported" : YUV444_ENABLED,
     1706                            "threshold" : YUV444_THRESHOLD,
     1707                            },
     1708                "cuda-device"   : self.cuda_device_info,
     1709                "cuda"          : self.cuda_info,
     1710                "pycuda"        : self.pycuda_info,
    17041711                })
    17051712        if self.scaling!=(1,1):
    17061713            info.update({
     
    17071714                "input_width"       : self.input_width,
    17081715                "input_height"      : self.input_height,
    17091716                "scaling"           : self.scaling})
    1710         updict(info, "cuda", self.cuda_device_info)
    1711         updict(info, "cuda", self.cuda_info)
    1712         updict(info, "pycuda", self.pycuda_info)
    17131717        if self.src_format:
    17141718            info["src_format"] = self.src_format
    17151719        if self.pixel_format:
  • xpra/codecs/ogg/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
  • xpra/codecs/ogg/muxer.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6import time
     7import os
     8
     9from xpra.log import Logger
     10log = Logger("encoder", "mkv")
     11
     12from libc.stdint cimport int64_t
     13
     14cdef extern from "string.h":
     15    void *memset(void *ptr, int value, size_t num) nogil
     16    void free(void *ptr) nogil
     17
     18cdef extern from "../../buffers/memalign.h":
     19    void *xmemalign(size_t size)
     20
     21cdef extern from "../../buffers/buffers.h":
     22    int object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len)
     23    int get_buffer_api_version()
     24
     25
     26cdef extern from "ogg/ogg.h":
     27    pass
     28
     29cdef class Muxer:
     30    cdef object __weakref__
     31
     32#init_context(w, h, src_format, encoding, quality, speed, scaling, options)
     33    def init_context(self, int width, int height, src_format, dst_formats, encoding, int quality, int speed, scaling, options):    #@DuplicatedSignature
     34        pass
  • xpra/net/bytestreams.py

     
    215215        d = Connection.get_info(self)
    216216        try:
    217217            d["type"] = "pipe"
    218             d["pipe.read.fd"] = self._read_fd
    219             d["pipe.write.fd"] = self._write_fd
     218            d["pipe"] = {"read"     : {"fd" : self._read_fd},
     219                         "write"    : {"fd" : self._write_fd}}
    220220        except:
    221221            pass
    222222        return d
     
    255255            d["type"] = "socket"
    256256            s = self._socket
    257257            if s:
    258                 from xpra.util import updict
    259                 updict(d, "socket", {
     258                d["socket"] = {
    260259                        "fileno"        : s.fileno(),
    261260                        "timeout"       : int(1000*(s.gettimeout() or 0)),
    262261                        "family"        : s.family,
    263262                        "proto"         : s.proto,
    264                         "type"          : s.type})
     263                        "type"          : s.type}
    265264        except:
    266265            log.warn("failed to get socket information", exc_info=True)
    267266        return d
  • xpra/net/protocol.py

     
    2020cryptolog = Logger("network", "crypto")
    2121
    2222from xpra.os_util import Queue, strtobytes
    23 from xpra.util import repr_ellipsized, updict, csv
     23from xpra.util import repr_ellipsized, csv
    2424from xpra.net import ConnectionClosedException
    2525from xpra.net.bytestreams import ABORT
    2626from xpra.net import compression
     
    210210
    211211    def get_info(self, alias_info=True):
    212212        info = {
    213             "input.packetcount"     : self.input_packetcount,
    214             "input.raw_packetcount" : self.input_raw_packetcount,
    215             "input.cipher"          : self.cipher_in_name or "",
    216             "input.cipher.padding"  : self.cipher_in_padding,
    217             "output.packetcount"    : self.output_packetcount,
    218             "output.raw_packetcount": self.output_raw_packetcount,
    219             "output.cipher"         : self.cipher_out_name or "",
    220             "output.cipher.padding" : self.cipher_out_padding,
    221213            "large_packets"         : self.large_packets,
    222214            "compression_level"     : self.compression_level,
    223             "max_packet_size"       : self.max_packet_size}
    224         updict(info, "input.count", self.input_stats)
    225         updict(info, "output.count", self.output_stats)
     215            "max_packet_size"       : self.max_packet_size,
     216            "input" : {
     217                       "packetcount"            : self.input_packetcount,
     218                       "raw_packetcount"        : self.input_raw_packetcount,
     219                       "count"                  : self.input_stats,
     220                       "cipher"                 : {"": self.cipher_in_name or "",
     221                                                   "padding"        : self.cipher_in_padding,
     222                                                   },
     223                        },
     224            "output" : {
     225                        "packetcount"           : self.output_packetcount,
     226                        "raw_packetcount"       : self.output_raw_packetcount,
     227                        "count"                 : self.output_stats,
     228                        "cipher"                : {"": self.cipher_out_name or "",
     229                                                   "padding" : self.cipher_out_padding
     230                                                   },
     231                        },
     232            }
    226233        c = self._compress
    227234        if c:
    228235            info["compressor"] = compression.get_compressor_name(self._compress)
     
    233240            else:
    234241                info["encoder"] = packet_encoding.get_encoder_name(self._encoder)
    235242        if alias_info:
    236             for k,v in self.send_aliases.items():
    237                 info["send_alias." + str(k)] = v
    238                 info["send_alias." + str(v)] = k
    239             for k,v in self.receive_aliases.items():
    240                 info["receive_alias." + str(k)] = v
    241                 info["receive_alias." + str(v)] = k
     243            info["send_alias"] = self.send_aliases
     244            info["receive_alias"] = self.receive_aliases
    242245        c = self._conn
    243246        if c:
    244247            try:
     
    248251        info["has_more"] = self._source_has_more.is_set()
    249252        for t in (self._write_thread, self._read_thread, self._read_parser_thread, self._write_format_thread):
    250253            if t:
    251                 info["thread.%s" % t.name] = t.is_alive()
     254                info.setdefault("thread", {})[t.name] = t.is_alive()
    252255        return info
    253256
    254257
  • xpra/net/pycrypto_backend.py

     
    2020    pass
    2121
    2222def get_info():
    23     caps = {"backend"           : "pycrypto",
    24             "pycrypto"          : "True",
    25             "pycrypto.version"  : Crypto.__version__}
    2623    try:
    2724        from Crypto.PublicKey import _fastmath
    2825    except:
    2926        _fastmath = None
    30     caps["pycrypto.fastmath"] = _fastmath is not None
    31     return caps
     27    return {"backend"           : "pycrypto",
     28            "pycrypto"          : {""           : True,
     29                                   "version"    : Crypto.__version__},
     30                                   "fastmath"   : _fastmath is not None}
    3231
    3332
    3433def get_key(password, key_salt, block_size, iterations):
  • xpra/net/pycryptography_backend.py

     
    6565    import cryptography
    6666    return {"backend"                       : "python-cryptography",
    6767            "backends"                      : [ci(x) for x in getattr(backend, "_backends", [])],
    68             "python-cryptography"           : True,
    69             "python-cryptography.version"   : cryptography.__version__}
     68            "python-cryptography"           : {""           : True,
     69                                               "version"    : cryptography.__version__}
     70            }
    7071
    7172def get_key(password, key_salt, block_size, iterations):
    7273    global backend
  • xpra/platform/darwin/shadow_server.py

     
    113113
    114114    def get_info(self, proto):
    115115        info = GTKServerBase.get_info(self, proto)
    116         info["features.shadow"] = True
    117         info["server.type"] = "Python/gtk2/osx-shadow"
     116        info.setdefault("features", {})["shadow"] = True
     117        info.setdefault("server", {})["type"] = "Python/gtk2/osx-shadow"
    118118        return info
  • xpra/platform/gui.py

     
    150150            return str(v)
    151151    def fnames(l):
    152152        return [fname(x) for x in l]
    153     info = {
     153    return {
    154154            "native_tray_menu_helpers"      : fnames(get_native_tray_menu_helper_classes()),
    155155            "native_trays"                  : fnames(get_native_tray_classes()),
    156156            "native_system_trays"           : fnames(get_native_system_tray_classes()),
     
    161161            "desktops"                      : get_number_of_desktops(),
    162162            "desktop_names"                 : get_desktop_names(),
    163163            "vertical-refresh"              : get_vrefresh(),
    164             "double_click.time"             : get_double_click_time(),
    165             "double_click.distance"         : get_double_click_distance(),
    166164            "fixed_cursor_size"             : get_fixed_cursor_size(),
    167165            "cursor_size"                   : get_cursor_size(),
    168             "dpi.x"                         : get_xdpi(),
    169             "dpi.y"                         : get_ydpi(),
    170166            "icon_size"                     : get_icon_size(),
     167            "double_click"                  : {
     168                                               "time"       : get_double_click_time(),
     169                                               "distance"   : get_double_click_distance(),
     170                                               },
     171            "dpi"                           : {
     172                                               "x"          : get_xdpi(),
     173                                               "y"          : get_ydpi(),
     174                                               },
     175            "antialias"                     : get_antialias_info(),
     176            "window_frame"                  : get_window_frame_sizes(),
    171177            }
    172     from xpra.util import updict
    173     updict(info, "antialias", get_antialias_info())
    174     updict(info, "window_frame", get_window_frame_sizes())
    175     return info
    176178
    177179get_info = get_info_base
    178180
  • xpra/platform/paths.py

     
    206206
    207207def get_info():
    208208    return {
    209             "install.prefix"    : get_install_prefix(),
    210             "default_conf.dirs" : get_default_conf_dirs(),
    211             "system_conf.dirs"  : get_system_conf_dirs(),
    212             "user_conf.dirs"    : get_user_conf_dirs(),
    213             "socket.dirs"       : get_socket_dirs(),
    214             "log.dir"           : get_default_log_dir(),
    215             "download.dir"      : get_download_dir(),
    216             "app.dir"           : get_app_dir(),
    217             "app.default.dir"   : default_get_app_dir(),
     209            "install"           : {"prefix" : get_install_prefix()},
     210            "default_conf"      : {"dirs"   : get_default_conf_dirs()},
     211            "system_conf"       : {"dirs"   : get_system_conf_dirs()},
     212            "user_conf"         : {"dirs"   : get_user_conf_dirs()},
     213            "socket"            : {"dirs"   : get_socket_dirs()},
     214            "log"               : {"dir"    : get_default_log_dir()},
     215            "download"          : {"dir"    : get_download_dir()},
     216            "app"               : {"dir"    : get_app_dir()},
     217            "app"               : {"default" : {"dir"   : default_get_app_dir()}},
    218218            "resources"         : get_resources_dir(),
    219219            "icons"             : get_icon_dir(),
    220220            "home"              : os.path.expanduser("~"),
  • xpra/platform/printing.py

     
    6868
    6969
    7070def get_info():
    71     return {
    72             "mimetypes"         : get_mimetypes(),
    73             "mimetypes.default" : DEFAULT_MIMETYPES,
     71    return {"mimetypes" :   {""         : get_mimetypes(),
     72                             "default"  : DEFAULT_MIMETYPES}
    7473            }
    7574
    7675
  • xpra/platform/pycups_printing.py

     
    416416
    417417def get_info():
    418418    from xpra.platform.printing import get_mimetypes, DEFAULT_MIMETYPES
    419     return {
    420             "mimetypes"         : get_mimetypes(),
    421             "mimetypes.default" : DEFAULT_MIMETYPES,
     419    return {"mimetypes"         : {""           : get_mimetypes(),
     420                                   "default"    : DEFAULT_MIMETYPES,
     421                                   "printers"   : MIMETYPE_TO_PRINTER,
     422                                   "ppd"        : MIMETYPE_TO_PPD},
     423            "mimetype"          : {"default"    : DEFAULT_MIMETYPE},
    422424            "simulate-failure"  : SIMULATE_PRINT_FAILURE,
    423425            "allow-user"        : ALLOW,
    424426            "raw-mode"          : RAW_MODE,
    425427            "generic"           : GENERIC,
    426428            "tmpdir"            : FORWARDER_TMPDIR,
    427             "mimetype.default"  : DEFAULT_MIMETYPE,
    428429            "lpadmin"           : LPADMIN,
    429430            "lpinfo"            : LPINFO,
    430431            "forwarder"         : FORWARDER_BACKEND,
     
    431432            "skipped-printers"  : SKIPPED_PRINTERS,
    432433            "add-local-printers": ADD_LOCAL_PRINTERS,
    433434            "printer-prefix"    : PRINTER_PREFIX,
    434             "cups-dbus.default" : DEFAULT_CUPS_DBUS,
    435             "cups-dbus"         : CUPS_DBUS,
    436             "cups-dbus.poll-delay" : POLLING_DELAY,
    437             "mimetypes.printers": MIMETYPE_TO_PRINTER,
    438             "mimetypes.ppd"     : MIMETYPE_TO_PPD,
     435            "cups-dbus"         : {""           : CUPS_DBUS,
     436                                   "default"    : DEFAULT_CUPS_DBUS,
     437                                   "poll-delay" : POLLING_DELAY},
    439438            "cups.default-options"  : DEFAULT_CUPS_OPTIONS,
    440             "printers.predefined" : UNPROBED_PRINTER_DEFS,
    441             "printers"          : get_printer_definitions(),
     439            "printers"          : {""           : get_printer_definitions(),
     440                                   "predefined" : UNPROBED_PRINTER_DEFS},
    442441            }
    443442
    444443
  • xpra/platform/win32/keyboard_config.py

     
    3636    def __repr__(self):
    3737        return "win32.KeyboardConfig"
    3838
    39     def get_info(self):
    40         info = KeyboardConfigBase.get_info(self)
    41         return info
    4239
    43 
    4440    def parse_options(self, props):
    4541        return KeyboardConfigBase.parse_options(self, props)
    4642
     
    122118    #no useful mapping:
    123119    "ICO_CLEAR"             : "IcoClr",
    124120    "ICO_HELP"              : "Help",
     121    "DIVIDE"                : "KP_Divide",
    125122    "MULTIPLY"              : "KP_Multiply",
     123    "SUBTRACT"              : "KP_Substract",
     124    "ADD"                   : "KP_Add",
    126125    "NONAME"                : "NoSymbol",
    127126    "NUMPAD0"               : "KP_0",
    128127    "NUMPAD1"               : "KP_1",
     
    167166    "OEM_PA1"               : "OemPa1",
    168167    "OEM_PA2"               : "OemPa2",
    169168    "OEM_PA3"               : "OemPa3",
    170     "OEM_PLUS"              : "plus",
     169    #"OEM_PLUS"              : "equal",
    171170    "OEM_RESET"             : "Reset",
    172171    "OEM_WSCTRL"            : "WsCtrl",
    173172    "PA1"                   : "Pa1",
     173    "OEM_102"               : "backslash",
    174174    #missing:?
    175175    #"PACKET"                : "Packet",
    176176    "PLAY"                  : "Play",
     
    263263    "VOLUME_UP"             : "XF86AudioRaiseVolume",
    264264    "XBUTTON1"              : "X1",
    265265    "XBUTTON2"              : "X2",
     266    "BRACKET_LEFT"          : "bracketleft",
     267    "BRACKET_RIGHT"         : "bracketright",
     268    "BRACE_LEFT"            : "braceleft",
     269    "BRACE_RIGHT"           : "braceright",
     270    "COLON"                 : "colon",
     271    "SEMICOLON"             : "semicolon",
     272    "APOSTROPHE"            : "apostrophe",
     273    "AT"                    : "at",
     274    "NUMBER_SIGN"           : "numbersign",
     275    "COMMA"                 : "comma",
     276    "LESS"                  : "less",
     277    "EQUAL"                 : "equal",
     278    "GREATER"               : "greater",
     279    "PERIOD"                : "period",
     280    "SLASH"                 : "slash",
     281    "QUESTION"              : "question",
     282    "BAR"                   : "bar",
     283    "EXCLAM"                : "exclam",
     284    "QUOTEDBL"              : "quotedbl",
     285    "STERLING"              : "sterling",
     286    "DOLLAR"                : "dollar",
     287    "PERCENT"               : "percent",
     288    "ASCIICIRCUM"           : "asciicircum",
     289    "AMPERSAND"             : "ampersand",
     290    "ASTERISK"              : "asterisk",
     291    "PARENLEFT"             : "parenleft",
     292    "PARENRIGHT"            : "parenright",
     293    "UNDERSCORE"            : "underscore",
     294    "BACKSLASH"             : "backslash",
     295    "GRAVE"                 : "grave",
    266296}
    267297
    268298#these aren't defined in win32con...
    269299DEFS = {
     300    "EXCLAM"                : 33,
     301    "QUOTEDBL"              : 34,
     302    "NUMBER_SIGN"           : 35,
     303    "DOLLAR"                : 36,
     304    "PERCENT"               : 37,
     305    "AMPERSAND"             : 38,
     306    "APOSTROPHE"            : 39,
     307    "PARENLEFT"             : 40,
     308    "PARENRIGHT"            : 41,
     309    "ASTERISK"              : 42,
     310    "COMMA"                 : 44,
     311    "PERIOD"                : 46,
     312    "SLASH"                 : 47,
     313    "COLON"                 : 58,
     314    "SEMICOLON"             : 59,
     315    "LESS"                  : 60,
     316    "EQUAL"                 : 61,
     317    "GREATER"               : 62,
     318    "QUESTION"              : 63,
     319    "AT"                    : 64,
     320    "BRACKET_LEFT"          : 91,
     321    "BACKSLASH"             : 92,
     322    "BRACKET_RIGHT"         : 93,
     323    "ASCIICIRCUM"           : 94,
     324    "UNDERSCORE"            : 95,
     325    "GRAVE"                 : 96,
     326    "BRACE_LEFT"            : 123,
     327    "BAR"                   : 124,
     328    "BRACE_RIGHT"           : 125,
     329    "ASCIITILDE"            : 126,
     330    "STERLING"              : 156,
    270331    "SLEEP"                 : 0x5F,
    271332    "OEM_FJ_JISHO"          : 0x92,
    272333    "OEM_FJ_MASSHOU"        : 0x93,
     
    313374    "OEM_FINISH"            : 0xF1,
    314375    "OEM_ENLW"              : 0xF4,
    315376    "OEM_BACKTAB"           : 0xF5,
    316     "ASCIITILDE"            : 65107,        #aka 0x00fe53
     377    "ASCIITILDE"            : 126,
     378    #"ASCIITILDE"            : 65107,        #aka 0x00fe53
    317379    "DEAD_GRAVE"            : 65104,        #aka 0x00fe50
    318380}
    319381
  • xpra/platform/win32/shadow_server.py

     
    393393
    394394    def get_info(self, proto):
    395395        info = GTKServerBase.get_info(self, proto)
    396         info["features.shadow"] = True
    397         info["server.type"] = "Python/gtk2/win32-shadow"
    398         info["server.tray"] = self.tray
    399         info["server.tray-icon"] = self.tray_icon or ""
     396        info.setdefault("features", {})["shadow"] = True
     397        info.setdefault("server", {
     398                                   "type"       : "Python/gtk2/win32-shadow",
     399                                   "tray"       : self.tray,
     400                                   "tray-icon"  :self.tray_icon or ""})
    400401        return info
    401402
    402403
  • xpra/platform/xposix/gui.py

     
    1515traylog = Logger("posix", "menu")
    1616menulog = Logger("posix", "menu")
    1717
    18 from xpra.util import iround
     18from xpra.util import iround, updict
    1919from xpra.gtk_common.gobject_compat import get_xid, is_gtk3
    2020
    2121device_bell = None
     
    456456    s = _get_xsettings()
    457457    if s:
    458458        serial, values = s
    459         i["xsettings.serial"] = serial
     459        xi = {"serial"  : serial}
    460460        for _,name,value,_ in values:
    461             i["xsettings.%s" % name] = value
    462     i["dpi.xsettings"] = _get_xsettings_dpi()
    463     i["dpi.randr"] = _get_randr_dpi()
     461            xi[name] = value
     462        i["xsettings"] = xi
     463    i.setdefault("dpi", {
     464                         "xsettings"    : _get_xsettings_dpi(),
     465                         "randr"        : _get_randr_dpi()
     466                         })
    464467    return i
    465468
    466469
  • xpra/server/gtk_server_base.py

     
    2525                           gtk_main_quit_on_fatal_exceptions_disable)
    2626from xpra.server.server_base import ServerBase
    2727from xpra.gtk_common.gtk_util import get_gtk_version_info, gtk_main
    28 from xpra.util import updict
    2928
    3029
    3130class GTKServerBase(ServerBase):
     
    8887
    8988    def do_get_info(self, proto, *args):
    9089        info = ServerBase.do_get_info(self, proto, *args)
    91         updict(info, "server", get_gtk_version_info())
    92         info.update({
    93                      "server.type"      : "Python/gtk-x11",
    94                      "features.randr"   : self.randr})
     90        vi = get_gtk_version_info()
     91        vi["type"] = "Python/gtk-x11"
     92        info.setdefault("server", {}).update(vi)
     93        info.setdefault("features", {})["randr"] = self.randr
    9594        return info
    9695
    9796    def get_root_window_size(self):
  • xpra/server/proxy/proxy_instance_process.py

     
    352352
    353353
    354354    def get_proxy_info(self, proto):
    355         info = {"proxy.version" : local_version}
    356         def upp(d):
    357             updict(info, "proxy", d)
    358         upp(get_server_info())
    359         upp(get_thread_info(proto))
     355        sinfo = {}
     356        sinfo.update(get_server_info())
     357        sinfo.update(get_thread_info(proto))
     358        info = {"proxy" : {
     359                           "version"    : local_version,
     360                           ""           : sinfo,
     361                           }
     362                }
    360363        info.update(self.get_encoder_info())
    361364        return info
    362365
  • xpra/server/proxy/proxy_server.py

     
    257257                i = 0
    258258                for p,v in self.processes.items():
    259259                    d,_ = v
    260                     info["proxy[%s].display" % i] = d
    261                     info["proxy[%s].live" % i] = p.is_alive()
    262                     info["proxy[%s].pid" % i] = p.pid
     260                    info[i] = {"display"    : d,
     261                               "live"       : p.is_alive(),
     262                               "pid"        : p.pid}
    263263                    i += 1
    264264                info["proxies"] = len(self.processes)
    265265        return info
  • xpra/server/server_base.py

     
    17721772                             "y"            : self.ydpi
    17731773                             })
    17741774        updict(info, "antialias", self.antialias)
    1775         info["cursor.size"] = self.cursor_size
     1775        info["cursor"] = {"size" : self.cursor_size}
    17761776        log("get_info took %.1fms", 1000.0*(time.time()-start))
    17771777        return info
    17781778
     
    18351835             "repeat.interval"  : self.key_repeat_interval,
    18361836             "keys_pressed"     : self.keys_pressed.values(),
    18371837             "modifiers"        : self.xkbmap_mod_meanings}
    1838         if self.keyboard_config:
    1839             for k,v in self.keyboard_config.get_info().items():
    1840                 if v is not None:
    1841                     info[k] = v
     1838        kc = self.keyboard_config
     1839        if kc:
     1840            info.update(kc.get_info())
    18421841        return info
    18431842
    18441843    def get_clipboard_info(self):
     
    18511850                "virtual-video-devices"     : self.virtual_video_devices}
    18521851
    18531852    def do_get_info(self, proto, server_sources=None, window_ids=None):
    1854         info = {"server.python.version" : python_platform.python_version()}
     1853        info = {"server" : {"python" : {"version" : python_platform.python_version()}}}
    18551854
    18561855        def up(prefix, d, suffix=""):
    18571856            updict(info, prefix, d, suffix)
     
    18701869
    18711870        info["windows"] = len([window for window in list(self._id_to_window.values()) if window.is_managed()])
    18721871        # other clients:
    1873         info["clients"] = len([p for p in self._server_sources.keys() if p!=proto])
    1874         info["clients.unauthenticated"] = len([p for p in self._potential_protocols if ((p is not proto) and (p not in self._server_sources.keys()))])
     1872        info["clients"] = {""                   : len([p for p in self._server_sources.keys() if p!=proto]),
     1873                           "unauthenticated"    : len([p for p in self._potential_protocols if ((p is not proto) and (p not in self._server_sources.keys()))])}
    18751874        #find the server source to report on:
    18761875        n = len(server_sources or [])
    18771876        if n==1:
     
    18791878            up("client", ss.get_info())
    18801879            info.update(ss.get_window_info(window_ids))
    18811880        elif n>1:
     1881            cinfo = {}
    18821882            for i, ss in enumerate(server_sources):
    1883                 up("client[%i]" % i, ss.get_info())
    1884                 wi = ss.get_window_info(window_ids)
    1885                 up("client[%i]" % i, wi)
    1886                 #this means that the last source overrides previous ones
    1887                 #(bad decision was made on the namespace for this..)
    1888                 info.update(wi)
     1883                sinfo = ss.get_info()
     1884                sinfo.update(ss.get_window_info(window_ids))
     1885                cinfo[i] = sinfo
     1886            up("client", cinfo)
    18891887        return info
    18901888
    18911889    def add_windows_info(self, info, window_ids):
     1890        winfo = {}
    18921891        for wid, window in self._id_to_window.items():
    18931892            if window_ids is not None and wid not in window_ids:
    18941893                continue
    1895             for k,v in self.get_window_info(window).items():
    1896                 wp = "window[%s]." % wid
    1897                 info[wp + k] = v
     1894            winfo[wid] = self.get_window_info(window)
     1895        updict(info, "window", winfo)
    18981896
    18991897    def get_window_info(self, window):
    19001898        from xpra.server.source import make_window_metadata
  • xpra/server/server_core.py

     
    4040from xpra.make_thread import make_thread
    4141from xpra.scripts.fdproxy import XpraProxy
    4242from xpra.server.control_command import ControlError, HelloCommand, HelpCommand, DebugControl
    43 from xpra.util import csv, typedict, updict, repr_ellipsized, dump_all_frames, \
     43from xpra.util import csv, typedict, updict, flatten_dict, repr_ellipsized, dump_all_frames, \
    4444        SERVER_SHUTDOWN, SERVER_UPGRADE, LOGIN_TIMEOUT, DONE, PROTOCOL_ERROR, SERVER_ERROR, VERSION_ERROR, CLIENT_REQUEST
    4545
    4646main_thread = threading.current_thread()
     
    877877        self.get_all_info(self.do_send_info, proto)
    878878
    879879    def do_send_info(self, proto, info):
    880         proto.send_now(("hello", info))
     880        proto.send_now(("hello", flatten_dict(info)))
    881881
    882882    def get_all_info(self, callback, proto=None, *args):
    883883        ui_info = self.get_ui_info(proto, *args)
     
    928928                "executable"        : sys.executable,
    929929                })
    930930        if self.session_name:
    931             info["session.name"] = self.session_name
     931            info["session"] = {"name" : self.session_name}
    932932        if self.child_reaper:
    933933            info.update(self.child_reaper.get_info())
    934934        return info
  • xpra/server/source.py

     
    4141from xpra.make_thread import make_thread
    4242from xpra.os_util import platform_name, Queue, get_machine_id, get_user_uuid
    4343from xpra.server.background_worker import add_work_item
    44 from xpra.util import csv, std, typedict, updict, get_screen_info, CLIENT_PING_TIMEOUT, WORKSPACE_UNSET, DEFAULT_METADATA_SUPPORTED
     44from xpra.util import csv, std, typedict, updict, flatten_dict, notypedict, get_screen_info, CLIENT_PING_TIMEOUT, WORKSPACE_UNSET, DEFAULT_METADATA_SUPPORTED
    4545
    4646
    4747NOYIELD = os.environ.get("XPRA_YIELD") is None
     
    371371        self.client_release = None
    372372        self.client_proxy = False
    373373        self.auto_refresh_delay = 0
     374        self.info_namespace = False
    374375        self.send_cursors = False
    375376        self.send_bell = False
    376377        self.send_notifications = False
     
    665666        self.lzo = c.boolget("lzo", False) and compression.use_lzo
    666667        self.send_windows = self.ui_client and c.boolget("windows", True)
    667668        self.pointer_grabs = c.boolget("pointer.grabs")
     669        self.info_namespace = c.boolget("info-namespace")
    668670        self.send_cursors = self.send_windows and c.boolget("cursors")
    669671        self.send_bell = c.boolget("bell")
    670672        self.send_notifications = c.boolget("notifications")
     
    13501352                "suspended"         : self.suspended,
    13511353                }
    13521354        if self.desktop_size_unscaled:
    1353             info["desktop_size.unscaled"] = self.desktop_size_unscaled
     1355            info["desktop_size"] = {"unscaled" : self.desktop_size_unscaled}
    13541356
    13551357        def addattr(k, name):
    13561358            v = getattr(self, name)
     
    13601362            addattr(x, "client_"+x)
    13611363        #encoding:
    13621364        info.update({
    1363              "encodings"         : self.encodings,
    1364              "encodings.core"    : self.core_encodings,
    1365              "encoding.default"  : self.default_encoding or ""
    1366              })
    1367         def up(prefix, d):
    1368             updict(info, prefix, d)
    1369         up("encoding",      self.default_encoding_options)
    1370         up("encoding",      self.encoding_options)
    1371         up("icons",         self.icons_encoding_options)
    1372         up("connection",    self.protocol.get_info())
    1373         up("av-sync",       {"client.delay"         : self.av_sync_delay,
    1374                              "total"                : self.av_sync_delay_total,
    1375                              "delta"                : self.av_sync_delta})
     1365                     "encodings"        : {
     1366                                           ""      : self.encodings,
     1367                                           "core"  : self.core_encodings
     1368                                           },
     1369                     "icons"            : self.icons_encoding_options,
     1370                     "connection"       : self.protocol.get_info(),
     1371                     "av-sync"          : {
     1372                                           "client"     : {"delay"  : self.av_sync_delay},
     1373                                           "total"      : self.av_sync_delay_total,
     1374                                           "delta"      : self.av_sync_delta,
     1375                                           },
     1376                     })
     1377        einfo = {"default"      : self.default_encoding or ""}
     1378        einfo.update(self.default_encoding_options)
     1379        einfo.update(self.encoding_options)
     1380        info.setdefault("encoding", {}).update(einfo)
    13761381        if self.window_frame_sizes:
    1377             up("window.frame-sizes", self.window_frame_sizes)
     1382            info.setdefault("window", {}).update({"frame-sizes" : self.window_frame_sizes})
    13781383        if self.window_filters:
    13791384            i = 0
     1385            finfo = {}
    13801386            for uuid, f in self.window_filters:
    13811387                if uuid==self.uuid:
    1382                     info["window-filter[%i]" % i] = str(f)
     1388                    finfo[i] = str(f)
    13831389                    i += 1
     1390            info["window-filter"] = finfo
    13841391        info.update(self.get_sound_info())
    13851392        info.update(self.get_features_info())
    13861393        info.update(self.get_screen_info())
     
    14201427            if prop is None:
    14211428                return {"state" : "inactive"}
    14221429            return prop.get_info()
    1423         info = {}
     1430        info = {
     1431                "speaker"       : sound_info(self.supports_speaker, self.sound_source),
     1432                "microphone"    : sound_info(self.supports_microphone, self.sound_sink),
     1433                }
    14241434        for prop in ("pulseaudio_id", "pulseaudio_server"):
    14251435            v = getattr(self, prop)
    14261436            if v is not None:
    14271437                info[prop] = v
    1428         for k,v in sound_info(self.supports_speaker, self.sound_source).items():
    1429             info["speaker.%s" % k] = v
    1430         for k,v in sound_info(self.supports_microphone, self.sound_sink).items():
    1431             info["microphone.%s" % k] = v
    14321438        return info
    14331439
    14341440    def get_window_info(self, window_ids=[]):
     
    14351441        """
    14361442            Adds encoding and window specific information
    14371443        """
    1438         info = {
    1439             "damage.compression_queue.size.current" : self.encode_work_queue.qsize(),
    1440             "damage.packet_queue.size.current"      : len(self.packet_queue),
    1441             }
     1444        info = {"damage"    : {
     1445                               "compression_queue"  : {"size" : {"current" : self.encode_work_queue.qsize()}},
     1446                               "packet_queue"       : {"size" : {"current" : len(self.packet_queue)}},
     1447                               },
     1448                "batch"     : self.global_batch_config.get_info(),
     1449                }
    14421450        qpixels = [x[2] for x in list(self.packet_queue)]
    14431451        add_list_stats(info, "packet_queue_pixels",  qpixels)
    14441452        if len(qpixels)>0:
    1445             info["packet_queue_pixels.current"] = qpixels[-1]
     1453            info["packet_queue_pixels"] = {"current" : qpixels[-1]}
    14461454
    14471455        info.update(self.statistics.get_info())
    14481456
     
    14501458            total_pixels = 0
    14511459            total_time = 0.0
    14521460            in_latencies, out_latencies = [], []
     1461            winfo = {}
    14531462            for wid in window_ids:
    14541463                ws = self.window_sources.get(wid)
    14551464                if ws is None:
    14561465                    continue
    14571466                #per-window source stats:
    1458                 updict(info, "window[%i]" % wid, ws.get_info())
     1467                winfo[wid] = ws.get_info()
    14591468                #collect stats for global averages:
    14601469                for _, _, pixels, _, _, encoding_time in list(ws.statistics.encoding_stats):
    14611470                    total_pixels += pixels
     
    14621471                    total_time += encoding_time
    14631472                in_latencies += [x*1000 for _, _, _, x in list(ws.statistics.damage_in_latency)]
    14641473                out_latencies += [x*1000 for _, _, _, x in list(ws.statistics.damage_out_latency)]
     1474            info["window"] = winfo
    14651475            v = 0
    14661476            if total_time>0:
    14671477                v = int(total_pixels / total_time)
    1468             info["encoding.pixels_encoded_per_second"] = v
     1478            info.setdefault("encoding", {})["pixels_encoded_per_second"] = v
    14691479            add_list_stats(info, "damage.in_latency",  in_latencies, show_percentile=[9])
    14701480            add_list_stats(info, "damage.out_latency",  out_latencies, show_percentile=[9])
    1471         updict(info, "batch", self.global_batch_config.get_info())
    14721481        return info
    14731482
    14741483
    14751484    def send_info_response(self, info):
    1476         self.send("info-response", info)
     1485        if self.info_namespace:
     1486            v = notypedict(info)
     1487        else:
     1488            v = flatten_dict(info)
     1489        self.send("info-response", v)
    14771490
    14781491
    14791492    def send_server_event(self, *args):
  • xpra/server/source_stats.py

     
    144144
    145145
    146146    def get_info(self):
    147         info = {
    148             "damage.events"                     : self.damage_events_count,
    149             "damage.packets_sent"               : self.packet_count,
    150             "encoding.decode_errors"            : self.decode_errors,
     147        info = {"damage" : {
     148                            "events"        : self.damage_events_count,
     149                            "packets_sent"  : self.packet_count,
     150                            },
     151                "encoding" : {"decode_errors"   : self.decode_errors},
    151152            }
    152153        qsizes = [x for _,x in list(self.compression_work_qsizes)]
    153154        add_list_stats(info, "damage.data_queue.size",  qsizes)
  • xpra/server/window/window_source.py

     
    4747LOG_THEME_DEFAULT_ICONS = os.environ.get("XPRA_LOG_THEME_DEFAULT_ICONS", "0")=="1"
    4848
    4949
    50 from xpra.util import updict
    5150from xpra.os_util import StringIOClass, memoryview_to_bytes
    5251from xpra.server.window.window_stats import WindowPerformanceStatistics
    5352from xpra.server.window.batch_config import DamageBatchConfig
     
    316315        """
    317316            Add window specific stats
    318317        """
     318        #"encoding" info:
     319        einfo = self.get_quality_speed_info()
     320        einfo.update({
     321                      ""                    : self.encoding,
     322                      "lossless_threshold"  : {
     323                                               "base"           : self._lossless_threshold_base,
     324                                               "pixel_boost"    : self._lossless_threshold_pixel_boost
     325                                               },
     326                      })
     327        try:
     328            #ie: get_strict_encoding -> "strict_encoding"
     329            einfo["selection"] = self.get_best_encoding.__name__.replace("get_", "")
     330        except:
     331            pass
     332
     333        #"encodings" info:
     334        esinfo = {
     335                  ""                : self.encodings,
     336                  "core"            : self.core_encodings,
     337                  "auto-refresh"    : self.client_refresh_encodings,
     338                  }
     339        larm = self.last_auto_refresh_message
     340        if larm:
     341            esinfo = {"auto-refresh"    : {
     342                                           "last-event" : {
     343                                                           "elapsed"    : int(1000*(time.time()-larm[0])),
     344                                                           "message"    : larm[1],
     345                                                           }
     346                                           }
     347                      }
     348
     349        now = time.time()
     350        buckets_info = {}
     351        for i,x in enumerate(self.delta_pixel_data):
     352            if x:
     353                w, h, pixel_format, coding, store, buflen, _, hits, last_used = x
     354                buckets_info[i] = w, h, pixel_format, coding, store, buflen, hits, int((now-last_used)*1000)
    319355        info = {
    320356                "dimensions"            : self.window_dimensions,
    321                 "encoding"              : self.encoding,
    322                 "suspended"             : self.suspended or False
    323                 }
    324         def up(prefix, d):
    325             updict(info, prefix, d)
    326 
    327         up("av-sync",       {"current"  : self.av_sync_delay,
    328                              "target"   : self.av_sync_delay_target})
    329         #heuristics
    330         up("encoding.lossless_threshold", {
    331                 "base"                  : self._lossless_threshold_base,
    332                 "pixel_boost"           : self._lossless_threshold_pixel_boost})
    333         up("encoding", {
     357                "suspended"             : self.suspended or False,
     358                "av-sync"               : {
     359                                           "current"    : self.av_sync_delay,
     360                                           "target"     : self.av_sync_delay_target
     361                                           },
     362                "encoding"              : einfo,
     363                "encodings"             : esinfo,
    334364                "rgb_threshold"         : self._rgb_auto_threshold,
    335365                "mmap"                  : bool(self._mmap) and (self._mmap_size>0),
    336366                "last_used"             : self.encoding_last_used or "",
    337367                "full-frames-only"      : self.full_frames_only,
    338368                "supports-transparency" : self.supports_transparency,
    339                 "delta"                 : self.supports_delta,
    340                 "delta.buckets"         : self.delta_buckets,
    341                 })
     369                "delta"                 : {""               : self.supports_delta,
     370                                           "buckets"        : self.delta_buckets,
     371                                           "bucket"         : buckets_info,
     372                                           },
     373                "property"              : self.get_property_info(),
     374                "batch"                 : self.batch_config.get_info(),
     375                "soft-timeout"          : {
     376                                           "expired"        : self.soft_expired,
     377                                           "max"            : self.max_soft_expired,
     378                                           },
     379                 "rgb_formats"          : self.rgb_formats,
     380                 "icons"                : self.icons_encoding_options,
     381                 }
    342382        if self.pixel_format:
    343383            info["pixel-format"] = self.pixel_format
    344         now = time.time()
    345         for i,x in enumerate(self.delta_pixel_data):
    346             if x:
    347                 w, h, pixel_format, coding, store, buflen, _, hits, last_used = x
    348                 info["encoding.delta.bucket[%s]" % i] = w, h, pixel_format, coding, store, buflen, hits, int((now-last_used)*1000)
    349         up("encoding",  self.get_quality_speed_info())
    350         try:
    351             #ie: get_strict_encoding -> "strict_encoding"
    352             info["encoding.selection"] = self.get_best_encoding.__name__.replace("get_", "")
    353         except:
    354             pass
    355         up("property",  self.get_property_info())
    356         up("batch",     self.batch_config.get_info())
    357         up("soft-timeout", {
    358                             "expired"       : self.soft_expired,
    359                             "max"           : self.max_soft_expired
    360                             })
    361         up("encodings", {
    362                  ""                     : self.encodings,
    363                  "core"                 : self.core_encodings,
    364                  "auto-refresh"         : self.client_refresh_encodings,
    365                  "rgb_formats"          : self.rgb_formats,
    366                  })
    367         larm = self.last_auto_refresh_message
    368         if larm:
    369             up("encodings.auto-refresh.last-event", {
    370                 "elapsed"               : int(1000*(time.time()-larm[0])),
    371                 "message"               : larm[1],
    372                                                      })
    373         up("icons", self.icons_encoding_options)
    374384        idata = self.window_icon_data
    375385        if idata:
    376386            pixel_data, stride, w, h = idata
    377             up("icon", {
    378                     "width"     : w,
    379                     "height"    : h,
    380                     "stride"    : stride,
    381                     "bytes"     : len(pixel_data)
    382                                })
    383 
     387            info["icon"] = {
     388                            "width"     : w,
     389                            "height"    : h,
     390                            "stride"    : stride,
     391                            "bytes"     : len(pixel_data)
     392                            }
    384393        info.update(self.statistics.get_info())
    385394        return info
    386395
  • xpra/server/window/window_stats.py

     
    153153
    154154
    155155    def get_info(self):
    156         info = {
    157                 "damage.events"         : self.damage_events_count,
    158                 "damage.packets_sent"   : self.packet_count}
     156        info = {"damage"    : {"events"         : self.damage_events_count,
     157                               "packets_sent"   : self.packet_count}
     158                }
    159159        #encoding stats:
    160160        if len(self.encoding_stats)>0:
    161161            estats = list(self.encoding_stats)
  • xpra/server/window/window_video_source.py

     
    1515from xpra.server.window.region import merge_all            #@UnresolvedImport
    1616from xpra.server.window.video_subregion import VideoSubregion
    1717from xpra.codecs.loader import PREFERED_ENCODING_ORDER, EDGE_ENCODING_ORDER
    18 from xpra.util import updict, parse_scaling_value, engs
     18from xpra.util import parse_scaling_value, engs
    1919from xpra.log import Logger
    2020
    2121log = Logger("encoding")
     
    144144
    145145    def get_info(self):
    146146        info = WindowSource.get_info(self)
    147         def up(prefix, d):
    148             updict(info, prefix, d)
    149147        sr = self.video_subregion
    150148        if sr:
    151             up("video_subregion", sr.get_info())
     149            info["video_subregion"] = sr.get_info()
    152150        info["scaling"] = self.actual_scaling
    153151        csce = self._csc_encoder
    154152        if csce:
    155             info["csc"] = csce.get_type()
    156             up("csc", csce.get_info())
     153            info["csc"] = csce.get_info()
    157154        ve = self._video_encoder
    158155        if ve:
    159             info["encoder"] = ve.get_type()
    160             up("encoder", ve.get_info())
    161         up("encoding.pipeline_param", self.get_pipeline_info())
    162         info["encodings.non-video"] = self.non_video_encodings
    163         info["encodings.edge"] = self.edge_encoding or ""
     156            info["encoder"] = ve.get_info()
     157        info.setdefault("encodings", {}).update({
     158                                                 "non-video"    : self.non_video_encodings,
     159                                                 "edge"         : self.edge_encoding or "",
     160                                                 })
     161        einfo = {"pipeline_param" : self.get_pipeline_info()}
    164162        if self._last_pipeline_check>0:
    165             info["encoding.pipeline_last_check"] = int(1000*(time.time()-self._last_pipeline_check))
     163            einfo["pipeline_last_check"] = int(1000*(time.time()-self._last_pipeline_check))
    166164        lps = self.last_pipeline_scores
    167165        if lps:
     166            popts = {}
    168167            for i, lp in enumerate(lps):
    169                 up("encoding.pipeline_option[%s]" % i, self.get_pipeline_score_info(*lp))
     168                popts[i] = self.get_pipeline_score_info(*lp)
     169            einfo["pipeline_option"] = popts
     170        info.setdefault("encoding", {}).update(einfo)
    170171        return info
    171172
    172173    def get_pipeline_info(self):
  • xpra/simple_stats.py

     
    77# Simple statistical functions
    88
    99from math import sqrt, pow
     10from xpra.util import updict
    1011
    1112def to_std_unit(v, unit=1000):
    1213    if v>=unit**3:
     
    6970    return values_to_scaled_values(absolute_to_diff_values(data), scale_unit=scale_unit, min_scaled_value=min_scaled_value, num_values=num_values)
    7071
    7172def add_weighted_list_stats(info, basename, weighted_values, show_percentile=False):
     73    updict(info, basename, get_weighted_list_stats(weighted_values, show_percentile))
     74
     75def get_weighted_list_stats(weighted_values, show_percentile=False):
    7276    values = [x for x, _ in weighted_values]
    7377    if len(values)==0:
    74         return
    75     info["%s.min" % basename] = int(min(values))
    76     info["%s.max" % basename] = int(max(values))
     78        return {}
    7779    #weighted mean:
    7880    tw = 0
    7981    tv = 0
     
    8183        tw += w
    8284        tv += v * w
    8385    avg = tv/tw
    84     info["%s.avg" % basename] = int(avg)
     86    stats = {
     87             "min"   : int(min(values)),
     88             "max"   : int(max(values)),
     89             "avg"   : int(avg),
     90             }
    8591    if show_percentile:
    8692        #percentile
    8793        svalues = sorted(values)
     
    8894        for i in range(1,10):
    8995            pct = i*10
    9096            index = len(values)*i//10
    91             info["%s.%sp" % (basename, pct)] = int(svalues[index])
     97            stats["%ip" % pct] = int(svalues[index])
     98    return stats
    9299
     100
    93101def find_invpow(x, n):
    94102    """Finds the integer component of the n'th root of x,
    95103    an integer such that y ** n <= x < (y + 1) ** n.
     
    109117    return mid + 1
    110118
    111119def add_list_stats(info, basename, in_values, show_percentile=[5, 8, 9], show_dev=False):
     120    updict(info, basename, get_list_stats(in_values, show_percentile, show_dev))
     121
     122def get_list_stats(in_values, show_percentile=[5, 8, 9], show_dev=False):
    112123    #this may be backed by a deque/list whichi is used by other threads
    113124    #so make a copy before use:
    114125    values = list(in_values)
    115126    if len(values)==0:
    116         return
    117     info["%s.cur" % basename] = int(values[-1])
    118     info["%s.min" % basename] = int(min(values))
    119     info["%s.max" % basename] = int(max(values))
     127        return  {}
    120128    #arithmetic mean
    121129    avg = sum(values)/len(values)
    122     info["%s.avg" % basename] = int(avg)
     130    lstats = {
     131              "cur"       : int(values[-1]),
     132              "min"       : int(min(values)),
     133              "max"       : int(max(values)),
     134              "avg"       : int(avg),
     135              }
    123136    if show_dev:
    124137        p = 1           #geometric mean
    125138        h = 0           #harmonic mean
     
    133146            var += (x-avg)**2
    134147        #standard deviation:
    135148        std = sqrt(var/len(values))
    136         info["%s.std" % basename] = int(std)
     149        lstats["std"] = int(std)
    137150        if avg!=0:
    138151            #coefficient of variation
    139             info["%s.cv_pct" % basename] = int(100.0*std/avg)
     152            lstats["cv_pct"] = int(100.0*std/avg)
    140153        if counter>0 and p<float('inf'):
    141154            #geometric mean
    142155            try:
     
    143156                v = int(pow(p, 1.0/counter))
    144157            except OverflowError:
    145158                v = find_invpow(p, counter)
    146             info["%s.gm" % basename] = v
     159            lstats["gm"] = v
    147160        if h!=0:
    148161            #harmonic mean
    149             info["%s.h" % basename] = int(counter/h)
     162            lstats["h"] = int(counter/h)
    150163    if show_percentile:
    151164        #percentile
    152165        svalues = sorted(values)
     
    153166        for i in show_percentile:
    154167            pct = i*10
    155168            index = len(values)*i//10
    156             info["%s.%sp" % (basename, pct)] = int(svalues[index])
     169            lstats["%ip" % pct] = int(svalues[index])
     170    return lstats
  • xpra/sound/pulseaudio/pulseaudio_pactl_util.py

     
    174174
    175175
    176176def get_info():
    177     info = {
    178             "pulseaudio.wrapper": "pactl",
    179             "pulseaudio.found"  : has_pa(),
    180             "pulseaudio.id"     : get_pulse_id(),
    181             "pulseaudio.server" : get_pulse_server(False),
    182            }
    183177    i = 0
     178    dinfo = {}
    184179    for monitors in (True, False):
    185180        for io in (True, False):
    186181            devices = get_pa_device_options(monitors, io, log_errors=False)
    187182            for d,name in devices.items():
    188                 info["device.%s" % d] = name
     183                dinfo[d] = name
    189184                i += 1
    190     info["devices"] = i
    191     return info
     185    return {
     186            "device"        : dinfo,
     187            "devices"       : i,
     188            "pulseaudio"    : {
     189                               "wrapper"   : "pactl",
     190                               "found"     : has_pa(),
     191                               "id"        : get_pulse_id(),
     192                               "server"    : get_pulse_server(False),
     193                               }
     194            }
    192195
    193196
    194197def main():
  • xpra/sound/sink.py

     
    1414                                        MP3, CODEC_ORDER, gst, QUEUE_LEAK, GST_QUEUE_NO_LEAK, MS_TO_NS
    1515
    1616from xpra.scripts.config import InitExit
    17 from xpra.util import updict, csv
     17from xpra.util import csv
    1818from xpra.os_util import thread
    1919from xpra.log import Logger
    2020log = Logger("sound")
     
    251251            clt = self.queue.get_property("current-level-time")
    252252            qmax = self.queue.get_property("max-size-time")
    253253            qmin = self.queue.get_property("min-threshold-time")
    254             updict(info, "queue", {
    255                 "min"           : qmin//MS_TO_NS,
    256                 "max"           : qmax//MS_TO_NS,
    257                 "cur"           : clt//MS_TO_NS,
    258                 "pct"           : min(QUEUE_TIME, clt)*100//qmax,
    259                 "overruns"      : self.overruns,
    260                 "underruns"     : self.underruns,
    261                 "state"         : self.queue_state})
     254            info["queue"] = {
     255                             "min"          : qmin//MS_TO_NS,
     256                             "max"          : qmax//MS_TO_NS,
     257                             "cur"          : clt//MS_TO_NS,
     258                             "pct"          : min(QUEUE_TIME, clt)*100//qmax,
     259                             "overruns"     : self.overruns,
     260                             "underruns"    : self.underruns,
     261                             "state"        : self.queue_state
     262                             }
    262263        return info
    263264
    264265    def add_data(self, data, metadata=None):
  • xpra/sound/src.py

     
    173173        if self.caps:
    174174            info["caps"] = self.caps
    175175        if self.queue:
    176             info["queue.cur"] = self.queue.get_property("current-level-time")//MS_TO_NS
     176            info["queue"] = {"cur" : self.queue.get_property("current-level-time")//MS_TO_NS}
    177177        if self.buffer_latency:
    178178            for x in ("actual-buffer-time", "actual-latency-time"):
    179179                v = self.src.get_property(x)
  • xpra/util.py

     
    500500    return int(v+0.5)
    501501
    502502
     503def notypedict(info):
     504    def ntd(d):
     505        for k in list(d.keys()):
     506            v = d[k]
     507            if isinstance(v, dict):
     508                d[k] = ntd(v)
     509        return dict(d)
     510    return ntd(info)
     511
     512def flatten_dict(info):
     513    to = {}
     514    def add_dict(path, d):
     515        for k,v in d.items():
     516            if path:
     517                npath = path+"."+str(k)
     518            else:
     519                npath = str(k)
     520            if isinstance(v, dict):
     521                add_dict(npath, v)
     522            elif v is not None:
     523                to[npath] = v
     524    add_dict(None, info)
     525    return to
     526
    503527#used for merging dicts with a prefix and suffix
    504528#non-None values get added to <todict> with a prefix and optional suffix
    505529def updict(todict, prefix, d, suffix=""):
  • xpra/x11/server.py

     
    287287
    288288    def do_get_info(self, proto, server_sources, window_ids):
    289289        info = X11ServerBase.do_get_info(self, proto, server_sources, window_ids)
    290         info["focused"] = self._has_focus
    291         info["grabbed"] = self._has_grab
    292290        log("do_get_info: adding cursor=%s", self.last_cursor_data)
     291        info.update({
     292                     "focused"  : self._has_focus,
     293                     "grabbed"  : self._has_grab,
     294                     "cursor"   : self.get_cursor_info(),
     295                     })
     296        return info
     297
     298    def get_cursor_info(self):
     299        #(NOT from UI thread)
    293300        #copy to prevent race:
    294301        cd = self.last_cursor_data
    295302        if cd is None:
    296             info["cursor"] = "None"
    297         else:
    298             info["cursor.is_default"] = bool(self.default_cursor_data and len(self.default_cursor_data)>=8 and len(cd)>=8 and cd[7]==cd[7])
    299             #all but pixels:
    300             for i, x in enumerate(("x", "y", "width", "height", "xhot", "yhot", "serial", None, "name")):
    301                 if x:
    302                     v = cd[i] or ""
    303                     info["cursor." + x] = v
    304         return info
     303            return {"" : "None"}
     304        cinfo = {"is_default"   : bool(self.default_cursor_data and len(self.default_cursor_data)>=8 and len(cd)>=8 and cd[7]==cd[7])}
     305        #all but pixels:
     306        for i, x in enumerate(("x", "y", "width", "height", "xhot", "yhot", "serial", None, "name")):
     307            if x:
     308                v = cd[i] or ""
     309                cinfo[x] = v
     310        return cinfo
    305311
    306312    def get_ui_info(self, proto, wids=None, *args):
    307313        info = X11ServerBase.get_ui_info(self, proto, wids, *args)
     
    309315        wm = self._wm
    310316        if wm:
    311317            info["window-manager-name"] = wm.get_net_wm_name()
     318        info.setdefault("cursor", {}).update(self.get_ui_cursor_info())
     319        return info
     320
     321    def get_ui_cursor_info(self):
     322        #(from UI thread)
    312323        #now cursor size info:
    313324        display = gtk.gdk.display_get_default()
    314325        pos = display.get_default_screen().get_root_window().get_pointer()[:2]
    315         info["cursor.position"] = pos
     326        cinfo = {"position" : pos}
    316327        for prop, size in {"default" : display.get_default_cursor_size(),
    317328                           "max"     : display.get_maximal_cursor_size()}.items():
    318329            if size is None:
    319330                continue
    320             info["cursor.%s_size" % prop] = size
    321         return info
     331            cinfo["%s_size" % prop] = size
     332        return cinfo
    322333
    323334
    324335    def get_window_info(self, window):
    325336        info = X11ServerBase.get_window_info(self, window)
    326         info["focused"] = self._has_focus and self._window_to_id.get(window, -1)==self._has_focus
    327         info["grabbed"] = self._has_grab and self._window_to_id.get(window, -1)==self._has_grab
    328         info["geometry"] = window.get_property("geometry")
    329         info["shown"] = self._desktop_manager.is_shown(window)
     337        info.update({
     338                     "focused"  : self._has_focus and self._window_to_id.get(window, -1)==self._has_focus,
     339                     "grabbed"  : self._has_grab and self._window_to_id.get(window, -1)==self._has_grab,
     340                     "geometry" : window.get_property("geometry"),
     341                     "shown"    : self._desktop_manager.is_shown(window),
     342                     })
    330343        try:
    331344            info["client-geometry"] = self._desktop_manager.window_geometry(window)
    332345        except:
  • xpra/x11/server_keyboard_config.py

     
    6565
    6666    def get_info(self):
    6767        info = KeyboardConfigBase.get_info(self)
    68         info["modifiers.filter"] = self.modifiers_filter
    6968        #keycodes:
    7069        if self.keycode_translation:
    7170            for kc, keycode in self.keycode_translation.items():
     
    8281                info["keymap.%s" % i] = (keyval, name, keycode, group, level)
    8382                i += 1
    8483        #modifiers:
     84        modinfo = {}
     85        modsinfo = {}
     86        modinfo["filter"] = self.modifiers_filter
    8587        if self.modifier_client_keycodes:
    8688            for mod, keys in self.modifier_client_keycodes.items():
    87                 info["modifier." + mod + ".client_keys"] = keys
     89                modinfo.setdefault(mod, {})["client_keys"] = keys
    8890        if self.keynames_for_mod:
    8991            for mod, keys in self.keynames_for_mod.items():
    90                 info["modifier." + mod + ".keys"] = tuple(keys)
     92                modinfo.setdefault(mod, {})["keys"] = tuple(keys)
    9193        if self.keycodes_for_modifier_keynames:
    9294            for mod, keys in self.keycodes_for_modifier_keynames.items():
    93                 info["modifier." + mod + ".keycodes"] = tuple(keys)
     95                modinfo.setdefault(mod, {})["keycodes"] = tuple(keys)
    9496        if self.xkbmap_mod_meanings:
    9597            for mod, mod_name in self.xkbmap_mod_meanings.items():
    96                 info["modifier." + mod ] = mod_name
    97         if self.xkbmap_x11_keycodes:
    98             for keycode, keysyms in self.xkbmap_x11_keycodes.items():
    99                 info["x11_keycode." + str(keycode) ] = keysyms
     98                modinfo[mod] = mod_name
     99        info["x11_keycode"] = self.xkbmap_x11_keycodes
    100100        for x in ("print", "layout", "variant"):
    101101            v = getattr(self, "xkbmap_"+x)
    102102            if v:
     
    104104        for x in ("nuisance", ):
    105105            v = getattr(self, "xkbmap_mod_"+x)
    106106            if v:
    107                 info["modifiers."+x] = list(v)
     107                modsinfo[x] = list(v)
    108108        for x in ("managed", "pointermissing"):
    109109            v = getattr(self, "xkbmap_mod_"+x)
    110110            if v:
    111                 info["modifiers."+x] = v
     111                modsinfo[x] = v
     112        info["modifier"] = modinfo
     113        info["modifiers"] = modsinfo
    112114        log("keyboard info: %s", "\n".join(["%s=%s" % (k,v) for k,v in info.items()]))
    113115        return info
    114116
  • xpra/x11/shadow_x11_server.py

     
    9595
    9696    def get_info(self, proto):
    9797        info = X11ServerBase.get_info(self, proto)
    98         info["features.shadow"] = True
    99         info["server.type"] = "Python/gtk2/x11-shadow"
     98        info.setdefault("features", {})["shadow"] = True
     99        info.setdefault("server", {})["type"] = "Python/gtk2/x11-shadow"
    100100        return info
  • xpra/x11/x11_server_base.py

     
    127127                    v = parts[1].strip()
    128128                    self.opengl_props[k] = v
    129129            else:
    130                 self.opengl_props["error"] = str(err)
     130                self.opengl_props["error"] = str(err).strip("\n\r")
    131131        except Exception as e:
    132132            gllog.warn("Warning: failed to query OpenGL properties")
    133133            gllog.warn(" %s", e)
     
    214214        return capabilities
    215215
    216216    def do_get_info(self, proto, server_sources, window_ids):
    217         from xpra.util import updict
    218217        info = GTKServerBase.do_get_info(self, proto, server_sources, window_ids)
    219218        if self.opengl_props:
    220             updict(info, "opengl", self.opengl_props)
    221         info["server.type"] = "Python/gtk/x11"
     219            info["opengl"] = self.opengl_props
     220        #this is added here because the server keyboard config doesn't know about "keys_pressed"..
     221        info["keyboard"] = {
     222                            "state"           : {"keys_pressed"   : list(self.keys_pressed.keys())},
     223                            "fast-switching"  : True,
     224                            }
    222225        try:
     226            fx = find_libfakeXinerama()
     227        except:
     228            fx = None
     229        sinfo = {"type"             : "Python/gtk/x11",
     230                 "fakeXinerama"     : self.fake_xinerama and bool(fx),
     231                 "libfakeXinerama"  : fx or "",
     232                 "Xkb"              : X11Keyboard.hasXkb(),
     233                 "XTest"            : X11Keyboard.hasXTest()}
     234        try:
    223235            from xpra.x11.gtk2.composite import CompositeHelper
    224             info["server.XShm"] = CompositeHelper.XShmEnabled
     236            sinfo["XShm"] = CompositeHelper.XShmEnabled
    225237        except:
    226238            pass
    227239        #randr:
     
    228240        try:
    229241            sizes = RandR.get_screen_sizes()
    230242            if self.randr and len(sizes)>=0:
    231                 info["server.randr.options"] = list(reversed(sorted(sizes)))
     243                sinfo["randr"] = {"options" : list(reversed(sorted(sizes)))}
    232244        except:
    233245            pass
    234         try:
    235             fx = find_libfakeXinerama()
    236         except:
    237             fx = None
    238         info["server.fakeXinerama"] = self.fake_xinerama and bool(fx)
    239         info["server.libfakeXinerama"] = fx or ""
    240         #this is added here because the server keyboard config doesn't know about "keys_pressed"..
    241         info["keyboard.state.keys_pressed"] = list(self.keys_pressed.keys())
    242         info["keyboard.fast-switching"] = True
    243         info["server.Xkb"] = X11Keyboard.hasXkb()
    244         info["server.XTest"] = X11Keyboard.hasXTest()
     246        info["server"] = sinfo
    245247        return info
    246248
    247249    def get_window_info(self, window):