• 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
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