• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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