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>
24 * @addtogroup IrrecoCmdChain
27 * IrrecoCmdChain contains a list of IrrecoCmds, which can then all be
28 * executed one after another by calling irreco_cmd_chain_execute().
35 * Source file of @ref IrrecoCmdChain.
40 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
42 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
44 typedef struct _IrrecoCmdChainExecute IrrecoCmdChainExecute
;
45 struct _IrrecoCmdChainExecute
{
47 IrrecoData
*irreco_data
;
51 GString
*banner_message
;
54 /* Execution time will be timed in relation of time_sync. */
66 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
68 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
70 static gboolean
irreco_cmd_chain_execute_next_2(IrrecoCmdChainExecute
*execute
);
74 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
75 /* Construction & Destruction */
76 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
79 * @name Construction & Destruction
83 IrrecoCmdChain
*irreco_cmd_chain_new()
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
)
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
)
108 if (self
== NULL
) IRRECO_RETURN
109 irreco_cmd_chain_remove_all(self
);
110 g_slice_free(IrrecoCmdChain
, self
);
118 IrrecoCmdChain
*irreco_cmd_chain_create()
121 IRRECO_RETURN_PTR(irreco_cmd_chain_new());
128 void irreco_cmd_chain_destroy(IrrecoCmdChain
*self
)
131 irreco_cmd_chain_free(self
);
139 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
140 /* Private Functions */
141 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
144 * @name Private Functions
149 * Command execution phaze one, update banner.
151 static gboolean
irreco_cmd_chain_execute_next_1(IrrecoCmdChainExecute
*execute
)
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
) {
167 if (execute
->banner
== NULL
) {
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
);
174 hildon_banner_set_text(HILDON_BANNER(execute
->banner
),
175 execute
->banner_message
->str
);
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
),
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
)
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;
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
;
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",
229 /* Schedule next call. */
231 g_timeout_add(time_diff
/ 1000,
233 irreco_cmd_chain_execute_next_1
),
236 g_idle_add(G_SOURCEFUNC(
237 irreco_cmd_chain_execute_next_1
),
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
);
257 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
258 /* Public Functions */
259 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
262 * @name Public Functions
267 * Set command chain id.
269 void irreco_cmd_chain_set_id(IrrecoCmdChain
*self
,
278 * Get command chain id.
280 IrrecoCmdChainId
irreco_cmd_chain_get_id(IrrecoCmdChain
*self
)
283 IRRECO_RETURN_INT(self
->id
);
287 * Save command chain into GKeyFile.
289 void irreco_cmd_chain_to_config(IrrecoCmdChain
*self
,
293 GString
*group
= NULL
;
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
);
317 * Read command chain from IrrecoKeyFile.
319 gboolean
irreco_cmd_chain_from_config(IrrecoCmdChain
*self
,
320 IrrecoKeyFile
*keyfile
,
321 IrrecoData
*irreco_data
)
324 gsize group_count
= 0;
325 gchar
**groups
= NULL
;
326 GString
*prefix
= NULL
;
327 const gchar
*group
= NULL
;
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
);
341 irreco_keyfile_get_bool(keyfile
, "show-progress",
342 &self
->show_progress
);
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
) ||
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
);
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
)
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(
388 self
->command_list
->data
);
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
)
400 g_assert(self
!= NULL
);
401 IRRECO_PRINTF("Setting execution rate to \"%li\".\n", execution_rate
);
402 self
->execution_rate
= execution_rate
;
407 * Append a command to command chain.
409 void irreco_cmd_chain_append(IrrecoCmdChain
*self
,
410 IrrecoCmd
* irreco_cmd
)
414 g_assert(self
!= NULL
);
416 self
->command_list
= g_list_append(
417 g_list_last(self
->command_list
), irreco_cmd
);
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
)
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
));
438 * Remove command by index.
440 void irreco_cmd_chain_remove(IrrecoCmdChain
*self
, guint index
)
442 IrrecoCmd
*irreco_cmd
;
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
);
458 * Change order of commands inside command chain.
460 void irreco_cmd_chain_move(IrrecoCmdChain
*self
,
461 guint from_index
, guint to_index
)
468 length
= irreco_cmd_chain_length(self
);
470 if (from_index
< 0) {
472 } else if (from_index
> length
) {
476 if (to_index
> length
) {
478 } else if (to_index
< 0) {
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
);
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
,
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
515 * Get number of command in command chain.
517 guint
irreco_cmd_chain_length(IrrecoCmdChain
*self
)
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
,
532 if (self
->command_list
== NULL
) IRRECO_RETURN_PTR(NULL
);
533 IRRECO_RETURN_PTR(g_list_nth_data(g_list_first(
539 * Print list of command inside command chain.
541 void irreco_cmd_chain_print(IrrecoCmdChain
*self
)
548 IRRECO_ERROR("IrrecoCmdChain pointer is NULL.\n");
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
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
)
569 self
->show_progress
= show_progress
;
570 if (self
->show_progress
) {
571 IRRECO_PRINTF("Progressbar is enabled.\n");
573 IRRECO_PRINTF("Progressbar is disabled.\n");
579 * Get if progressbar banner is shown when executing command chains.
581 gboolean
irreco_cmd_chain_get_show_progress(IrrecoCmdChain
*self
)
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
,
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),
614 IRRECO_RETURN_BOOL(FALSE
);
616 /* Multiple commands. */
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
;
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
);