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 25 26class Annotation: 27 def __init__(self, key, value): 28 self.key = key 29 self.value = value 30 self.annotations = [] 31 self.since = "" 32 33 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, container): 34 key = self.key 35 overridden_key = utils.lookup_annotation( 36 self.annotations, "org.gtk.GDBus.C.Name" 37 ) 38 if utils.is_ugly_case(overridden_key): 39 self.key_lower = overridden_key.lower() 40 else: 41 if overridden_key: 42 key = overridden_key 43 self.key_lower = ( 44 utils.camel_case_to_uscore(key) 45 .lower() 46 .replace("-", "_") 47 .replace(".", "_") 48 ) 49 50 if len(self.since) == 0: 51 self.since = utils.lookup_since(self.annotations) 52 if len(self.since) == 0: 53 self.since = container.since 54 55 for a in self.annotations: 56 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 57 58 59class Arg: 60 def __init__(self, name, signature): 61 self.name = name 62 self.signature = signature 63 self.annotations = [] 64 self.doc_string = "" 65 self.since = "" 66 67 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, arg_number): 68 if len(self.doc_string) == 0: 69 self.doc_string = utils.lookup_docs(self.annotations) 70 if len(self.since) == 0: 71 self.since = utils.lookup_since(self.annotations) 72 73 if self.name is None: 74 self.name = "unnamed_arg%d" % arg_number 75 # default to GVariant 76 self.ctype_in_g = "GVariant *" 77 self.ctype_in = "GVariant *" 78 self.ctype_in_dup = "GVariant *" 79 self.ctype_out = "GVariant **" 80 self.gtype = "G_TYPE_VARIANT" 81 self.free_func = "g_variant_unref" 82 self.format_in = "@" + self.signature 83 self.format_out = "@" + self.signature 84 self.gvariant_get = "XXX" 85 self.gvalue_get = "g_value_get_variant" 86 self.array_annotation = "" 87 88 if not utils.lookup_annotation( 89 self.annotations, "org.gtk.GDBus.C.ForceGVariant" 90 ): 91 if self.signature == "b": 92 self.ctype_in_g = "gboolean " 93 self.ctype_in = "gboolean " 94 self.ctype_out = "gboolean *" 95 self.gtype = "G_TYPE_BOOLEAN" 96 self.free_func = None 97 self.format_in = "b" 98 self.format_out = "b" 99 self.gvariant_get = "g_variant_get_boolean" 100 self.gvalue_get = "g_value_get_boolean" 101 elif self.signature == "y": 102 self.ctype_in_g = "guchar " 103 self.ctype_in = "guchar " 104 self.ctype_out = "guchar *" 105 self.gtype = "G_TYPE_UCHAR" 106 self.free_func = None 107 self.format_in = "y" 108 self.format_out = "y" 109 self.gvariant_get = "g_variant_get_byte" 110 self.gvalue_get = "g_value_get_uchar" 111 elif self.signature == "n": 112 self.ctype_in_g = "gint " 113 self.ctype_in = "gint16 " 114 self.ctype_out = "gint16 *" 115 self.gtype = "G_TYPE_INT" 116 self.free_func = None 117 self.format_in = "n" 118 self.format_out = "n" 119 self.gvariant_get = "g_variant_get_int16" 120 self.gvalue_get = "g_value_get_int" 121 elif self.signature == "q": 122 self.ctype_in_g = "guint " 123 self.ctype_in = "guint16 " 124 self.ctype_out = "guint16 *" 125 self.gtype = "G_TYPE_UINT" 126 self.free_func = None 127 self.format_in = "q" 128 self.format_out = "q" 129 self.gvariant_get = "g_variant_get_uint16" 130 self.gvalue_get = "g_value_get_uint" 131 elif self.signature == "i": 132 self.ctype_in_g = "gint " 133 self.ctype_in = "gint " 134 self.ctype_out = "gint *" 135 self.gtype = "G_TYPE_INT" 136 self.free_func = None 137 self.format_in = "i" 138 self.format_out = "i" 139 self.gvariant_get = "g_variant_get_int32" 140 self.gvalue_get = "g_value_get_int" 141 elif self.signature == "u": 142 self.ctype_in_g = "guint " 143 self.ctype_in = "guint " 144 self.ctype_out = "guint *" 145 self.gtype = "G_TYPE_UINT" 146 self.free_func = None 147 self.format_in = "u" 148 self.format_out = "u" 149 self.gvariant_get = "g_variant_get_uint32" 150 self.gvalue_get = "g_value_get_uint" 151 elif self.signature == "x": 152 self.ctype_in_g = "gint64 " 153 self.ctype_in = "gint64 " 154 self.ctype_out = "gint64 *" 155 self.gtype = "G_TYPE_INT64" 156 self.free_func = None 157 self.format_in = "x" 158 self.format_out = "x" 159 self.gvariant_get = "g_variant_get_int64" 160 self.gvalue_get = "g_value_get_int64" 161 elif self.signature == "t": 162 self.ctype_in_g = "guint64 " 163 self.ctype_in = "guint64 " 164 self.ctype_out = "guint64 *" 165 self.gtype = "G_TYPE_UINT64" 166 self.free_func = None 167 self.format_in = "t" 168 self.format_out = "t" 169 self.gvariant_get = "g_variant_get_uint64" 170 self.gvalue_get = "g_value_get_uint64" 171 elif self.signature == "d": 172 self.ctype_in_g = "gdouble " 173 self.ctype_in = "gdouble " 174 self.ctype_out = "gdouble *" 175 self.gtype = "G_TYPE_DOUBLE" 176 self.free_func = None 177 self.format_in = "d" 178 self.format_out = "d" 179 self.gvariant_get = "g_variant_get_double" 180 self.gvalue_get = "g_value_get_double" 181 elif self.signature == "s": 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 = "s" 189 self.format_out = "s" 190 self.gvariant_get = "g_variant_get_string" 191 self.gvalue_get = "g_value_get_string" 192 elif self.signature == "o": 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 = "o" 200 self.format_out = "o" 201 self.gvariant_get = "g_variant_get_string" 202 self.gvalue_get = "g_value_get_string" 203 elif self.signature == "g": 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 = "g" 211 self.format_out = "g" 212 self.gvariant_get = "g_variant_get_string" 213 self.gvalue_get = "g_value_get_string" 214 elif self.signature == "ay": 215 self.ctype_in_g = "const gchar *" 216 self.ctype_in = "const gchar *" 217 self.ctype_in_dup = "gchar *" 218 self.ctype_out = "gchar **" 219 self.gtype = "G_TYPE_STRING" 220 self.free_func = "g_free" 221 self.format_in = "^ay" 222 self.format_out = "^ay" 223 self.gvariant_get = "g_variant_get_bytestring" 224 self.gvalue_get = "g_value_get_string" 225 elif self.signature == "as": 226 self.ctype_in_g = "const gchar *const *" 227 self.ctype_in = "const gchar *const *" 228 self.ctype_in_dup = "gchar **" 229 self.ctype_out = "gchar ***" 230 self.gtype = "G_TYPE_STRV" 231 self.free_func = "g_strfreev" 232 self.format_in = "^as" 233 self.format_out = "^as" 234 self.gvariant_get = "g_variant_get_strv" 235 self.gvalue_get = "g_value_get_boxed" 236 self.array_annotation = "(array zero-terminated=1)" 237 elif self.signature == "ao": 238 self.ctype_in_g = "const gchar *const *" 239 self.ctype_in = "const gchar *const *" 240 self.ctype_in_dup = "gchar **" 241 self.ctype_out = "gchar ***" 242 self.gtype = "G_TYPE_STRV" 243 self.free_func = "g_strfreev" 244 self.format_in = "^ao" 245 self.format_out = "^ao" 246 self.gvariant_get = "g_variant_get_objv" 247 self.gvalue_get = "g_value_get_boxed" 248 self.array_annotation = "(array zero-terminated=1)" 249 elif self.signature == "aay": 250 self.ctype_in_g = "const gchar *const *" 251 self.ctype_in = "const gchar *const *" 252 self.ctype_in_dup = "gchar **" 253 self.ctype_out = "gchar ***" 254 self.gtype = "G_TYPE_STRV" 255 self.free_func = "g_strfreev" 256 self.format_in = "^aay" 257 self.format_out = "^aay" 258 self.gvariant_get = "g_variant_get_bytestring_array" 259 self.gvalue_get = "g_value_get_boxed" 260 self.array_annotation = "(array zero-terminated=1)" 261 262 for a in self.annotations: 263 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 264 265 266class Method: 267 def __init__(self, name, h_type_implies_unix_fd=True): 268 self.name = name 269 self.h_type_implies_unix_fd = h_type_implies_unix_fd 270 self.in_args = [] 271 self.out_args = [] 272 self.annotations = [] 273 self.doc_string = "" 274 self.since = "" 275 self.deprecated = False 276 self.unix_fd = False 277 278 def post_process( 279 self, interface_prefix, cns, cns_upper, cns_lower, containing_iface 280 ): 281 if len(self.doc_string) == 0: 282 self.doc_string = utils.lookup_docs(self.annotations) 283 if len(self.since) == 0: 284 self.since = utils.lookup_since(self.annotations) 285 if len(self.since) == 0: 286 self.since = containing_iface.since 287 288 name = self.name 289 overridden_name = utils.lookup_annotation( 290 self.annotations, "org.gtk.GDBus.C.Name" 291 ) 292 if utils.is_ugly_case(overridden_name): 293 self.name_lower = overridden_name.lower() 294 else: 295 if overridden_name: 296 name = overridden_name 297 self.name_lower = utils.camel_case_to_uscore(name).lower().replace("-", "_") 298 self.name_hyphen = self.name_lower.replace("_", "-") 299 300 arg_count = 0 301 for a in self.in_args: 302 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count) 303 arg_count += 1 304 if self.h_type_implies_unix_fd and "h" in a.signature: 305 self.unix_fd = True 306 307 for a in self.out_args: 308 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count) 309 arg_count += 1 310 if self.h_type_implies_unix_fd and "h" in a.signature: 311 self.unix_fd = True 312 313 if ( 314 utils.lookup_annotation(self.annotations, "org.freedesktop.DBus.Deprecated") 315 == "true" 316 ): 317 self.deprecated = True 318 319 if utils.lookup_annotation(self.annotations, "org.gtk.GDBus.C.UnixFD"): 320 self.unix_fd = True 321 322 for a in self.annotations: 323 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 324 325 326class Signal: 327 def __init__(self, name): 328 self.name = name 329 self.args = [] 330 self.annotations = [] 331 self.doc_string = "" 332 self.since = "" 333 self.deprecated = False 334 335 def post_process( 336 self, interface_prefix, cns, cns_upper, cns_lower, containing_iface 337 ): 338 if len(self.doc_string) == 0: 339 self.doc_string = utils.lookup_docs(self.annotations) 340 if len(self.since) == 0: 341 self.since = utils.lookup_since(self.annotations) 342 if len(self.since) == 0: 343 self.since = containing_iface.since 344 345 name = self.name 346 overridden_name = utils.lookup_annotation( 347 self.annotations, "org.gtk.GDBus.C.Name" 348 ) 349 if utils.is_ugly_case(overridden_name): 350 self.name_lower = overridden_name.lower() 351 else: 352 if overridden_name: 353 name = overridden_name 354 self.name_lower = utils.camel_case_to_uscore(name).lower().replace("-", "_") 355 self.name_hyphen = self.name_lower.replace("_", "-") 356 357 arg_count = 0 358 for a in self.args: 359 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count) 360 arg_count += 1 361 362 if ( 363 utils.lookup_annotation(self.annotations, "org.freedesktop.DBus.Deprecated") 364 == "true" 365 ): 366 self.deprecated = True 367 368 for a in self.annotations: 369 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 370 371 372class Property: 373 def __init__(self, name, signature, access): 374 self.name = name 375 self.signature = signature 376 self.access = access 377 self.annotations = [] 378 self.arg = Arg("value", self.signature) 379 self.arg.annotations = self.annotations 380 self.readable = False 381 self.writable = False 382 if self.access == "readwrite": 383 self.readable = True 384 self.writable = True 385 elif self.access == "read": 386 self.readable = True 387 elif self.access == "write": 388 self.writable = True 389 else: 390 print_error('Invalid access type "{}"'.format(self.access)) 391 self.doc_string = "" 392 self.since = "" 393 self.deprecated = False 394 self.emits_changed_signal = True 395 396 def post_process( 397 self, interface_prefix, cns, cns_upper, cns_lower, containing_iface 398 ): 399 if len(self.doc_string) == 0: 400 self.doc_string = utils.lookup_docs(self.annotations) 401 if len(self.since) == 0: 402 self.since = utils.lookup_since(self.annotations) 403 if len(self.since) == 0: 404 self.since = containing_iface.since 405 406 name = self.name 407 overridden_name = utils.lookup_annotation( 408 self.annotations, "org.gtk.GDBus.C.Name" 409 ) 410 if utils.is_ugly_case(overridden_name): 411 self.name_lower = overridden_name.lower() 412 else: 413 if overridden_name: 414 name = overridden_name 415 self.name_lower = utils.camel_case_to_uscore(name).lower().replace("-", "_") 416 self.name_hyphen = self.name_lower.replace("_", "-") 417 # don't clash with the GType getter, e.g.: 418 # GType foo_bar_get_type (void); G_GNUC_CONST 419 if self.name_lower == "type": 420 self.name_lower = "type_" 421 422 # recalculate arg 423 self.arg.annotations = self.annotations 424 self.arg.post_process(interface_prefix, cns, cns_upper, cns_lower, 0) 425 426 if ( 427 utils.lookup_annotation(self.annotations, "org.freedesktop.DBus.Deprecated") 428 == "true" 429 ): 430 self.deprecated = True 431 432 for a in self.annotations: 433 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 434 435 # FIXME: for now we only support 'false' and 'const' on the signal itself, 436 # see #674913 and 437 # http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format 438 # for details 439 if utils.lookup_annotation( 440 self.annotations, "org.freedesktop.DBus.Property.EmitsChangedSignal" 441 ) in ("false", "const"): 442 self.emits_changed_signal = False 443 444 445class Interface: 446 def __init__(self, name): 447 self.name = name 448 self.methods = [] 449 self.signals = [] 450 self.properties = [] 451 self.annotations = [] 452 self.doc_string = "" 453 self.doc_string_brief = "" 454 self.since = "" 455 self.deprecated = False 456 457 def post_process(self, interface_prefix, c_namespace): 458 if len(self.doc_string) == 0: 459 self.doc_string = utils.lookup_docs(self.annotations) 460 if len(self.doc_string_brief) == 0: 461 self.doc_string_brief = utils.lookup_brief_docs(self.annotations) 462 if len(self.since) == 0: 463 self.since = utils.lookup_since(self.annotations) 464 465 if len(c_namespace) > 0: 466 if utils.is_ugly_case(c_namespace): 467 cns = c_namespace.replace("_", "") 468 cns_upper = c_namespace.upper() + "_" 469 cns_lower = c_namespace.lower() + "_" 470 else: 471 cns = c_namespace 472 cns_upper = utils.camel_case_to_uscore(c_namespace).upper() + "_" 473 cns_lower = utils.camel_case_to_uscore(c_namespace).lower() + "_" 474 else: 475 cns = "" 476 cns_upper = "" 477 cns_lower = "" 478 479 overridden_name = utils.lookup_annotation( 480 self.annotations, "org.gtk.GDBus.C.Name" 481 ) 482 if utils.is_ugly_case(overridden_name): 483 name = overridden_name.replace("_", "") 484 name_with_ns = cns + name 485 self.name_without_prefix = name 486 self.camel_name = name_with_ns 487 self.ns_upper = cns_upper 488 self.name_lower = cns_lower + overridden_name.lower() 489 self.name_upper = overridden_name.upper() 490 491 # print_error('handle Ugly_Case "{}"'.format(overridden_name)) 492 else: 493 if overridden_name: 494 name = overridden_name 495 else: 496 name = self.name 497 if name.startswith(interface_prefix): 498 name = name[len(interface_prefix) :] 499 self.name_without_prefix = name 500 name = utils.strip_dots(name) 501 name_with_ns = utils.strip_dots(cns + "." + name) 502 self.camel_name = name_with_ns 503 self.ns_upper = cns_upper 504 self.name_lower = cns_lower + utils.camel_case_to_uscore(name) 505 self.name_upper = utils.camel_case_to_uscore(name).upper() 506 507 self.name_hyphen = self.name_upper.lower().replace("_", "-") 508 509 if ( 510 utils.lookup_annotation(self.annotations, "org.freedesktop.DBus.Deprecated") 511 == "true" 512 ): 513 self.deprecated = True 514 515 for m in self.methods: 516 m.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 517 518 for s in self.signals: 519 s.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 520 521 for p in self.properties: 522 p.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 523 524 for a in self.annotations: 525 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) 526