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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

# -*- Mode: Python; py-indent-offset: 4 -*- 

# vim: tabstop=4 shiftwidth=4 expandtab 

# 

# Copyright (C) 2010 Ignacio Casal Quinteiro <icq@gnome.org> 

# 

# This library is free software; you can redistribute it and/or 

# modify it under the terms of the GNU Lesser General Public 

# License as published by the Free Software Foundation; either 

# version 2.1 of the License, or (at your option) any later version. 

# 

# This library is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 

# Lesser General Public License for more details. 

# 

# You should have received a copy of the GNU Lesser General Public 

# License along with this library; if not, write to the Free Software 

# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 

# USA 

 

import warnings 

 

from .._ossighelper import wakeup_on_signal, register_sigint_fallback 

from ..overrides import override, deprecated_init 

from ..module import get_introspection_module 

from gi import PyGIWarning 

 

from gi.repository import GLib 

 

import sys 

 

Gio = get_introspection_module('Gio') 

 

__all__ = [] 

 

 

class Application(Gio.Application): 

 

def run(self, *args, **kwargs): 

with register_sigint_fallback(self.quit): 

with wakeup_on_signal(): 

return Gio.Application.run(self, *args, **kwargs) 

 

 

Application = override(Application) 

__all__.append('Application') 

 

 

class VolumeMonitor(Gio.VolumeMonitor): 

 

def __init__(self, *args, **kwargs): 

super(VolumeMonitor, self).__init__(*args, **kwargs) 

 

# https://bugzilla.gnome.org/show_bug.cgi?id=744690 

warnings.warn( 

"Gio.VolumeMonitor shouldn't be instantiated directly, " 

"use Gio.VolumeMonitor.get() instead.", 

PyGIWarning, stacklevel=2) 

 

 

VolumeMonitor = override(VolumeMonitor) 

__all__.append('VolumeMonitor') 

 

 

class FileEnumerator(Gio.FileEnumerator): 

def __iter__(self): 

return self 

 

def __next__(self): 

file_info = self.next_file(None) 

 

if file_info is not None: 

return file_info 

else: 

raise StopIteration 

 

# python 2 compat for the iter protocol 

next = __next__ 

 

 

FileEnumerator = override(FileEnumerator) 

__all__.append('FileEnumerator') 

 

 

class MenuItem(Gio.MenuItem): 

def set_attribute(self, attributes): 

for (name, format_string, value) in attributes: 

self.set_attribute_value(name, GLib.Variant(format_string, value)) 

 

 

MenuItem = override(MenuItem) 

__all__.append('MenuItem') 

 

 

class Settings(Gio.Settings): 

'''Provide dictionary-like access to GLib.Settings.''' 

 

__init__ = deprecated_init(Gio.Settings.__init__, 

arg_names=('schema', 'path', 'backend')) 

 

def __contains__(self, key): 

return key in self.list_keys() 

 

def __len__(self): 

return len(self.list_keys()) 

 

def __bool__(self): 

# for "if mysettings" we don't want a dictionary-like test here, just 

# if the object isn't None 

return True 

 

# alias for Python 2.x object protocol 

__nonzero__ = __bool__ 

 

def __getitem__(self, key): 

# get_value() aborts the program on an unknown key 

if key not in self: 

raise KeyError('unknown key: %r' % (key,)) 

 

return self.get_value(key).unpack() 

 

def __setitem__(self, key, value): 

# set_value() aborts the program on an unknown key 

if key not in self: 

raise KeyError('unknown key: %r' % (key,)) 

 

# determine type string of this key 

range = self.get_range(key) 

type_ = range.get_child_value(0).get_string() 

v = range.get_child_value(1) 

if type_ == 'type': 

# v is boxed empty array, type of its elements is the allowed value type 

type_str = v.get_child_value(0).get_type_string() 

assert type_str.startswith('a') 

type_str = type_str[1:] 

elif type_ == 'enum': 

# v is an array with the allowed values 

assert v.get_child_value(0).get_type_string().startswith('a') 

type_str = v.get_child_value(0).get_child_value(0).get_type_string() 

allowed = v.unpack() 

if value not in allowed: 

