Mercurial > pidgin
annotate plugins/tcl/tcl_signals.c @ 8252:10a41e67a800
[gaim-migrate @ 8975]
I'm tired, so I probably broke something...
1. clean up warnings trying to put chats into the blist before the blist is there to put chats in
2. clean up warnings trying to mess with the buddy pounce menu before the buddy pounce menu is there to be messed with
3. clean up warnings with reconnecting and the progress bars in the connection dialog, i think
4. re-order things so the tab doesn't go grey if it's already red. this annoyed me.
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Fri, 13 Feb 2004 07:48:19 +0000 |
parents | bf630f7dfdcd |
children | 1a97d5e88d12 |
rev | line source |
---|---|
6694 | 1 /** |
2 * @file tcl_signals.c Gaim Tcl signal API | |
3 * | |
4 * gaim | |
5 * | |
6 * Copyright (C) 2003 Ethan Blanton <eblanton@cs.purdue.edu> | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
22 #include <tcl.h> | |
23 #include <stdarg.h> | |
24 | |
25 #include "tcl_gaim.h" | |
26 | |
27 #include "internal.h" | |
28 #include "connection.h" | |
29 #include "conversation.h" | |
30 #include "signals.h" | |
31 #include "debug.h" | |
32 #include "value.h" | |
33 #include "core.h" | |
34 | |
35 static GList *tcl_callbacks; | |
36 | |
37 static void *tcl_signal_callback(va_list args, struct tcl_signal_handler *handler); | |
38 | |
39 void tcl_signal_init() | |
40 { | |
41 tcl_callbacks = NULL; | |
42 } | |
43 | |
44 void tcl_signal_handler_free(struct tcl_signal_handler *handler) | |
45 { | |
46 if (handler == NULL) | |
47 return; | |
48 | |
49 g_free(handler->signal); | |
50 if (handler->argnames != NULL) | |
51 g_free(handler->argnames); | |
52 Tcl_DecrRefCount(handler->proc); | |
53 g_free(handler); | |
54 } | |
55 | |
56 void tcl_signal_cleanup(Tcl_Interp *interp) | |
57 { | |
58 GList *cur; | |
59 struct tcl_signal_handler *handler; | |
60 | |
61 for (cur = tcl_callbacks; cur != NULL; cur = g_list_next(cur)) { | |
62 handler = cur->data; | |
63 if (handler->interp == interp) { | |
64 tcl_signal_handler_free(handler); | |
65 cur->data = NULL; | |
66 } | |
67 } | |
68 tcl_callbacks = g_list_remove_all(tcl_callbacks, NULL); | |
69 } | |
70 | |
71 gboolean tcl_signal_connect(struct tcl_signal_handler *handler) | |
72 { | |
73 gaim_signal_get_values(handler->instance, handler->signal, &handler->returntype, | |
74 &handler->nargs, &handler->argtypes); | |
75 | |
76 if (handler->nargs != handler->nnames) | |
77 return FALSE; | |
78 | |
79 tcl_signal_disconnect(handler->interp, handler->signal, handler->interp); | |
80 | |
81 if (!gaim_signal_connect_vargs(handler->instance, handler->signal, (void *)handler->interp, | |
82 GAIM_CALLBACK(tcl_signal_callback), (void *)handler)) | |
83 return FALSE; | |
84 | |
85 tcl_callbacks = g_list_append(tcl_callbacks, (gpointer)handler); | |
86 | |
87 return TRUE; | |
88 } | |
89 | |
90 void tcl_signal_disconnect(void *instance, const char *signal, Tcl_Interp *interp) | |
91 { | |
92 GList *cur; | |
93 struct tcl_signal_handler *handler; | |
94 gboolean found = FALSE; | |
95 | |
96 for (cur = tcl_callbacks; cur != NULL; cur = g_list_next(cur)) { | |
97 handler = cur->data; | |
98 if (handler->interp == interp && handler->instance == instance | |
99 && !strcmp(signal, handler->signal)) { | |
100 gaim_signal_disconnect(instance, signal, handler->interp, | |
101 GAIM_CALLBACK(tcl_signal_callback)); | |
102 tcl_signal_handler_free(handler); | |
103 cur->data = NULL; | |
104 found = TRUE; | |
105 break; | |
106 } | |
107 } | |
108 if (found) | |
109 tcl_callbacks = g_list_remove_all(tcl_callbacks, NULL); | |
110 } | |
111 | |
112 static void *tcl_signal_callback(va_list args, struct tcl_signal_handler *handler) | |
113 { | |
114 struct var { | |
115 void *val; | |
116 char *str; | |
117 } *vars; | |
118 GString *val, *name; | |
119 GaimBlistNode *node; | |
120 int error, i; | |
121 void *retval = NULL; | |
122 Tcl_Obj *result; | |
123 | |
124 vars = g_new0(struct var, handler->nargs); | |
125 val = g_string_sized_new(32); | |
126 name = g_string_sized_new(32); | |
127 | |
128 for (i = 0; i < handler->nargs; i++) { | |
129 g_string_printf(name, "::gaim::_callback::%s", handler->argnames[i]); | |
130 | |
131 switch(gaim_value_get_type(handler->argtypes[i])) { | |
132 default: /* Yes, at the top */ | |
133 case GAIM_TYPE_UNKNOWN: /* What? I guess just pass the word ... */ | |
134 /* treat this as a pointer, but complain first */ | |
135 gaim_debug(GAIM_DEBUG_ERROR, "tcl", "unknown GaimValue type %d\n", | |
136 gaim_value_get_type(handler->argtypes[i])); | |
137 case GAIM_TYPE_POINTER: | |
138 case GAIM_TYPE_OBJECT: | |
139 case GAIM_TYPE_BOXED: | |
140 /* These are all "pointer" types to us */ | |
141 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
142 vars[i].val = va_arg(args, void **); | |
143 Tcl_LinkVar(handler->interp, name->str, vars[i].val, TCL_LINK_INT); | |
144 } else { | |
145 vars[i].val = va_arg(args, void *); | |
146 Tcl_LinkVar(handler->interp, name->str, (char *)&vars[i].val, | |
147 TCL_LINK_INT|TCL_LINK_READ_ONLY); | |
148 } | |
149 break; | |
150 case GAIM_TYPE_BOOLEAN: | |
151 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
152 vars[i].val = va_arg(args, gboolean *); | |
153 Tcl_LinkVar(handler->interp, name->str, vars[i].val, TCL_LINK_BOOLEAN); | |
154 } else { | |
155 vars[i].val = (void *)va_arg(args, gboolean); | |
156 Tcl_LinkVar(handler->interp, name->str, (char *)&vars[i].val, | |
157 TCL_LINK_BOOLEAN|TCL_LINK_READ_ONLY); | |
158 } | |
159 break; | |
160 case GAIM_TYPE_CHAR: | |
161 case GAIM_TYPE_UCHAR: | |
162 case GAIM_TYPE_SHORT: | |
163 case GAIM_TYPE_USHORT: | |
164 case GAIM_TYPE_INT: | |
165 case GAIM_TYPE_UINT: | |
166 case GAIM_TYPE_LONG: | |
167 case GAIM_TYPE_ULONG: | |
168 case GAIM_TYPE_ENUM: | |
169 /* These next two are totally bogus */ | |
170 case GAIM_TYPE_INT64: | |
171 case GAIM_TYPE_UINT64: | |
172 /* I should really cast these individually to | |
173 * preserve as much information as possible ... | |
174 * but heh */ | |
175 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
176 vars[i].val = (void *)va_arg(args, int *); | |
177 Tcl_LinkVar(handler->interp, name->str, vars[i].val, TCL_LINK_INT); | |
178 } else { | |
179 vars[i].val = (void *)va_arg(args, int); | |
180 Tcl_LinkVar(handler->interp, name->str, (char *)&vars[i].val, | |
181 TCL_LINK_INT|TCL_LINK_READ_ONLY); | |
182 } | |
183 break; | |
184 case GAIM_TYPE_STRING: | |
185 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
186 vars[i].val = (void *)va_arg(args, char **); | |
187 if (vars[i].val != NULL && *(char **)vars[i].val != NULL) { | |
188 vars[i].str = (char *)ckalloc(strlen(*(char **)vars[i].val) + 1); | |
189 strcpy(vars[i].str, *(char **)vars[i].val); | |
190 } else { | |
191 vars[i].str = (char *)ckalloc(1); | |
192 *vars[i].str = '\0'; | |
193 } | |
194 Tcl_LinkVar(handler->interp, name->str, (char *)&vars[i].str, TCL_LINK_STRING); | |
195 } else { | |
196 vars[i].val = (void *)va_arg(args, char *); | |
197 Tcl_LinkVar(handler->interp, name->str, (char *)&vars[i].val, | |
198 TCL_LINK_STRING|TCL_LINK_READ_ONLY); | |
199 } | |
200 break; | |
201 case GAIM_TYPE_SUBTYPE: | |
202 switch (gaim_value_get_subtype(handler->argtypes[i])) { | |
203 default: | |
204 case GAIM_SUBTYPE_UNKNOWN: | |
205 gaim_debug(GAIM_DEBUG_ERROR, "tcl", "subtype unknown\n"); | |
206 case GAIM_SUBTYPE_ACCOUNT: | |
207 case GAIM_SUBTYPE_CONNECTION: | |
208 case GAIM_SUBTYPE_CONVERSATION: | |
209 case GAIM_SUBTYPE_CONV_WINDOW: | |
210 case GAIM_SUBTYPE_PLUGIN: | |
211 /* pointers again */ | |
212 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
213 vars[i].val = va_arg(args, void **); | |
214 Tcl_LinkVar(handler->interp, name->str, vars[i].val, TCL_LINK_INT); | |
215 } else { | |
216 vars[i].val = va_arg(args, void *); | |
217 Tcl_LinkVar(handler->interp, name->str, (char *)&vars[i].val, | |
218 TCL_LINK_INT|TCL_LINK_READ_ONLY); | |
219 } | |
220 break; | |
221 case GAIM_SUBTYPE_BLIST: | |
222 case GAIM_SUBTYPE_BLIST_BUDDY: | |
223 case GAIM_SUBTYPE_BLIST_GROUP: | |
224 case GAIM_SUBTYPE_BLIST_CHAT: | |
225 /* We're going to switch again for code-deduping */ | |
226 if (gaim_value_is_outgoing(handler->argtypes[i])) | |
227 node = *va_arg(args, GaimBlistNode **); | |
228 else | |
229 node = va_arg(args, GaimBlistNode *); | |
230 switch (node->type) { | |
231 case GAIM_BLIST_GROUP_NODE: | |
6700 | 232 g_string_printf(val, "group {%s}", ((GaimGroup *)node)->name); |
6694 | 233 break; |
6735 | 234 case GAIM_BLIST_CONTACT_NODE: |
235 /* g_string_printf(val, "contact {%s}", Contact Name? ); */ | |
236 break; | |
6694 | 237 case GAIM_BLIST_BUDDY_NODE: |
6700 | 238 g_string_printf(val, "buddy {%s} %lu", ((GaimBuddy *)node)->name, |
239 (unsigned long)((GaimBuddy *)node)->account); | |
6694 | 240 break; |
241 case GAIM_BLIST_CHAT_NODE: | |
7118
bf630f7dfdcd
[gaim-migrate @ 7685]
Christian Hammond <chipx86@chipx86.com>
parents:
6735
diff
changeset
|
242 g_string_printf(val, "chat {%s} %lu", ((GaimChat *)node)->alias, |
bf630f7dfdcd
[gaim-migrate @ 7685]
Christian Hammond <chipx86@chipx86.com>
parents:
6735
diff
changeset
|
243 (unsigned long)((GaimChat *)node)->account); |
6694 | 244 break; |
245 case GAIM_BLIST_OTHER_NODE: | |
246 g_string_printf(val, "other"); | |
247 break; | |
248 } | |
249 vars[i].str = g_strdup(val->str); | |
250 Tcl_LinkVar(handler->interp, name->str, (char *)&vars[i].str, | |
251 TCL_LINK_STRING|TCL_LINK_READ_ONLY); | |
252 break; | |
253 } | |
254 } | |
255 } | |
256 | |
257 /* Call the friggin' procedure already */ | |
258 if ((error = Tcl_EvalObjEx(handler->interp, handler->proc, TCL_EVAL_GLOBAL)) != TCL_OK) { | |
259 gaim_debug(GAIM_DEBUG_ERROR, "tcl", "error evaluating callback: %s\n", | |
260 Tcl_GetString(Tcl_GetObjResult(handler->interp))); | |
261 } else { | |
262 result = Tcl_GetObjResult(handler->interp); | |
263 /* handle return values -- strings and words only */ | |
264 if (handler->returntype) { | |
265 if (gaim_value_get_type(handler->returntype) == GAIM_TYPE_STRING) { | |
266 retval = (void *)g_strdup(Tcl_GetString(result)); | |
267 } else { | |
268 if ((error = Tcl_GetIntFromObj(handler->interp, result, (int *)&retval)) != TCL_OK) { | |
269 gaim_debug(GAIM_DEBUG_ERROR, "tcl", "Error retrieving procedure result: %s\n", | |
270 Tcl_GetString(Tcl_GetObjResult(handler->interp))); | |
271 retval = NULL; | |
272 } | |
273 } | |
274 } | |
275 } | |
276 | |
277 /* And finally clean up */ | |
278 for (i = 0; i < handler->nargs; i++) { | |
279 g_string_printf(name, "::gaim::_callback::%s", handler->argnames[i]); | |
280 Tcl_UnlinkVar(handler->interp, name->str); | |
281 /* We basically only have to deal with strings and buddies | |
282 * on the way out */ | |
283 switch (gaim_value_get_type(handler->argtypes[i])) { | |
284 case GAIM_TYPE_STRING: | |
285 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
286 if (vars[i].val != NULL && *(char **)vars[i].val != NULL) { | |
287 g_free(*(char **)vars[i].val); | |
288 *(char **)vars[i].val = g_strdup(vars[i].str); | |
289 } | |
290 ckfree(vars[i].str); | |
291 } | |
292 break; | |
293 case GAIM_TYPE_SUBTYPE: | |
294 switch(gaim_value_get_subtype(handler->argtypes[i])) { | |
295 case GAIM_SUBTYPE_BLIST: | |
296 case GAIM_SUBTYPE_BLIST_BUDDY: | |
297 case GAIM_SUBTYPE_BLIST_GROUP: | |
298 case GAIM_SUBTYPE_BLIST_CHAT: | |
299 g_free(vars[i].str); | |
300 break; | |
301 default: | |
302 /* nothing */ | |
303 ; | |
304 } | |
305 break; | |
306 default: | |
307 /* nothing */ | |
308 ; | |
309 } | |
310 } | |
311 | |
312 g_string_free(name, TRUE); | |
313 g_string_free(val, FALSE); | |
314 g_free(vars); | |
315 | |
316 return retval; | |
317 } |