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.patch

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

work in progress patch

  • xpra/child_reaper.py

     
    186186
    187187    def get_info(self):
    188188        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])}
     189        info = {"children"  : {""           : len(iv),
     190                               "dead"       : len([x for x in iv if x.dead]),
     191                               "ignored"    : len([x for x in iv if x.ignore])}}
    192192        pi = sorted(self._proc_info, key=lambda x: x.pid, reverse=True)
     193        cinfo = {}
    193194        for i, procinfo in enumerate(pi):
    194195            d = dict((k,getattr(procinfo,k)) for k in ("name", "command", "ignore", "forget", "returncode", "dead", "pid"))
    195             updict(info, "child[%i]" % i, d)
     196            cinfo[i] = d
     197        updict(info, "child", cinfo)
    196198        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/ui_client_base.py

     
    24202420            ss.add_data(data, metadata)
    24212421        if self.av_sync and self.server_av_sync:
    24222422            info = ss.get_info()
    2423             queue_used = info.get("queue.cur")
     2423            queue_used = info.get("queue.cur") or info.get("queue", {}).get("cur")
    24242424            if queue_used is None:
    24252425                return
    24262426            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/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

     
    15861586                "encoder_height"    : self.encoder_height,
    15871587                "bitrate"           : self.target_bitrate,
    15881588                "quality"           : self.quality,
    1589                 "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,
     1589                "speed"             : self.speed})
     1590        updict(info, "lossless", {
     1591                ""          : self.lossless,
     1592                "supported" : LOSSLESS_ENABLED,
     1593                "threshold" : LOSSLESS_THRESHOLD})
     1594        updict(info, "yuv444", {
     1595                "supported" : YUV444_ENABLED,
     1596                "threshold" : YUV444_THRESHOLD,
    15951597                })
    15961598        if self.scaling!=(1,1):
    15971599            info.update({
  • xpra/codecs/nvenc5/encoder.pyx

     
    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,
    16331628                })
     1629        updict(info, "lossless", {
     1630                ""          : self.lossless,
     1631                "supported" : LOSSLESS_ENABLED,
     1632                "threshold" : LOSSLESS_THRESHOLD})
     1633        updict(info, "yuv444", {
     1634                "supported" : YUV444_ENABLED,
     1635                "threshold" : YUV444_THRESHOLD,
     1636                })
    16341637        if self.scaling!=(1,1):
    16351638            info.update({
    16361639                "input_width"       : self.input_width,
  • xpra/codecs/nvenc6/encoder.pyx

     
    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,
    17041699                })
     1700        updict(info, "lossless", {
     1701                ""          : self.lossless,
     1702                "supported" : LOSSLESS_ENABLED,
     1703                "threshold" : LOSSLESS_THRESHOLD})
     1704        updict(info, "yuv444", {
     1705                "supported" : YUV444_ENABLED,
     1706                "threshold" : YUV444_THRESHOLD,
     1707                })
    17051708        if self.scaling!=(1,1):
    17061709            info.update({
    17071710                "input_width"       : self.input_width,
  • 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
  • xpra/net/protocol.py

     
    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,
    223215            "max_packet_size"       : self.max_packet_size}
    224         updict(info, "input.count", self.input_stats)
    225         updict(info, "output.count", self.output_stats)
     216        updict(info, "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        updict(info, "output", {
     224            "packetcount"           : self.output_packetcount,
     225            "raw_packetcount"       : self.output_raw_packetcount,
     226            "count"                 : self.output_stats,
     227            "cipher"                : {"": self.cipher_out_name or "",
     228                                       "padding" : self.cipher_out_padding},
     229            })
    226230        c = self._compress
    227231        if c:
    228232            info["compressor"] = compression.get_compressor_name(self._compress)
     
    233237            else:
    234238                info["encoder"] = packet_encoding.get_encoder_name(self._encoder)
    235239        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
     240            info["send_alias"] = self.send_aliases
     241            info["receive_alias"] = self.receive_aliases
    242242        c = self._conn
    243243        if c:
    244244            try:
     
    248248        info["has_more"] = self._source_has_more.is_set()
    249249        for t in (self._write_thread, self._read_thread, self._read_parser_thread, self._write_format_thread):
    250250            if t:
    251                 info["thread.%s" % t.name] = t.is_alive()
     251                info.setdefault("thread", {})[t.name] = t.is_alive()
    252252        return info
    253253
    254254
  • 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

     
    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(),
    171167            }
    172168    from xpra.util import updict
     169    updict("double_click", {
     170                            "time"          : get_double_click_time(),
     171                            "distance"      : get_double_click_distance(),
     172                            })
     173    updict("dpi", {
     174                   "x"                      : get_xdpi(),
     175                   "y"                      : get_ydpi()
     176                   })
    173177    updict(info, "antialias", get_antialias_info())
    174178    updict(info, "window_frame", get_window_frame_sizes())
    175179    return info
  • 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        updict(i, "xsettings", xi)
     463    i.setdefault("dpi", {
     464                         "xsettings"    : _get_xsettings_dpi(),
     465                         "randr"        : _get_randr_dpi()})
    464466    return i
    465467
    466468
  • xpra/server/gtk_server_base.py

     
    8888
    8989    def do_get_info(self, proto, *args):
    9090        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})
     91        vi = get_gtk_version_info()
     92        vi["type"] = "Python/gtk-x11"
     93        info.setdefault("server", {}).update(vi)
     94        info.setdefault("features", {})["randr"] = self.randr
    9595        return info
    9696
    9797    def get_root_window_size(self):
  • 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, get_screen_info, CLIENT_PING_TIMEOUT, WORKSPACE_UNSET, DEFAULT_METADATA_SUPPORTED
    4545
    4646
    4747NOYIELD = os.environ.get("XPRA_YIELD") is None
     
    13501350                "suspended"         : self.suspended,
    13511351                }
    13521352        if self.desktop_size_unscaled:
    1353             info["desktop_size.unscaled"] = self.desktop_size_unscaled
     1353            info["desktop_size"] = {"unscaled" : self.desktop_size_unscaled}
    13541354
    13551355        def addattr(k, name):
    13561356            v = getattr(self, name)
     
    13601360            addattr(x, "client_"+x)
    13611361        #encoding:
    13621362        info.update({
    1363              "encodings"         : self.encodings,
    1364              "encodings.core"    : self.core_encodings,
    1365              "encoding.default"  : self.default_encoding or ""
     1363             "encodings"         : {""      : self.encodings,
     1364                                    "core"  : self.core_encodings},
    13661365             })
     1366        info.setdefault("encoding", {})["default"] = self.default_encoding or ""
    13671367        def up(prefix, d):
    13681368            updict(info, prefix, d)
    13691369        up("encoding",      self.default_encoding_options)
     
    13701370        up("encoding",      self.encoding_options)
    13711371        up("icons",         self.icons_encoding_options)
    13721372        up("connection",    self.protocol.get_info())
    1373         up("av-sync",       {"client.delay"         : self.av_sync_delay,
     1373        up("av-sync",       {"client"               : {"delay"  : self.av_sync_delay},
    13741374                             "total"                : self.av_sync_delay_total,
    13751375                             "delta"                : self.av_sync_delta})
    13761376        if self.window_frame_sizes:
    1377             up("window.frame-sizes", self.window_frame_sizes)
     1377            up("window", {"frame-sizes" : self.window_frame_sizes})
    13781378        if self.window_filters:
    13791379            i = 0
     1380            finfo = {}
    13801381            for uuid, f in self.window_filters:
    13811382                if uuid==self.uuid:
    1382                     info["window-filter[%i]" % i] = str(f)
     1383                    finfo[i] = str(f)
    13831384                    i += 1
     1385            up("window-filter", finfo)
    13841386        info.update(self.get_sound_info())
    13851387        info.update(self.get_features_info())
    13861388        info.update(self.get_screen_info())
     
    14251427            v = getattr(self, prop)
    14261428            if v is not None:
    14271429                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
     1430        updict(info, "speaker",     sound_info(self.supports_speaker, self.sound_source))
     1431        updict(info, "microphone",  sound_info(self.supports_microphone, self.sound_sink))
    14321432        return info
    14331433
    14341434    def get_window_info(self, window_ids=[]):
     
    14351435        """
    14361436            Adds encoding and window specific information
    14371437        """
    1438         info = {
    1439             "damage.compression_queue.size.current" : self.encode_work_queue.qsize(),
    1440             "damage.packet_queue.size.current"      : len(self.packet_queue),
    1441             }
     1438        info = {"damage"    : {
     1439                               "compression_queue"  : {"size" : {"current" : self.encode_work_queue.qsize()}},
     1440                               "packet_queue"       : {"size" : {"current" : len(self.packet_queue)}},
     1441                               }
     1442                }
    14421443        qpixels = [x[2] for x in list(self.packet_queue)]
    14431444        add_list_stats(info, "packet_queue_pixels",  qpixels)
    14441445        if len(qpixels)>0:
    1445             info["packet_queue_pixels.current"] = qpixels[-1]
     1446            info["packet_queue_pixels"] = {"current" : qpixels[-1]}
    14461447
    14471448        info.update(self.statistics.get_info())
    14481449
     
    14501451            total_pixels = 0
    14511452            total_time = 0.0
    14521453            in_latencies, out_latencies = [], []
     1454            winfo = {}
    14531455            for wid in window_ids:
    14541456                ws = self.window_sources.get(wid)
    14551457                if ws is None:
    14561458                    continue
    14571459                #per-window source stats:
    1458                 updict(info, "window[%i]" % wid, ws.get_info())
     1460                winfo[wid] = ws.get_info()
    14591461                #collect stats for global averages:
    14601462                for _, _, pixels, _, _, encoding_time in list(ws.statistics.encoding_stats):
    14611463                    total_pixels += pixels
     
    14621464                    total_time += encoding_time
    14631465                in_latencies += [x*1000 for _, _, _, x in list(ws.statistics.damage_in_latency)]
    14641466                out_latencies += [x*1000 for _, _, _, x in list(ws.statistics.damage_out_latency)]
     1467            updict(info, "window", winfo)
    14651468            v = 0
    14661469            if total_time>0:
    14671470                v = int(total_pixels / total_time)
    1468             info["encoding.pixels_encoded_per_second"] = v
     1471            info.setdefault("encoding", {})["pixels_encoded_per_second"] = v
    14691472            add_list_stats(info, "damage.in_latency",  in_latencies, show_percentile=[9])
    14701473            add_list_stats(info, "damage.out_latency",  out_latencies, show_percentile=[9])
    14711474        updict(info, "batch", self.global_batch_config.get_info())
     
    14731476
    14741477
    14751478    def send_info_response(self, info):
    1476         self.send("info-response", info)
     1479        self.send("info-response", flatten_dict(info))
    14771480
    14781481
    14791482    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

     
    318318        """
    319319        info = {
    320320                "dimensions"            : self.window_dimensions,
    321                 "encoding"              : self.encoding,
    322321                "suspended"             : self.suspended or False
    323322                }
    324323        def up(prefix, d):
     
    327326        up("av-sync",       {"current"  : self.av_sync_delay,
    328327                             "target"   : self.av_sync_delay_target})
    329328        #heuristics
    330         up("encoding.lossless_threshold", {
    331                 "base"                  : self._lossless_threshold_base,
    332                 "pixel_boost"           : self._lossless_threshold_pixel_boost})
     329        up("encoding", {""                      : self.encoding,
     330                        "lossless_threshold"    : {
     331                                                   "base"           : self._lossless_threshold_base,
     332                                                   "pixel_boost"    : self._lossless_threshold_pixel_boost}
     333                        })
     334        now = time.time()
     335        buckets_info = {}
     336        for i,x in enumerate(self.delta_pixel_data):
     337            if x:
     338                w, h, pixel_format, coding, store, buflen, _, hits, last_used = x
     339                buckets_info[i] = w, h, pixel_format, coding, store, buflen, hits, int((now-last_used)*1000)
    333340        up("encoding", {
    334341                "rgb_threshold"         : self._rgb_auto_threshold,
    335342                "mmap"                  : bool(self._mmap) and (self._mmap_size>0),
     
    336343                "last_used"             : self.encoding_last_used or "",
    337344                "full-frames-only"      : self.full_frames_only,
    338345                "supports-transparency" : self.supports_transparency,
    339                 "delta"                 : self.supports_delta,
    340                 "delta.buckets"         : self.delta_buckets,
     346                "delta"                 : {""           : self.supports_delta,
     347                                           "buckets"    : self.delta_buckets,
     348                                           "bucket"     : buckets_info,
     349                                           },
    341350                })
    342351        if self.pixel_format:
    343352            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)
    349353        up("encoding",  self.get_quality_speed_info())
    350354        try:
    351355            #ie: get_strict_encoding -> "strict_encoding"
    352             info["encoding.selection"] = self.get_best_encoding.__name__.replace("get_", "")
     356            info["encoding"]["selection"] = self.get_best_encoding.__name__.replace("get_", "")
    353357        except:
    354358            pass
    355359        up("property",  self.get_property_info())
     
    366370                 })
    367371        larm = self.last_auto_refresh_message
    368372        if larm:
    369             up("encodings.auto-refresh.last-event", {
    370                 "elapsed"               : int(1000*(time.time()-larm[0])),
    371                 "message"               : larm[1],
    372                                                      })
     373            up("encodings", {"auto-refresh" : {"last-event" : {
     374                                                              "elapsed" : int(1000*(time.time()-larm[0])),
     375                                                              "message" : larm[1],
     376                                                              }
     377                                              }
     378                             })
    373379        up("icons", self.icons_encoding_options)
    374380        idata = self.window_icon_data
    375381        if idata:
  • 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

     
    158158        if ve:
    159159            info["encoder"] = ve.get_type()
    160160            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 ""
     161        info["encodings"] = {"non-video"    : self.non_video_encodings,
     162                             "edge"         : self.edge_encoding or ""}
     163        einfo = {"pipeline_param" : self.get_pipeline_info()}
    164164        if self._last_pipeline_check>0:
    165             info["encoding.pipeline_last_check"] = int(1000*(time.time()-self._last_pipeline_check))
     165            einfo["pipeline_last_check"] = int(1000*(time.time()-self._last_pipeline_check))
    166166        lps = self.last_pipeline_scores
    167167        if lps:
     168            popts = {}
    168169            for i, lp in enumerate(lps):
    169                 up("encoding.pipeline_option[%s]" % i, self.get_pipeline_score_info(*lp))
     170                popts[i] = self.get_pipeline_score_info(*lp)
     171            einfo["pipeline_option"] = popts
     172        up("encoding", einfo)
    170173        return info
    171174
    172175    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

     
    99
    1010from xpra.sound.pulseaudio.pulseaudio_common_util import get_pulse_server_x11_property, get_pulse_id_x11_property
    1111from xpra.scripts.exec_util import safe_exec
    12 from xpra.util import nonl
     12from xpra.util import nonl, updict
    1313
    1414from xpra.log import Logger
    1515log = Logger("sound")
     
    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            }
     177    info = {}
     178    updict(info, "pulseaudio", {
     179                                "wrapper"   : "pactl",
     180                                "found"     : has_pa(),
     181                                "id"        : get_pulse_id(),
     182                                "server"    : get_pulse_server(False),
     183                                })
    183184    i = 0
     185    dinfo = {}
    184186    for monitors in (True, False):
    185187        for io in (True, False):
    186188            devices = get_pa_device_options(monitors, io, log_errors=False)
    187189            for d,name in devices.items():
    188                 info["device.%s" % d] = name
     190                dinfo[d] = name
    189191                i += 1
     192    info["device"] = dinfo
    190193    info["devices"] = i
    191194    return info
    192195
  • 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
     503
     504def flatten_dict(info):
     505    to = {}
     506    def add_dict(path, d):
     507        for k,v in d.items():
     508            if path:
     509                npath = path+"."+str(k)
     510            else:
     511                npath = str(k)
     512            if isinstance(v, dict):
     513                add_dict(npath, v)
     514            elif v is not None:
     515                to[npath] = v
     516    add_dict(None, info)
     517    return to
     518
    503519#used for merging dicts with a prefix and suffix
    504520#non-None values get added to <todict> with a prefix and optional suffix
    505521def updict(todict, prefix, d, suffix=""):
  • xpra/x11/server.py

     
    290290        info["focused"] = self._has_focus
    291291        info["grabbed"] = self._has_grab
    292292        log("do_get_info: adding cursor=%s", self.last_cursor_data)
     293        updict(info, "cursor", self.get_cursor_info())
     294        return info
     295
     296    def get_cursor_info(self):
     297        #(NOT from UI thread)
    293298        #copy to prevent race:
    294299        cd = self.last_cursor_data
    295300        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
     301            return {"" : "None"}
     302        cinfo = {"is_default"   : bool(self.default_cursor_data and len(self.default_cursor_data)>=8 and len(cd)>=8 and cd[7]==cd[7])}
     303        #all but pixels:
     304        for i, x in enumerate(("x", "y", "width", "height", "xhot", "yhot", "serial", None, "name")):
     305            if x:
     306                v = cd[i] or ""
     307                cinfo[x] = v
     308        return cinfo
    305309
    306310    def get_ui_info(self, proto, wids=None, *args):
    307311        info = X11ServerBase.get_ui_info(self, proto, wids, *args)
     
    309313        wm = self._wm
    310314        if wm:
    311315            info["window-manager-name"] = wm.get_net_wm_name()
     316        info.setdefault("cursor", {}).update(self.get_ui_cursor_info())
     317        return info
     318
     319    def get_ui_cursor_info(self):
     320        #(from UI thread)
    312321        #now cursor size info:
    313322        display = gtk.gdk.display_get_default()
    314323        pos = display.get_default_screen().get_root_window().get_pointer()[:2]
    315         info["cursor.position"] = pos
     324        cinfo = {"position" : pos}
    316325        for prop, size in {"default" : display.get_default_cursor_size(),
    317326                           "max"     : display.get_maximal_cursor_size()}.items():
    318327            if size is None:
    319328                continue
    320             info["cursor.%s_size" % prop] = size
    321         return info
     329            cinfo["%s_size" % prop] = size
     330        return cinfo
    322331
    323332
    324333    def get_window_info(self, window):
    325334        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)
     335        info.update({
     336                     "focused"  : self._has_focus and self._window_to_id.get(window, -1)==self._has_focus,
     337                     "grabbed"  : self._has_grab and self._window_to_id.get(window, -1)==self._has_grab,
     338                     "geometry" : window.get_property("geometry"),
     339                     "shown"    : self._desktop_manager.is_shown(window),
     340                     })
    330341        try:
    331342            info["client-geometry"] = self._desktop_manager.window_geometry(window)
    332343        except:
  • xpra/x11/server_keyboard_config.py

     
    1212log = Logger("keyboard")
    1313
    1414
    15 from xpra.util import csv
     15from xpra.util import csv, updict
    1616from xpra.gtk_common.keymap import get_gtk_keymap
    1717from xpra.x11.gtk_x11.keys import grok_modifier_map
    1818from xpra.keyboard.mask import DEFAULT_MODIFIER_NUISANCE, DEFAULT_MODIFIER_NUISANCE_KEYNAMES, mask_to_names
     
    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        updict(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        updict(info, "modifier", modinfo)
     113        updict(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)
     
    218218        info = GTKServerBase.do_get_info(self, proto, server_sources, window_ids)
    219219        if self.opengl_props:
    220220            updict(info, "opengl", self.opengl_props)
    221         info["server.type"] = "Python/gtk/x11"
     221        #this is added here because the server keyboard config doesn't know about "keys_pressed"..
     222        updict(info, "keyboard", {
     223                                  "state"           : {"keys_pressed"   : list(self.keys_pressed.keys())},
     224                                  "fast-switching"  : True,
     225                                  })
    222226        try:
     227            fx = find_libfakeXinerama()
     228        except:
     229            fx = None
     230        sinfo = {"type"             : "Python/gtk/x11",
     231                 "fakeXinerama"     : self.fake_xinerama and bool(fx),
     232                 "libfakeXinerama"  : fx or "",
     233                 "Xkb"              : X11Keyboard.hasXkb(),
     234                 "XTest"            : X11Keyboard.hasXTest()}
     235        try:
    223236            from xpra.x11.gtk2.composite import CompositeHelper
    224             info["server.XShm"] = CompositeHelper.XShmEnabled
     237            sinfo["XShm"] = CompositeHelper.XShmEnabled
    225238        except:
    226239            pass
    227240        #randr:
     
    228241        try:
    229242            sizes = RandR.get_screen_sizes()
    230243            if self.randr and len(sizes)>=0:
    231                 info["server.randr.options"] = list(reversed(sorted(sizes)))
     244                sinfo["randr"] = {"options" : list(reversed(sorted(sizes)))}
    232245        except:
    233246            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()
     247        updict(info, "server", sinfo)
    245248        return info
    246249
    247250    def get_window_info(self, window):