Skip to content

Commit

Permalink
#2539 add window info to header menu
Browse files Browse the repository at this point in the history
git-svn-id: https://xpra.org/svn/Xpra/trunk@26322 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed May 12, 2020
1 parent 6826fdc commit 2b48464
Show file tree
Hide file tree
Showing 2 changed files with 261 additions and 4 deletions.
18 changes: 14 additions & 4 deletions src/xpra/client/gtk3/window_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,26 @@ def __init__(self, client, window):

def setup_menu(self):
menu = Gtk.Menu()
menu.append(self.make_closemenuitem())
#menu.append(self.make_closemenuitem())
menu.connect("deactivate", self.menu_deactivated)
menu.append(self.make_aboutmenuitem())
if self.client.client_supports_opengl:
menu.append(self.make_openglmenuitem())
#menu.append(self.make_aboutmenuitem())
menu.append(self.make_infomenuitem())
#if self.client.client_supports_opengl:
# menu.append(self.make_openglmenuitem())
menu.append(self.make_refreshmenuitem())
menu.append(self.make_reinitmenuitem())
menu.show_all()
return menu

def make_infomenuitem(self):
def show_info(*_args):
from xpra.client.gtk_base.window_info import WindowInfo
wi = WindowInfo(self.client, self.window)
wi.show()
gl = self.menuitem("Window Information", "information.png", "Window state and details", show_info)
gl.set_tooltip_text()
return gl

def make_openglmenuitem(self):
gl = self.checkitem("OpenGL")
gl.set_tooltip_text("hardware accelerated rendering using OpenGL")
Expand Down
247 changes: 247 additions & 0 deletions src/xpra/client/gtk_base/window_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
# -*- coding: utf-8 -*-
# This file is part of Xpra.
# Copyright (C) 2020 Antoine Martin <[email protected]>
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

from gi.repository import Gtk, GLib

from xpra.util import typedict, csv, WORKSPACE_UNSET
from xpra.os_util import bytestostr
from xpra.client import mixin_features
from xpra.common import GRAVITY_STR
from xpra.gtk_common.gtk_util import (
add_close_accel, label,
TableBuilder, imagebutton, get_gtk_version_info,
)
from xpra.log import Logger

log = Logger("info")


def slabel(text="", tooltip=None, font=None):
l = label(text, tooltip, font)
l.set_selectable(True)
return l


def x(self):
self.size_constraints = typedict()
self.geometry_hints = {}
self.pending_refresh = []


class WindowInfo(Gtk.Window):

def __init__(self, client, window):
Gtk.Window.__init__(self)
add_close_accel(self, self.destroy)
self._client = client
self._window = window
self.is_closed = False
self.set_title("Window Information for %s" % window.get_title())
self.set_destroy_with_parent(True)
self.set_resizable(True)
self.set_decorated(True)
self.set_size_request(480, 640)
self.set_transient_for(window)
self.set_icon(client.get_pixbuf("information.png"))
self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
def window_deleted(*_args):
self.is_closed = True
self.connect('delete_event', window_deleted)

tb = TableBuilder(1, 2)
self.wid_label = slabel()
tb.new_row("Window ID", self.wid_label)
self.title_label = slabel()
self.title_label.set_line_wrap(True)
self.title_label.set_size_request(400, -1)
tb.new_row("Title", self.title_label)
self.or_image = Gtk.Image()
tb.new_row("Override-Redirect", self.or_image)
self.state_label = slabel()
tb.new_row("State", self.state_label)
self.attributes_label = slabel()
tb.new_row("Attributes", self.attributes_label)
self.focus_image = Gtk.Image()
tb.new_row("Focus", self.focus_image)
self.button_state_label = slabel()
tb.new_row("Button State", self.button_state_label)
#self.group_leader_label = slabel()
#tb.new_row("Group Leader", self.group_leader_label)
tb.new_row("", slabel())
self.gravity_label = slabel()
tb.new_row("Gravity", self.gravity_label)
self.content_type_label = slabel()
tb.new_row("Content Type", self.content_type_label)
tb.new_row("", slabel())
self.pixel_depth_label = slabel()
tb.new_row("Pixel Depth", self.pixel_depth_label)
self.alpha_image = Gtk.Image()
tb.new_row("Alpha Channel", self.alpha_image)
self.opengl_image = Gtk.Image()
tb.new_row("OpenGL", self.opengl_image)
tb.new_row("", slabel())
self.geometry_label = slabel()
tb.new_row("Geometry", self.geometry_label)
self.outer_geometry_label = slabel()
tb.new_row("Outer Geometry", self.outer_geometry_label)
self.inner_geometry_label = slabel()
tb.new_row("Inner Geometry", self.inner_geometry_label)
self.offsets_label = slabel()
tb.new_row("Offsets", self.offsets_label)
self.frame_extents_label = slabel()
tb.new_row("Frame Extents", self.frame_extents_label)
self.max_size_label = slabel()
tb.new_row("Maximum Size", self.max_size_label)
self.size_constraints_label = slabel()
tb.new_row("Size Constraints", self.size_constraints_label)
self.add(tb.get_table())

def destroy(self, *_args):
self.is_closed = True
Gtk.Window.destroy(self)

