3 * Copyright (C) 2006-2011 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
26 * Represents an object signal. Signals enable objects to provide notifications.
28 public class Vala
.Signal
: Symbol
, Lockable
{
30 * The return type of handlers of this signal.
32 public DataType return_type
{
33 get { return _return_type
; }
36 _return_type
.parent_node
= this
;
51 * Specifies whether this signal has an emitter wrapper function.
53 public bool has_emitter
{ get; set; }
56 * Specifies whether this signal has virtual method handler.
58 public bool is_virtual
{ get; set; }
60 private List
<Parameter
> parameters
= new ArrayList
<Parameter
> ();
62 * Refers to the default signal handler, which is an anonymous
63 * function in the scope.
65 public Method default_handler
{ get; private set; }
67 public bool is_detailed
{ get; set; }
69 public bool no_recurse
{ get; set; }
71 public string run_type
{ get; set; }
73 public bool is_action
{ get; set; }
75 public bool no_hooks
{ get; set; }
80 private bool lock_used
= false;
82 private DataType _return_type
;
87 * Creates a new signal.
89 * @param name signal name
90 * @param return_type signal return type
91 * @param source reference to source code
92 * @return newly created signal
94 public Signal (string name
, DataType return_type
, SourceReference? source_reference
= null, Comment? comment
= null) {
95 base (name
, source_reference
, comment
);
96 this
.return_type
= return_type
;
97 this
.run_type
= "last";
101 * Appends parameter to signal handler.
103 * @param param a formal parameter
105 public void add_parameter (Parameter param
) {
106 // default C parameter position
107 param
.cparameter_position
= parameters
.size
+ 1;
108 param
.carray_length_parameter_position
= param
.cparameter_position
+ 0.1;
109 param
.cdelegate_target_parameter_position
= param
.cparameter_position
+ 0.1;
110 param
.cdestroy_notify_parameter_position
= param
.cparameter_position
+ 0.1;
112 parameters
.add (param
);
113 scope
.add (param
.name
, param
);
116 public List
<Parameter
> get_parameters () {
121 * Returns generated delegate to be used for signal handlers.
125 public Delegate
get_delegate (DataType sender_type
, CodeNode node_reference
) {
126 var actual_return_type
= return_type
.get_actual_type (sender_type
, null, node_reference
);
128 var generated_delegate
= new
Delegate (null, actual_return_type
);
129 generated_delegate
.has_target
= true;
130 generated_delegate
.access
= SymbolAccessibility
.PUBLIC
;
131 generated_delegate
.owner
= scope
;
133 // sender parameter is never null and doesn't own its value
134 var sender_param_type
= sender_type
.copy ();
135 sender_param_type
.value_owned
= false;
136 sender_param_type
.nullable
= false;
138 generated_delegate
.sender_type
= sender_param_type
;
140 bool is_generic
= false;
142 foreach (Parameter param
in parameters
) {
143 var actual_param
= param
.copy ();
144 actual_param
.variable_type
= actual_param
.variable_type
.get_actual_type (sender_type
, null, node_reference
);
145 generated_delegate
.add_parameter (actual_param
);
147 if (actual_param
.variable_type is GenericType
) {
153 var cl
= (ObjectTypeSymbol
) parent_symbol
;
154 foreach (var type_param
in cl
.get_type_parameters ()) {
155 generated_delegate
.add_type_parameter (new
TypeParameter (type_param
.name
, type_param
.source_reference
));
158 // parameter types must refer to the delegate type parameters
159 // instead of to the class type parameters
160 foreach (var param
in generated_delegate
.get_parameters ()) {
161 if (param
.variable_type is GenericType
) {
162 param
.variable_type
.type_parameter
= generated_delegate
.get_type_parameters ().get (generated_delegate
.get_type_parameter_index (param
.variable_type
.type_parameter
.name
));
167 scope
.add (null, generated_delegate
);
169 return generated_delegate
;
173 * Returns the name of this signal as it is used in C code.
175 * @return the name to be used in C code
177 public string get_cname () {
179 cname
= camel_case_to_lower_case (name
);
184 public void set_cname (string cname
) {
189 * Returns the string literal of this signal to be used in C code.
191 * @return string literal to be used in C code
193 public CCodeConstant
get_canonical_cconstant (string? detail
= null) {
194 var str
= new
StringBuilder ("\"");
196 string i
= get_cname ();
198 while (i
.length
> 0) {
199 unichar c
= i
.get_char ();
203 str
.append_unichar (c
);
209 if (detail
!= null) {
216 return new
CCodeConstant (str
.str
);
219 public override void accept (CodeVisitor visitor
) {
220 visitor
.visit_signal (this
);
223 public override void accept_children (CodeVisitor visitor
) {
224 return_type
.accept (visitor
);
226 foreach (Parameter param
in parameters
) {
227 param
.accept (visitor
);
229 if (default_handler
== null && body
!= null) {
230 body
.accept (visitor
);
231 } else if (default_handler
!= null) {
232 default_handler
.accept (visitor
);
236 void process_signal_attribute (Attribute a
) {
237 if (a
.has_argument ("detailed")) {
238 is_detailed
= a
.get_bool ("detailed");
240 if (a
.has_argument ("no_recurse")) {
241 no_recurse
= a
.get_bool ("no_recurse");
243 if (a
.has_argument ("run")) {
244 var arg
= a
.get_string ("run");
245 if (arg
== "first") {
247 } else if (arg
== "last") {
249 } else if (arg
== "cleanup") {
250 run_type
= "cleanup";
254 if (a
.has_argument ("action")) {
255 is_action
= a
.get_bool ("action");
258 if (a
.has_argument ("no_hooks")) {
259 no_hooks
= a
.get_bool ("no_hooks");
264 * Process all associated attributes.
266 public void process_attributes () {
267 foreach (Attribute a
in attributes
) {
268 if (a
.name
== "HasEmitter") {
270 } else if (a
.name
== "Signal") {
271 process_signal_attribute (a
);
272 } else if (a
.name
== "Deprecated") {
273 process_deprecated_attribute (a
);
274 } else if (a
.name
== "Experimental") {
275 process_experimental_attribute (a
);
280 public bool get_lock_used () {
284 public void set_lock_used (bool used
) {
288 public override void replace_type (DataType old_type
, DataType new_type
) {
289 if (return_type
== old_type
) {
290 return_type
= new_type
;
294 public override bool check (CodeContext context
) {
301 process_attributes ();
303 return_type
.check (context
);
305 foreach (Parameter param
in parameters
) {
306 param
.check (context
);
309 if (!is_virtual
&& body
!= null) {
310 Report
.error (source_reference
, "Only virtual signals can have a default signal handler body");
315 default_handler
= new
Method (name
, return_type
, source_reference
);
317 default_handler
.owner
= owner
;
318 default_handler
.access
= access
;
319 default_handler
.external
= external
;
320 default_handler
.is_virtual
= true;
321 default_handler
.vfunc_name
= name
;
322 default_handler
.signal_reference
= this
;
323 default_handler
.body
= body
;
326 foreach (Parameter param
in parameters
) {
327 default_handler
.add_parameter (param
);
330 var cl
= parent_symbol as ObjectTypeSymbol
;
332 cl
.add_hidden_method (default_handler
);
333 default_handler
.check (context
);
337 if (!external_package
&& !hides
&& get_hidden_member () != null) {
338 Report
.warning (source_reference
, "%s hides inherited signal `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));