Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of Xpra. 

2# Copyright (C) 2008, 2009 Nathaniel Smith <njs@pobox.com> 

3# Copyright (C) 2012-2020 Antoine Martin <antoine@xpra.org> 

4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

5# later version. See the file COPYING for details. 

6 

7from gi.repository import GObject 

8 

9from xpra.x11.gtk_x11.window_damage import WindowDamageHandler 

10from xpra.gtk_common.gobject_util import one_arg_signal 

11from xpra.x11.gtk_x11.gdk_bindings import ( 

12 add_event_receiver, #@UnresolvedImport 

13 remove_event_receiver, #@UnresolvedImport 

14 get_parent, #@UnresolvedImport 

15 ) 

16from xpra.gtk_common.error import trap 

17from xpra.x11.gtk_x11.world_window import get_world_window 

18from xpra.x11.bindings.ximage import XImageBindings #@UnresolvedImport 

19from xpra.x11.bindings.window_bindings import constants, X11WindowBindings #@UnresolvedImport 

20from xpra.log import Logger 

21 

22log = Logger("x11", "window") 

23 

24XImage = XImageBindings() 

25X11Window = X11WindowBindings() 

26X11Window.ensure_XComposite_support() 

27 

28StructureNotifyMask = constants["StructureNotifyMask"] 

29 

30 

31class CompositeHelper(WindowDamageHandler, GObject.GObject): 

32 

33 __gsignals__ = WindowDamageHandler.__common_gsignals__.copy() 

34 __gsignals__.update({ 

35 #emit: 

36 "contents-changed" : one_arg_signal, 

37 }) 

38 

39 # This may raise XError. 

40 def __init__(self, window): 

41 WindowDamageHandler.__init__(self, window) 

42 GObject.GObject.__init__(self) 

43 self._listening_to = None 

44 

45 def __repr__(self): 

46 return "CompositeHelper(%#x)" % self.xid 

47 

48 def setup(self): 

49 X11Window.XCompositeRedirectWindow(self.xid) 

50 WindowDamageHandler.setup(self) 

51 

52 def do_destroy(self, win): 

53 trap.swallow_synced(X11Window.XCompositeUnredirectWindow, self.xid) 

54 WindowDamageHandler.do_destroy(self, win) 

55 

56 def invalidate_pixmap(self): 

57 lt = self._listening_to 

58 if lt: 

59 self._listening_to = None 

60 self._cleanup_listening(lt) 

61 WindowDamageHandler.invalidate_pixmap(self) 

62 

63 def _cleanup_listening(self, listening): 

64 if listening: 

65 # Don't want to stop listening to self.client_window!: 

66 assert self.client_window is None or self.client_window not in listening 

67 for w in listening: 

68 remove_event_receiver(w, self) 

69 

70 def _set_pixmap(self): 

71 # The tricky part here is that the pixmap returned by 

72 # NameWindowPixmap gets invalidated every time the window's 

73 # viewable state changes. ("viewable" here is the X term that 

74 # means "mapped, and all ancestors are also mapped".) But 

75 # there is no X event that will tell you when a window's 

76 # viewability changes! Instead we have to find all ancestors, 

77 # and watch all of them for unmap and reparent events. But 

78 # what about races? I hear you cry. By doing things in the 

79 # exact order: 

80 # 1) select for StructureNotify 

81 # 2) QueryTree to get parent 

82 # 3) repeat 1 & 2 up to the root 

83 # 4) call NameWindowPixmap 

84 # we are safe. (I think.) 

85 listening = [] 

86 e = None 

87 try: 

88 screen = self.client_window.get_screen() 

89 if not screen: 

90 log("cannot set pixmap on client window - maybe deleted?") 

91 return 

92 root = screen.get_root_window() 

93 gdkworld = None 

94 world = get_world_window() 

95 if world: 

96 gdkworld = world.get_window() 

97 win = get_parent(self.client_window) 

98 while win not in (None, root, gdkworld) and win.get_parent() is not None: 

99 # We have to use a lowlevel function to manipulate the 

100 # event selection here, because SubstructureRedirectMask 

101 # does not roundtrip through the GDK event mask 

102 # functions. So if we used them, here, we would clobber 

103 # corral window selection masks, and those don't deserve 

104 # clobbering. They are our friends! X is driving me 

105 # slowly mad. 

106 xid = win.get_xid() 

107 X11Window.addXSelectInput(xid, StructureNotifyMask) 

108 add_event_receiver(win, self, max_receivers=-1) 

109 listening.append(win) 

110 win = get_parent(win) 

111 handle = XImage.get_xcomposite_pixmap(self.xid) 

112 except Exception as e: 

113 try: 

114 self._cleanup_listening(listening) 

115 except Exception: 

116 pass 

117 raise 

118 if handle is None: 

119 log("failed to name a window pixmap for %#x: %s", self.xid, e) 

120 self._cleanup_listening(listening) 

121 else: 

122 self._contents_handle = handle 

123 # Don't save the listening set until after 

124 # NameWindowPixmap has succeeded, to maintain our 

125 # invariant: 

126 self._listening_to = listening 

127 

128 

129 def do_xpra_damage_event(self, event): 

130 event.x += self._border_width 

131 event.y += self._border_width 

132 self.emit("contents-changed", event) 

133 

134GObject.type_register(CompositeHelper)