raise ValueError('value %s is not an allowed enum (%s)' % (value, allowed)) 

else: 

raise NotImplementedError('Cannot handle allowed type range class ' + str(type_)) 

 

self.set_value(key, GLib.Variant(type_str, value)) 

 

def keys(self): 

return self.list_keys() 

 

 

Settings = override(Settings) 

__all__.append('Settings') 

 

 

class _DBusProxyMethodCall: 

'''Helper class to implement DBusProxy method calls.''' 

 

def __init__(self, dbus_proxy, method_name): 

self.dbus_proxy = dbus_proxy 

self.method_name = method_name 

 

def __async_result_handler(self, obj, result, user_data): 

(result_callback, error_callback, real_user_data) = user_data 

try: 

ret = obj.call_finish(result) 

except Exception: 

etype, e = sys.exc_info()[:2] 

# return exception as value 

if error_callback: 

error_callback(obj, e, real_user_data) 

else: 

result_callback(obj, e, real_user_data) 

return 

 

result_callback(obj, self._unpack_result(ret), real_user_data) 

 

def __call__(self, *args, **kwargs): 

# the first positional argument is the signature, unless we are calling 

# a method without arguments; then signature is implied to be '()'. 

if args: 

signature = args[0] 

args = args[1:] 

if not isinstance(signature, str): 

raise TypeError('first argument must be the method signature string: %r' % signature) 

else: 

signature = '()' 

 

arg_variant = GLib.Variant(signature, tuple(args)) 

 

if 'result_handler' in kwargs: 

# asynchronous call 

user_data = (kwargs['result_handler'], 

kwargs.get('error_handler'), 

kwargs.get('user_data')) 

self.dbus_proxy.call(self.method_name, arg_variant, 

kwargs.get('flags', 0), kwargs.get('timeout', -1), None, 

self.__async_result_handler, user_data) 

else: 

# synchronous call 

result = self.dbus_proxy.call_sync(self.method_name, arg_variant, 

kwargs.get('flags', 0), 

kwargs.get('timeout', -1), 

None) 

return self._unpack_result(result) 

 

@classmethod 

def _unpack_result(klass, result): 

'''Convert a D-BUS return variant into an appropriate return value''' 

 

result = result.unpack() 

 

# to be compatible with standard Python behaviour, unbox 

# single-element tuples and return None for empty result tuples 

if len(result) == 1: 

result = result[0] 

elif len(result) == 0: 

result = None 

 

return result 

 

 

class DBusProxy(Gio.DBusProxy): 

'''Provide comfortable and pythonic method calls. 

 

This marshalls the method arguments into a GVariant, invokes the 

call_sync() method on the DBusProxy object, and unmarshalls the result 

GVariant back into a Python tuple. 

 

The first argument always needs to be the D-Bus signature tuple of the 

method call. Example: 

 

proxy = Gio.DBusProxy.new_sync(...) 

result = proxy.MyMethod('(is)', 42, 'hello') 

 

The exception are methods which take no arguments, like 

proxy.MyMethod('()'). For these you can omit the signature and just write 

proxy.MyMethod(). 

 

Optional keyword arguments: 

 

- timeout: timeout for the call in milliseconds (default to D-Bus timeout) 

 

- flags: Combination of Gio.DBusCallFlags.* 

 

- result_handler: Do an asynchronous method call and invoke 

result_handler(proxy_object, result, user_data) when it finishes. 

 

- error_handler: If the asynchronous call raises an exception, 

error_handler(proxy_object, exception, user_data) is called when it 

finishes. If error_handler is not given, result_handler is called with 

the exception object as result instead. 

 

- user_data: Optional user data to pass to result_handler for 

asynchronous calls. 

 

Example for asynchronous calls: 

 

def mymethod_done(proxy, result, user_data): 

if isinstance(result, Exception): 

# handle error 

else: 

# do something with result 

 

proxy.MyMethod('(is)', 42, 'hello', 

result_handler=mymethod_done, user_data='data') 

''' 

def __getattr__(self, name): 

return _DBusProxyMethodCall(self, name) 

 

 

DBusProxy = override(DBusProxy) 

__all__.append('DBusProxy')