1# -*- Mode: Python -*- 2 3# GDBus - GLib D-Bus Library 4# 5# Copyright (C) 2008-2011 Red Hat, Inc. 6# 7# This library is free software; you can redistribute it and/or 8# modify it under the terms of the GNU Lesser General Public 9# License as published by the Free Software Foundation; either 10# version 2.1 of the License, or (at your option) any later version. 11# 12# This library is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15# Lesser General Public License for more details. 16# 17# You should have received a copy of the GNU Lesser General 18# Public License along with this library; if not, see <http://www.gnu.org/licenses/>. 19# 20# Author: David Zeuthen <davidz@redhat.com> 21 22from . import utils 23from .utils import print_error 24 25class Annotation: 26 def __init__(self, key, value): 27 self.key = key 28 self.value = value 29 self.annotations = [] 30 self.since = '' 31 32 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, container): 33 key = self.key 34 overridden_key = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name') 35 if utils.is_ugly_case(overridden_key): 36 self.key_lower = overridden_key.lower() 37 else: 38 if overridden_key: 39 key = overridden_key 40 self.key_lower = utils.camel_case_to_uscore(key).lower().replace('-', '_').replace('.', '_') 41 42 if len(self.since) == 0: 43 self.since = utils.lookup_since(self.annotations) 44 if len(self.since) == 0: 45 self.since = container.since 46 47 for a in self.annotations: 48 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 49 50class Arg: 51 def __init__(self, name, signature): 52 self.name = name 53 self.signature = signature 54 self.annotations = [] 55 self.doc_string = '' 56 self.since = '' 57 58 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, arg_number): 59 if len(self.doc_string) == 0: 60 self.doc_string = utils.lookup_docs(self.annotations) 61 if len(self.since) == 0: 62 self.since = utils.lookup_since(self.annotations) 63 64 if self.name is None: 65 self.name = 'unnamed_arg%d'%arg_number 66 # default to GVariant 67 self.ctype_in_g = 'GVariant *' 68 self.ctype_in = 'GVariant *' 69 self.ctype_in_dup = 'GVariant *' 70 self.ctype_out = 'GVariant **' 71 self.gtype = 'G_TYPE_VARIANT' 72 self.free_func = 'g_variant_unref' 73 self.format_in = '@' + self.signature 74 self.format_out = '@' + self.signature 75 self.gvariant_get = 'XXX' 76 self.gvalue_get = 'g_value_get_variant' 77 self.array_annotation = '' 78 79 if not utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.ForceGVariant'): 80 if self.signature == 'b': 81 self.ctype_in_g = 'gboolean ' 82 self.ctype_in = 'gboolean ' 83 self.ctype_out = 'gboolean *' 84 self.gtype = 'G_TYPE_BOOLEAN' 85 self.free_func = None 86 self.format_in = 'b' 87 self.format_out = 'b' 88 self.gvariant_get = 'g_variant_get_boolean' 89 self.gvalue_get = 'g_value_get_boolean' 90 elif self.signature == 'y': 91 self.ctype_in_g = 'guchar ' 92 self.ctype_in = 'guchar ' 93 self.ctype_out = 'guchar *' 94 self.gtype = 'G_TYPE_UCHAR' 95 self.free_func = None 96 self.format_in = 'y' 97 self.format_out = 'y' 98 self.gvariant_get = 'g_variant_get_byte' 99 self.gvalue_get = 'g_value_get_uchar' 100 elif self.signature == 'n': 101 self.ctype_in_g = 'gint ' 102 self.ctype_in = 'gint16 ' 103 self.ctype_out = 'gint16 *' 104 self.gtype = 'G_TYPE_INT' 105 self.free_func = None 106 self.format_in = 'n' 107 self.format_out = 'n' 108 self.gvariant_get = 'g_variant_get_int16' 109 self.gvalue_get = 'g_value_get_int' 110 elif self.signature == 'q': 111 self.ctype_in_g = 'guint ' 112 self.ctype_in = 'guint16 ' 113 self.ctype_out = 'guint16 *' 114 self.gtype = 'G_TYPE_UINT' 115 self.free_func = None 116 self.format_in = 'q' 117 self.format_out = 'q' 118 self.gvariant_get = 'g_variant_get_uint16' 119 self.gvalue_get = 'g_value_get_uint' 120 elif self.signature == 'i': 121 self.ctype_in_g = 'gint ' 122 self.ctype_in = 'gint ' 123 self.ctype_out = 'gint *' 124 self.gtype = 'G_TYPE_INT' 125 self.free_func = None 126 self.format_in = 'i' 127 self.format_out = 'i' 128 self.gvariant_get = 'g_variant_get_int32' 129 self.gvalue_get = 'g_value_get_int' 130 elif self.signature == 'u': 131 self.ctype_in_g = 'guint ' 132 self.ctype_in = 'guint ' 133 self.ctype_out = 'guint *' 134 self.gtype = 'G_TYPE_UINT' 135 self.free_func = None 136 self.format_in = 'u' 137 self.format_out = 'u' 138 self.gvariant_get = 'g_variant_get_uint32' 139 self.gvalue_get = 'g_value_get_uint' 140 elif self.signature == 'x': 141 self.ctype_in_g = 'gint64 ' 142 self.ctype_in = 'gint64 ' 143 self.ctype_out = 'gint64 *' 144 self.gtype = 'G_TYPE_INT64' 145 self.free_func = None 146 self.format_in = 'x' 147 self.format_out = 'x' 148 self.gvariant_get = 'g_variant_get_int64' 149 self.gvalue_get = 'g_value_get_int64' 150 elif self.signature == 't': 151 self.ctype_in_g = 'guint64 ' 152 self.ctype_in = 'guint64 ' 153 self.ctype_out = 'guint64 *' 154 self.gtype = 'G_TYPE_UINT64' 155 self.free_func = None 156 self.format_in = 't' 157 self.format_out = 't' 158 self.gvariant_get = 'g_variant_get_uint64' 159 self.gvalue_get = 'g_value_get_uint64' 160 elif self.signature == 'd': 161 self.ctype_in_g = 'gdouble ' 162 self.ctype_in = 'gdouble ' 163 self.ctype_out = 'gdouble *' 164 self.gtype = 'G_TYPE_DOUBLE' 165 self.free_func = None 166 self.format_in = 'd' 167 self.format_out = 'd' 168 self.gvariant_get = 'g_variant_get_double' 169 self.gvalue_get = 'g_value_get_double' 170 elif self.signature == 's': 171 self.ctype_in_g = 'const gchar *' 172 self.ctype_in = 'const gchar *' 173 self.ctype_in_dup = 'gchar *' 174 self.ctype_out = 'gchar **' 175 self.gtype = 'G_TYPE_STRING' 176 self.free_func = 'g_free' 177 self.format_in = 's' 178 self.format_out = 's' 179 self.gvariant_get = 'g_variant_get_string' 180 self.gvalue_get = 'g_value_get_string' 181 elif self.signature == 'o': 182 self.ctype_in_g = 'const gchar *' 183 self.ctype_in = 'const gchar *' 184 self.ctype_in_dup = 'gchar *' 185 self.ctype_out = 'gchar **' 186 self.gtype = 'G_TYPE_STRING' 187 self.free_func = 'g_free' 188 self.format_in = 'o' 189 self.format_out = 'o' 190 self.gvariant_get = 'g_variant_get_string' 191 self.gvalue_get = 'g_value_get_string' 192 elif self.signature == 'g': 193 self.ctype_in_g = 'const gchar *' 194 self.ctype_in = 'const gchar *' 195 self.ctype_in_dup = 'gchar *' 196 self.ctype_out = 'gchar **' 197 self.gtype = 'G_TYPE_STRING' 198 self.free_func = 'g_free' 199 self.format_in = 'g' 200 self.format_out = 'g' 201 self.gvariant_get = 'g_variant_get_string' 202 self.gvalue_get = 'g_value_get_string' 203 elif self.signature == 'ay': 204 self.ctype_in_g = 'const gchar *' 205 self.ctype_in = 'const gchar *' 206 self.ctype_in_dup = 'gchar *' 207 self.ctype_out = 'gchar **' 208 self.gtype = 'G_TYPE_STRING' 209 self.free_func = 'g_free' 210 self.format_in = '^ay' 211 self.format_out = '^ay' 212 self.gvariant_get = 'g_variant_get_bytestring' 213 self.gvalue_get = 'g_value_get_string' 214 elif self.signature == 'as': 215 self.ctype_in_g = 'const gchar *const *' 216 self.ctype_in = 'const gchar *const *' 217 self.ctype_in_dup = 'gchar **' 218 self.ctype_out = 'gchar ***' 219 self.gtype = 'G_TYPE_STRV' 220 self.free_func = 'g_strfreev' 221 self.format_in = '^as' 222 self.format_out = '^as' 223 self.gvariant_get = 'g_variant_get_strv' 224 self.gvalue_get = 'g_value_get_boxed' 225 self.array_annotation = '(array zero-terminated=1)' 226 elif self.signature == 'ao': 227 self.ctype_in_g = 'const gchar *const *' 228 self.ctype_in = 'const gchar *const *' 229 self.ctype_in_dup = 'gchar **' 230 self.ctype_out = 'gchar ***' 231 self.gtype = 'G_TYPE_STRV' 232 self.free_func = 'g_strfreev' 233 self.format_in = '^ao' 234 self.format_out = '^ao' 235 self.gvariant_get = 'g_variant_get_objv' 236 self.gvalue_get = 'g_value_get_boxed' 237 self.array_annotation = '(array zero-terminated=1)' 238 elif self.signature == 'aay': 239 self.ctype_in_g = 'const gchar *const *' 240 self.ctype_in = 'const gchar *const *' 241 self.ctype_in_dup = 'gchar **' 242 self.ctype_out = 'gchar ***' 243 self.gtype = 'G_TYPE_STRV' 244 self.free_func = 'g_strfreev' 245 self.format_in = '^aay' 246 self.format_out = '^aay' 247 self.gvariant_get = 'g_variant_get_bytestring_array' 248 self.gvalue_get = 'g_value_get_boxed' 249 self.array_annotation = '(array zero-terminated=1)' 250 251 for a in self.annotations: 252 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 253 254class Method: 255 def __init__(self, name): 256 self.name = name 257 self.in_args = [] 258 self.out_args = [] 259 self.annotations = [] 260 self.doc_string = '' 261 self.since = '' 262 self.deprecated = False 263 264 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, containing_iface): 265 if len(self.doc_string) == 0: 266 self.doc_string = utils.lookup_docs(self.annotations) 267 if len(self.since) == 0: 268 self.since = utils.lookup_since(self.annotations) 269 if len(self.since) == 0: 270 self.since = containing_iface.since 271 272 name = self.name 273 overridden_name = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name') 274 if utils.is_ugly_case(overridden_name): 275 self.name_lower = overridden_name.lower() 276 else: 277 if overridden_name: 278 name = overridden_name 279 self.name_lower = utils.camel_case_to_uscore(name).lower().replace('-', '_') 280 self.name_hyphen = self.name_lower.replace('_', '-') 281 282 arg_count = 0 283 for a in self.in_args: 284 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count) 285 arg_count += 1 286 287 for a in self.out_args: 288 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count) 289 arg_count += 1 290 291 if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true': 292 self.deprecated = True 293 294 for a in self.annotations: 295 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 296 297class Signal: 298 def __init__(self, name): 299 self.name = name 300 self.args = [] 301 self.annotations = [] 302 self.doc_string = '' 303 self.since = '' 304 self.deprecated = False 305 306 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, containing_iface): 307 if len(self.doc_string) == 0: 308 self.doc_string = utils.lookup_docs(self.annotations) 309 if len(self.since) == 0: 310 self.since = utils.lookup_since(self.annotations) 311 if len(self.since) == 0: 312 self.since = containing_iface.since 313 314 name = self.name 315 overridden_name = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name') 316 if utils.is_ugly_case(overridden_name): 317 self.name_lower = overridden_name.lower() 318 else: 319 if overridden_name: 320 name = overridden_name 321 self.name_lower = utils.camel_case_to_uscore(name).lower().replace('-', '_') 322 self.name_hyphen = self.name_lower.replace('_', '-') 323 324 arg_count = 0 325 for a in self.args: 326 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count) 327 arg_count += 1 328 329 if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true': 330 self.deprecated = True 331 332 for a in self.annotations: 333 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 334 335class Property: 336 def __init__(self, name, signature, access): 337 self.name = name 338 self.signature = signature 339 self.access = access 340 self.annotations = [] 341 self.arg = Arg('value', self.signature) 342 self.arg.annotations = self.annotations 343 self.readable = False 344 self.writable = False 345 if self.access == 'readwrite': 346 self.readable = True 347 self.writable = True 348 elif self.access == 'read': 349 self.readable = True 350 elif self.access == 'write': 351 self.writable = True 352 else: 353 print_error('Invalid access type "{}"'.format(self.access)) 354 self.doc_string = '' 355 self.since = '' 356 self.deprecated = False 357 self.emits_changed_signal = True 358 359 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, containing_iface): 360 if len(self.doc_string) == 0: 361 self.doc_string = utils.lookup_docs(self.annotations) 362 if len(self.since) == 0: 363 self.since = utils.lookup_since(self.annotations) 364 if len(self.since) == 0: 365 self.since = containing_iface.since 366 367 name = self.name 368 overridden_name = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name') 369 if utils.is_ugly_case(overridden_name): 370 self.name_lower = overridden_name.lower() 371 else: 372 if overridden_name: 373 name = overridden_name 374 self.name_lower = utils.camel_case_to_uscore(name).lower().replace('-', '_') 375 self.name_hyphen = self.name_lower.replace('_', '-') 376 # don't clash with the GType getter, e.g.: GType foo_bar_get_type (void); G_GNUC_CONST 377 if self.name_lower == 'type': 378 self.name_lower = 'type_' 379 380 # recalculate arg 381 self.arg.annotations = self.annotations 382 self.arg.post_process(interface_prefix, cns, cns_upper, cns_lower, 0) 383 384 if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true': 385 self.deprecated = True 386 387 for a in self.annotations: 388 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 389 390 # FIXME: for now we only support 'false' and 'const' on the signal itself, see #674913 and 391 # http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format 392 # for details 393 if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Property.EmitsChangedSignal') in ('false', 'const'): 394 self.emits_changed_signal = False 395 396class Interface: 397 def __init__(self, name): 398 self.name = name 399 self.methods = [] 400 self.signals = [] 401 self.properties = [] 402 self.annotations = [] 403 self.doc_string = '' 404 self.doc_string_brief = '' 405 self.since = '' 406 self.deprecated = False 407 408 def post_process(self, interface_prefix, c_namespace): 409 if len(self.doc_string) == 0: 410 self.doc_string = utils.lookup_docs(self.annotations) 411 if len(self.doc_string_brief) == 0: 412 self.doc_string_brief = utils.lookup_brief_docs(self.annotations) 413 if len(self.since) == 0: 414 self.since = utils.lookup_since(self.annotations) 415 416 if len(c_namespace) > 0: 417 if utils.is_ugly_case(c_namespace): 418 cns = c_namespace.replace('_', '') 419 cns_upper = c_namespace.upper() + '_' 420 cns_lower = c_namespace.lower() + '_' 421 else: 422 cns = c_namespace 423 cns_upper = utils.camel_case_to_uscore(c_namespace).upper() + '_' 424 cns_lower = utils.camel_case_to_uscore(c_namespace).lower() + '_' 425 else: 426 cns = '' 427 cns_upper = '' 428 cns_lower = '' 429 430 overridden_name = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name') 431 if utils.is_ugly_case(overridden_name): 432 name = overridden_name.replace('_', '') 433 name_with_ns = cns + name 434 self.name_without_prefix = name 435 self.camel_name = name_with_ns 436 self.ns_upper = cns_upper 437 self.name_lower = cns_lower + overridden_name.lower() 438 self.name_upper = overridden_name.upper() 439 440 #print_error('handle Ugly_Case "{}"'.format(overridden_name)) 441 else: 442 if overridden_name: 443 name = overridden_name 444 else: 445 name = self.name 446 if name.startswith(interface_prefix): 447 name = name[len(interface_prefix):] 448 self.name_without_prefix = name 449 name = utils.strip_dots(name) 450 name_with_ns = utils.strip_dots(cns + '.' + name) 451 self.camel_name = name_with_ns 452 self.ns_upper = cns_upper 453 self.name_lower = cns_lower + utils.camel_case_to_uscore(name) 454 self.name_upper = utils.camel_case_to_uscore(name).upper() 455 456 self.name_hyphen = self.name_upper.lower().replace('_', '-') 457 458 if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true': 459 self.deprecated = True 460 461 for m in self.methods: 462 m.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 463 464 for s in self.signals: 465 s.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 466 467 for p in self.properties: 468 p.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 469 470 for a in self.annotations: 471 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 472