Merge branch 'master' of ssh://pege77@mercury.wipsl.com/var/git/irreco-theme-editor
[irreco.git] / irreco / src / core / irreco_cmd_chain.c
blobb3d97a0a22ee638a13c9a6fe5f32749b63b4388d
1 /*
2 * irreco - Ir Remote Control
3 * Copyright (C) 2007 Arto Karppinen (arto.karppinen@iki.fi)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program 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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "irreco_cmd_chain.h"
21 #include <hildon/hildon-banner.h>
23 /**
24 * @addtogroup IrrecoCmdChain
25 * @ingroup Irreco
27 * IrrecoCmdChain contains a list of IrrecoCmds, which can then all be
28 * executed one after another by calling irreco_cmd_chain_execute().
30 * @{
33 /**
34 * @file
35 * Source file of @ref IrrecoCmdChain.
40 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
41 /* Datatypes */
42 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
44 typedef struct _IrrecoCmdChainExecute IrrecoCmdChainExecute;
45 struct _IrrecoCmdChainExecute {
47 IrrecoData *irreco_data;
48 GFunc call_when_done;
49 gpointer user_data;
51 GString *banner_message;
52 GtkWidget *banner;
54 /* Execution time will be timed in relation of time_sync. */
55 GTimeVal time_sync;
56 glong time_pos;
58 IrrecoCmdChain *self;
59 IrrecoCmd *command;
60 guint pos;
61 guint len;
66 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
67 /* Prototypes */
68 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
70 static gboolean irreco_cmd_chain_execute_next_2(IrrecoCmdChainExecute *execute);
74 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
75 /* Construction & Destruction */
76 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
78 /**
79 * @name Construction & Destruction
80 * @{
83 IrrecoCmdChain *irreco_cmd_chain_new()
85 IrrecoCmdChain *self;
86 IRRECO_ENTER
88 self = g_slice_new0(IrrecoCmdChain);
89 self->execution_rate = IRRECO_SECONDS_TO_USEC(0.3);
90 self->show_progress = TRUE;
91 IRRECO_RETURN_PTR(self);
94 IrrecoCmdChain *irreco_cmd_chain_new_from_config(IrrecoKeyFile *keyfile,
95 IrrecoData *irreco_data)
97 IrrecoCmdChain *self;
98 IRRECO_ENTER
100 self = irreco_cmd_chain_new();
101 irreco_cmd_chain_from_config(self, keyfile, irreco_data);
102 IRRECO_RETURN_PTR(self);
105 void irreco_cmd_chain_free(IrrecoCmdChain *self)
107 IRRECO_ENTER
108 if (self == NULL) IRRECO_RETURN
109 irreco_cmd_chain_remove_all(self);
110 g_slice_free(IrrecoCmdChain, self);
111 IRRECO_RETURN
115 * @deprecated
116 * @todo
118 IrrecoCmdChain *irreco_cmd_chain_create()
120 IRRECO_ENTER
121 IRRECO_RETURN_PTR(irreco_cmd_chain_new());
125 * @deprecated
126 * @todo
128 void irreco_cmd_chain_destroy(IrrecoCmdChain *self)
130 IRRECO_ENTER
131 irreco_cmd_chain_free(self);
132 IRRECO_RETURN
135 /** @} */
139 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
140 /* Private Functions */
141 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
144 * @name Private Functions
145 * @{
149 * Command execution phaze one, update banner.
151 static gboolean irreco_cmd_chain_execute_next_1(IrrecoCmdChainExecute *execute)
153 gdouble fraction;
154 IRRECO_ENTER
156 IRRECO_PRINTF("Command %i / %u\n", execute->pos + 1, execute->len);
157 execute->command = irreco_cmd_chain_get(execute->self, execute->pos);
159 g_string_printf(execute->banner_message, "%s%s", _("Executing: "),
160 irreco_cmd_get_long_name(execute->command));
161 IRRECO_PRINTF("%s\n", execute->banner_message->str);
163 /* Show progressbar if enabled. */
164 if (execute->self->show_progress) {
166 /* Setup banner. */
167 if (execute->banner == NULL) {
168 GtkWidget *owner;
169 owner = GTK_WIDGET(irreco_window_manager_get_gtk_window(
170 execute->irreco_data->window_manager));
171 execute->banner = hildon_banner_show_progress(
172 owner, NULL, execute->banner_message->str);
173 } else {
174 hildon_banner_set_text(HILDON_BANNER(execute->banner),
175 execute->banner_message->str);
178 /* Set progress. */
179 fraction = (float) 1 / (float) execute->len *
180 (float)(execute->pos + 1);
181 IRRECO_DEBUG("Proggressbar fraction %f\n", fraction);
182 hildon_banner_set_fraction(HILDON_BANNER(execute->banner),
183 fraction);
185 g_idle_add(G_SOURCEFUNC(irreco_cmd_chain_execute_next_2), execute);
186 IRRECO_RETURN_BOOL(FALSE);
190 * Command execution phaze two, execute command.
192 static gboolean irreco_cmd_chain_execute_next_2(IrrecoCmdChainExecute *execute)
194 gboolean result;
195 IRRECO_ENTER
197 /* Wait command delay is simply added to the time_pos. */
198 if (execute->command->type == IRRECO_COMMAND_WAIT) {
200 /* Wait command overrides the chain specific execution rate.*/
201 execute->time_pos = execute->time_pos
202 + execute->command->wait.delay;
203 execute->pos = execute->pos + 1;
204 result = TRUE;
205 } else {
206 result = irreco_cmd_execute(execute->command,
207 execute->irreco_data);
208 execute->time_pos = execute->time_pos
209 + execute->self->execution_rate;
210 execute->pos = execute->pos + 1;
213 /* Is something remaining to be executed? */
214 if (result == TRUE && execute->pos < execute->len) {
216 GTimeVal time_current, time_next;
217 glong time_diff;
219 g_get_current_time(&time_current);
220 time_next.tv_sec = execute->time_sync.tv_sec;
221 time_next.tv_usec = execute->time_sync.tv_usec;
222 g_time_val_add(&time_next, execute->time_pos);
224 /* How much time to next execution? */
225 time_diff = irreco_time_diff(&time_current, &time_next);
226 IRRECO_PRINTF("Executing next command after \"%li\" usec.\n",
227 time_diff);
229 /* Schedule next call. */
230 if (time_diff > 0) {
231 g_timeout_add(time_diff / 1000,
232 G_SOURCEFUNC(
233 irreco_cmd_chain_execute_next_1),
234 execute);
235 } else {
236 g_idle_add(G_SOURCEFUNC(
237 irreco_cmd_chain_execute_next_1),
238 execute);
241 /* End of chain. */
242 } else {
243 if (execute->banner) gtk_widget_destroy(execute->banner);
244 g_string_free(execute->banner_message, TRUE);
245 IRRECO_DEBUG("Calling call_when_done()\n");
246 execute->call_when_done(execute->self, execute->user_data);
247 g_slice_free(IrrecoCmdChainExecute, execute);
250 IRRECO_RETURN_BOOL(FALSE);
253 /** @} */
257 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
258 /* Public Functions */
259 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
262 * @name Public Functions
263 * @{
267 * Set command chain id.
269 void irreco_cmd_chain_set_id(IrrecoCmdChain *self,
270 IrrecoCmdChainId id)
272 IRRECO_ENTER
273 self->id = id;
274 IRRECO_RETURN
278 * Get command chain id.
280 IrrecoCmdChainId irreco_cmd_chain_get_id(IrrecoCmdChain *self)
282 IRRECO_ENTER
283 IRRECO_RETURN_INT(self->id);
287 * Save command chain into GKeyFile.
289 void irreco_cmd_chain_to_config(IrrecoCmdChain *self,
290 GKeyFile *keyfile)
292 gint command_id = 0;
293 GString *group = NULL;
294 IRRECO_ENTER
296 /* Save command chain settings to keyfile. */
297 group = g_string_new(NULL);
298 g_string_printf(group, "chain-%i", self->id);
299 g_key_file_set_integer(keyfile, group->str, "chain-id", self->id);
300 irreco_gkeyfile_set_glong(keyfile, group->str, "exec-rate",
301 self->execution_rate);
302 g_key_file_set_boolean(keyfile, group->str, "show-progress",
303 self->show_progress);
305 /* Save commands to keyfile. */
306 IRRECO_CMD_CHAIN_FOREACH(self, command)
307 g_string_printf(group, "chain-%i:command-%i", self->id, ++command_id);
308 g_key_file_set_integer(keyfile, group->str, "chain-id", self->id);
309 irreco_cmd_to_keyfile(command, keyfile, group->str);
310 IRRECO_CMD_CHAIN_FOREACH_END
312 g_string_free(group, TRUE);
313 IRRECO_RETURN
317 * Read command chain from IrrecoKeyFile.
319 gboolean irreco_cmd_chain_from_config(IrrecoCmdChain *self,
320 IrrecoKeyFile *keyfile,
321 IrrecoData *irreco_data)
323 guint i = 0;
324 gsize group_count = 0;
325 gchar **groups = NULL;
326 GString *prefix = NULL;
327 const gchar *group = NULL;
328 IRRECO_ENTER
330 /* Read command chain settings from keyfile. */
331 group = irreco_keyfile_get_group(keyfile);
332 IRRECO_PRINTF("Reading command chain from group \"%s\"\n", group);
334 if (!irreco_keyfile_get_int(keyfile, "chain-id", &self->id) ||
335 !irreco_keyfile_get_glong(keyfile, "exec-rate",
336 &self->execution_rate)) {
337 IRRECO_RETURN_BOOL(FALSE);
340 /* Optional keys. */
341 irreco_keyfile_get_bool(keyfile, "show-progress",
342 &self->show_progress);
344 /* Read commands. */
345 groups = g_key_file_get_groups(keyfile->keyfile, &group_count);
346 prefix = g_string_new(NULL);
347 g_string_printf(prefix, "chain-%i", self->id);
349 for (i = 0; i < group_count; i++) {
350 IrrecoCmdChainId id = 0;
351 const gchar *group = groups[i];
352 IrrecoCmd *command = NULL;
354 /* Read only command that belong to this chain. */
355 if (!g_str_has_prefix(group, prefix->str) ||
356 !irreco_keyfile_get_int(keyfile, "chain-id", &id) ||
357 self->id != id) {
358 continue;
361 IRRECO_PRINTF("Reading command from group \"%s\"\n", group);
362 irreco_keyfile_set_group(keyfile, group);
363 command = irreco_cmd_from_keyfile(irreco_data, keyfile);
364 if (command == NULL) continue;
366 IRRECO_PRINTF("Appending command to chain \"%i\".\n", self->id);
367 irreco_cmd_chain_append(self, command);
370 g_strfreev(groups);
371 g_string_free(prefix, TRUE);
372 IRRECO_RETURN_BOOL(TRUE);
376 * Remove all commands from command chain.
378 void irreco_cmd_chain_remove_all(IrrecoCmdChain *self)
380 IRRECO_ENTER
382 g_assert(self != NULL);
384 while (self->command_list != NULL) {
385 irreco_cmd_destroy(self->command_list->data);
386 self->command_list = g_list_remove(
387 self->command_list,
388 self->command_list->data);
390 IRRECO_RETURN
394 * Set interval between the start of execution of commands inside command chain.
396 void irreco_cmd_chain_set_execution_rate(IrrecoCmdChain *self,
397 glong execution_rate)
399 IRRECO_ENTER
400 g_assert(self != NULL);
401 IRRECO_PRINTF("Setting execution rate to \"%li\".\n", execution_rate);
402 self->execution_rate = execution_rate;
403 IRRECO_RETURN
407 * Append a command to command chain.
409 void irreco_cmd_chain_append(IrrecoCmdChain *self,
410 IrrecoCmd * irreco_cmd)
412 IRRECO_ENTER
414 g_assert(self != NULL);
416 self->command_list = g_list_append(
417 g_list_last(self->command_list), irreco_cmd);
418 IRRECO_RETURN
422 * Create a copy of command, and append the command to command chain.
424 void irreco_cmd_chain_append_copy(IrrecoCmdChain *self,
425 IrrecoCmd * irreco_cmd)
427 IRRECO_ENTER
429 g_assert(self != NULL);
431 self->command_list = g_list_append(
432 g_list_last(self->command_list),
433 irreco_cmd_dublicate(irreco_cmd));
434 IRRECO_RETURN
438 * Remove command by index.
440 void irreco_cmd_chain_remove(IrrecoCmdChain *self, guint index)
442 IrrecoCmd *irreco_cmd;
443 IRRECO_ENTER
445 g_assert(self != NULL);
447 IRRECO_DEBUG("Removing command from index \"%u\".\n", index);
448 irreco_cmd = (IrrecoCmd *) g_list_nth_data(g_list_first(
449 self->command_list), index);
450 irreco_cmd_destroy(irreco_cmd);
451 self->command_list = g_list_remove(
452 g_list_first(self->command_list), irreco_cmd);
454 IRRECO_RETURN
458 * Change order of commands inside command chain.
460 void irreco_cmd_chain_move(IrrecoCmdChain *self,
461 guint from_index, guint to_index)
463 gpointer data;
464 GList* from_link;
465 gint length;
466 IRRECO_ENTER
468 length = irreco_cmd_chain_length(self);
470 if (from_index < 0) {
471 from_index = 0;
472 } else if (from_index > length) {
473 IRRECO_RETURN
476 if (to_index > length) {
477 to_index = length;
478 } else if (to_index < 0) {
479 IRRECO_RETURN
482 from_link = g_list_nth(g_list_first(
483 self->command_list), from_index);
484 data = from_link->data;
485 self->command_list = g_list_delete_link(
486 self->command_list, from_link);
487 self->command_list = g_list_insert(g_list_first(
488 self->command_list), data, to_index);
490 IRRECO_RETURN
494 * Make a copy of a command chain.
496 * @param from Make a copy of this IrrecoCmdChain, or NULL.
498 void irreco_cmd_chain_copy(IrrecoCmdChain * from,
499 IrrecoCmdChain * to)
501 IRRECO_ENTER
502 irreco_cmd_chain_remove_all(to);
503 to->execution_rate = from->execution_rate;
504 to->show_progress = from->show_progress;
506 if (from == NULL) IRRECO_RETURN
507 IRRECO_CMD_CHAIN_FOREACH(from, command)
508 irreco_cmd_chain_append_copy(to, command);
509 IRRECO_CMD_CHAIN_FOREACH_END
511 IRRECO_RETURN
515 * Get number of command in command chain.
517 guint irreco_cmd_chain_length(IrrecoCmdChain *self)
519 IRRECO_ENTER
520 if (self->command_list == NULL) IRRECO_RETURN_UINT(0);
521 IRRECO_RETURN_UINT(g_list_length(g_list_first(
522 self->command_list)));
526 * Get Nth IrrecoCmd from command chain.
528 IrrecoCmd *irreco_cmd_chain_get(IrrecoCmdChain *self,
529 guint from_index)
531 IRRECO_ENTER
532 if (self->command_list == NULL) IRRECO_RETURN_PTR(NULL);
533 IRRECO_RETURN_PTR(g_list_nth_data(g_list_first(
534 self->command_list),
535 from_index));
539 * Print list of command inside command chain.
541 void irreco_cmd_chain_print(IrrecoCmdChain *self)
543 gint i = 0;
544 guint len;
545 IRRECO_ENTER
547 if (self == NULL) {
548 IRRECO_ERROR("IrrecoCmdChain pointer is NULL.\n");
549 IRRECO_RETURN
552 len = irreco_cmd_chain_length(self);
553 IRRECO_PRINTF("Printing command chain. Lenght: %u\n", len);
554 IRRECO_CMD_CHAIN_FOREACH(self, command)
555 IRRECO_PRINTF("Command %i / %u\n", ++i, len);
556 irreco_cmd_print(command);
557 IRRECO_CMD_CHAIN_FOREACH_END
559 IRRECO_RETURN
563 * Set if progressbar banner is shown when executing command chains.
565 void irreco_cmd_chain_set_show_progress(IrrecoCmdChain *self,
566 gboolean show_progress)
568 IRRECO_ENTER
569 self->show_progress = show_progress;
570 if (self->show_progress) {
571 IRRECO_PRINTF("Progressbar is enabled.\n");
572 } else {
573 IRRECO_PRINTF("Progressbar is disabled.\n");
575 IRRECO_RETURN
579 * Get if progressbar banner is shown when executing command chains.
581 gboolean irreco_cmd_chain_get_show_progress(IrrecoCmdChain *self)
583 IRRECO_ENTER
584 IRRECO_RETURN_INT(self->show_progress);
588 * Start executing the command chain.
590 * If the command chain is longer than one command, then delayed execution is
591 * started. In that case, call_when_done will be called when the command chain
592 * has finished executing.
594 * Data pointer will be the command chain, and user_data what user has given.
596 * @return TRUE if delayed execution started, FALSE otherwise.
598 gboolean irreco_cmd_chain_execute(IrrecoCmdChain *self,
599 IrrecoData *irreco_data,
600 GFunc call_when_done,
601 gpointer user_data)
603 guint len;
604 IRRECO_ENTER
606 /* Empty list. */
607 if (self->command_list == NULL) {
608 IRRECO_RETURN_BOOL(FALSE);
610 /* Only one comamnd. */
611 } else if ((len = irreco_cmd_chain_length(self)) == 1) {
612 irreco_cmd_execute(irreco_cmd_chain_get(self, 0),
613 irreco_data);
614 IRRECO_RETURN_BOOL(FALSE);
616 /* Multiple commands. */
617 } else {
618 IrrecoCmdChainExecute *execute;
620 execute = g_slice_new0(IrrecoCmdChainExecute);
621 execute->banner_message = g_string_new("");
622 execute->irreco_data = irreco_data;
623 execute->self = self;
624 execute->pos = 0;
625 execute->len = len;
627 execute->call_when_done = call_when_done;
628 execute->user_data = user_data;
630 g_get_current_time(&execute->time_sync);
631 irreco_cmd_chain_execute_next_1(execute);
633 IRRECO_RETURN_BOOL(TRUE);
636 /** @} */