def show(self):
self.populate()
super().show_all()
GLib.timeout_add(1000, self.populate)

def populate(self):
if self.is_closed:
return False
self.do_populate()
return True

def do_populate(self):
w = self._window
if not w:
return
def dict_str(d):
return "\n".join("%s : %s" % (k,v) for k,v in d.items())
def get_window_state():
state = []
for s in ("fullscreen", "maximized",
"above", "below", "shaded", "sticky",
"skip-pager", "skip-taskbar",
"iconified"):
#ie: "skip-pager" -> self.window._skip_pager
if getattr(w, "_%s" % s.replace("-", "_"), False):
state.append(s)
for s in ("modal", ):
fn = getattr(w, "get_%s" % s, None)
if fn and fn():
state.append(s)
return csv(state) or "none"
def get_attributes():
attr = {}
workspace = w.get_desktop_workspace()
if workspace>0 and workspace!=WORKSPACE_UNSET:
attr["workspace"] = workspace
opacity = w.get_opacity()
if opacity<1:
attr["opacity"] = opacity
role = w.get_role()
if role:
attr["role"] = role
#get_type_hint
return dict_str(attr)
self.wid_label.set_text(str(w._id))
self.title_label.set_text(w.get_title())
self.bool_icon(self.or_image, w._override_redirect)
self.state_label.set_text(get_window_state())
self.attributes_label.set_text(get_attributes())
self.bool_icon(self.focus_image, w._focused)
self.button_state_label.set_text(csv(b for b,s in w.button_state.items() if s) or "none")
#self.group_leader_label.set_text(str(w.group_leader))
self.gravity_label.set_text(GRAVITY_STR.get(w.window_gravity, "invalid"))
self.content_type_label.set_text(w.content_type or "unknown")
#geometry:
self.pixel_depth_label.set_text(str(w.pixel_depth or 24))
self.bool_icon(self.alpha_image, w._window_alpha)
self.bool_icon(self.opengl_image, getattr(w._backing, "gl_setup", False))
#tells us if this window instance can paint with alpha
self._window_alpha = False
def geom_str(geom):
return "%ix%i at %i,%i" % (geom[2], geom[3], geom[0], geom[1])
geom = list(w._pos)+list(w._size)
self.geometry_label.set_text(geom_str(geom))
geom = list(w.get_position()) + list(w.get_size())
self.outer_geometry_label.set_text(geom_str(geom))
self.inner_geometry_label.set_text(geom_str(w.get_drawing_area_geometry()))
self.offsets_label.set_text(",".join(w.window_offset or []) or "none")
self.frame_extents_label.set_text(csv(w._current_frame_extents or []) or "none")
self.max_size_label.set_text(csv(w.max_window_size))
def hsc(sc):
#make the dict more human readable
ssc = dict((bytestostr(k),v) for k,v in sc.items())
ssc.pop("gravity", None)
return dict_str(ssc)
self.size_constraints_label.set_text(hsc(w.size_constraints))

def bool_icon(self, image, on_off):
c = self._client
if not c:
return
if on_off:
icon = c.get_pixbuf("ticked-small.png")
else:
icon = c.get_pixbuf("unticked-small.png")
image.set_from_pixbuf(icon)

def show_opengl_state(self):
if self.client.opengl_enabled:
glinfo = "%s / %s" % (
self.client.opengl_props.get("vendor", ""),
self.client.opengl_props.get("renderer", ""),
)
display_mode = self.client.opengl_props.get("display_mode", [])
bit_depth = self.client.opengl_props.get("depth", 0)
info = []
if bit_depth:
info.append("%i-bit" % bit_depth)
if "DOUBLE" in display_mode:
info.append("double buffering")
elif "SINGLE" in display_mode:
info.append("single buffering")
else:
info.append("unknown buffering")
if "ALPHA" in display_mode:
info.append("with transparency")
else:
info.append("without transparency")
else:
#info could be telling us that the gl bindings are missing:
glinfo = self.client.opengl_props.get("info", "disabled")
info = ["n/a"]
self.client_opengl_label.set_text(glinfo)
self.opengl_buffering.set_text(" ".join(info))

def show_window_renderers(self):
if not mixin_features.windows:
return
wr = []
renderers = {}
for wid, window in tuple(self.client._id_to_window.items()):
renderers.setdefault(window.get_backing_class(), []).append(wid)
for bclass, windows in renderers.items():
wr.append("%s (%i)" % (bclass.__name__.replace("Backing", ""), len(windows)))
self.window_rendering.set_text("GTK3: %s" % csv(wr))

self.bool_icon(self.client_opengl_icon, self.client.client_supports_opengl)

def get_window_encoder_stats(self):
window_encoder_stats = {}
#new-style server with namespace (easier):
window_dict = self.client.server_last_info.get("window")
if window_dict and isinstance(window_dict, dict):
for k,v in window_dict.items():
try:
wid = int(k)
encoder_stats = v.get("encoder")
if encoder_stats:
window_encoder_stats[wid] = encoder_stats
except Exception:
log.error("Error: cannot lookup window dict", exc_info=True)
return window_encoder_stats

0 comments on commit 2b48464

Please sign in to comment.