girara
|
00001 /* See LICENSE file for license and copyright information */ 00002 00003 #include <string.h> 00004 #include <stdlib.h> 00005 #include <glib/gi18n-lib.h> 00006 00007 #include "commands.h" 00008 #include "datastructures.h" 00009 #include "session.h" 00010 #include "internal.h" 00011 #include "utils.h" 00012 #include "settings.h" 00013 #include "shortcuts.h" 00014 00015 #if GTK_MAJOR_VERSION == 2 00016 #include "gtk2-compat.h" 00017 #endif 00018 00019 /* default commands implementation */ 00020 bool 00021 girara_cmd_map_unmap(girara_session_t* session, girara_list_t* argument_list, 00022 bool unmap) 00023 { 00024 typedef struct gdk_keyboard_button_s 00025 { 00026 char* identifier; 00027 int keyval; 00028 } gdk_keyboard_button_t; 00029 00030 static const gdk_keyboard_button_t gdk_keyboard_buttons[] = { 00031 {"BackSpace", GDK_KEY_BackSpace}, 00032 {"CapsLock", GDK_KEY_Caps_Lock}, 00033 {"Down", GDK_KEY_Down}, 00034 {"Esc", GDK_KEY_Escape}, 00035 {"F10", GDK_KEY_F10}, 00036 {"F11", GDK_KEY_F11}, 00037 {"F12", GDK_KEY_F12}, 00038 {"F1", GDK_KEY_F1}, 00039 {"F2", GDK_KEY_F2}, 00040 {"F3", GDK_KEY_F3}, 00041 {"F4", GDK_KEY_F4}, 00042 {"F5", GDK_KEY_F5}, 00043 {"F6", GDK_KEY_F6}, 00044 {"F7", GDK_KEY_F7}, 00045 {"F8", GDK_KEY_F8}, 00046 {"F9", GDK_KEY_F9}, 00047 {"Left", GDK_KEY_Left}, 00048 {"PageDown", GDK_KEY_Page_Down}, 00049 {"PageUp", GDK_KEY_Page_Up}, 00050 {"Return", GDK_KEY_Return}, 00051 {"Right", GDK_KEY_Right}, 00052 {"Space", GDK_KEY_space}, 00053 {"Super", GDK_KEY_Super_L}, 00054 {"Tab", GDK_KEY_Tab}, 00055 {"ShiftTab", GDK_KEY_ISO_Left_Tab}, 00056 {"Up", GDK_KEY_Up} 00057 }; 00058 00059 typedef struct gdk_mouse_button_s 00060 { 00061 char* identifier; 00062 int button; 00063 } gdk_mouse_button_t; 00064 00065 static const gdk_mouse_button_t gdk_mouse_buttons[] = { 00066 {"Button1", GIRARA_MOUSE_BUTTON1}, 00067 {"Button2", GIRARA_MOUSE_BUTTON2}, 00068 {"Button3", GIRARA_MOUSE_BUTTON3}, 00069 {"Button4", GIRARA_MOUSE_BUTTON4}, 00070 {"Button5", GIRARA_MOUSE_BUTTON5}, 00071 {"Button6", GIRARA_MOUSE_BUTTON6}, 00072 {"Button7", GIRARA_MOUSE_BUTTON7}, 00073 {"Button8", GIRARA_MOUSE_BUTTON8}, 00074 {"Button9", GIRARA_MOUSE_BUTTON9} 00075 }; 00076 00077 typedef struct event_type_s 00078 { 00079 char* identifier; 00080 int event; 00081 } event_type_t; 00082 00083 static const event_type_t event_types[] = { 00084 {"motion", GIRARA_EVENT_MOTION_NOTIFY}, 00085 {"scroll_up", GIRARA_EVENT_SCROLL_UP}, 00086 {"scroll_down", GIRARA_EVENT_SCROLL_DOWN}, 00087 {"scroll_left", GIRARA_EVENT_SCROLL_LEFT}, 00088 {"scroll_right", GIRARA_EVENT_SCROLL_RIGHT} 00089 }; 00090 00091 typedef struct mouse_event_s 00092 { 00093 char* identifier; 00094 int event; 00095 } mouse_event_t; 00096 00097 static const mouse_event_t mouse_events[] = { 00098 {"button-pressed", GIRARA_EVENT_BUTTON_PRESS}, 00099 {"2-button-pressed", GIRARA_EVENT_2BUTTON_PRESS}, 00100 {"3-button-pressed", GIRARA_EVENT_2BUTTON_PRESS}, 00101 {"button-released", GIRARA_EVENT_BUTTON_RELEASE} 00102 }; 00103 00104 size_t number_of_arguments = girara_list_size(argument_list); 00105 00106 if (number_of_arguments < ((unmap == true) ? 1 : 2)) { 00107 if (unmap == true) { 00108 girara_notify(session, GIRARA_WARNING, _("Usage: unmap <binding>")); 00109 } else { 00110 girara_notify(session, GIRARA_WARNING, _("Usage: map <binding> <function>")); 00111 } 00112 return false; 00113 } 00114 00115 int shortcut_mask = 0; 00116 int shortcut_key = 0; 00117 int shortcut_mouse_button = 0; 00118 girara_mode_t shortcut_mode = session->modes.normal; 00119 char* shortcut_argument_data = NULL; 00120 int shortcut_argument_n = 0; 00121 char* shortcut_buffer_command = NULL; 00122 girara_event_type_t event_type = GIRARA_EVENT_BUTTON_PRESS; 00123 girara_shortcut_function_t shortcut_function = NULL; 00124 bool mouse_event = false; 00125 00126 size_t current_command = 0; 00127 char* tmp = girara_list_nth(argument_list, current_command); 00128 size_t tmp_length = strlen(tmp); 00129 00130 /* Check first argument for mode */ 00131 bool is_mode = false; 00132 if (tmp_length >= 3 && tmp[0] == '[' && tmp[tmp_length - 1] == ']') { 00133 char* tmp_inner = g_strndup(tmp + 1, tmp_length - 2); 00134 00135 GIRARA_LIST_FOREACH(session->modes.identifiers, girara_mode_string_t*, iter, mode) 00136 if (!g_strcmp0(tmp_inner, mode->name)) { 00137 shortcut_mode = mode->index; 00138 is_mode = true; 00139 break; 00140 } 00141 GIRARA_LIST_FOREACH_END(session->modes.identifiers, girara_mode_string_t*, iter, mode); 00142 00143 if (is_mode == false) { 00144 girara_warning("Unregistered mode specified: %s", tmp_inner); 00145 girara_notify(session, GIRARA_ERROR, _("Unregistered mode specified: %s"), tmp_inner); 00146 g_free(tmp_inner); 00147 return false; 00148 } 00149 g_free(tmp_inner); 00150 } 00151 00152 unsigned int limit = (unmap == true) ? 1 : 2; 00153 if (number_of_arguments < limit) { 00154 girara_warning("Invalid number of arguments passed: %zu instead of at least %u", number_of_arguments, limit); 00155 girara_notify(session, GIRARA_ERROR, 00156 _("Invalid number of arguments passed: %zu instead of at least %u"), number_of_arguments, limit); 00157 return false; 00158 } 00159 00160 if (is_mode == true) { 00161 tmp = girara_list_nth(argument_list, ++current_command); 00162 tmp_length = strlen(tmp); 00163 } 00164 00165 /* Check for multi key shortcut */ 00166 if (tmp_length >= 3 && tmp[0] == '<' && tmp[tmp_length - 1] == '>') { 00167 tmp = g_strndup(tmp + 1, tmp_length - 2); 00168 tmp_length = strlen(tmp); 00169 00170 /* Multi key shortcut */ 00171 if (strchr(tmp, '-') != NULL && tmp_length > 2) { 00172 switch (tmp[0]) { 00173 case 'S': 00174 shortcut_mask = GDK_SHIFT_MASK; 00175 break; 00176 case 'A': 00177 shortcut_mask = GDK_MOD1_MASK; 00178 break; 00179 case 'C': 00180 shortcut_mask = GDK_CONTROL_MASK; 00181 break; 00182 default: 00183 girara_warning("Invalid modifier in %s", tmp); 00184 girara_notify(session, GIRARA_ERROR, _("Invalid modifier in %s"), tmp); 00185 g_free(tmp); 00186 return false; 00187 } 00188 00189 /* Single key */ 00190 if (tmp_length == 3) { 00191 shortcut_key = tmp[2]; 00192 /* Possible special key */ 00193 } else { 00194 bool found = false; 00195 for (unsigned int i = 0; i < LENGTH(gdk_keyboard_buttons); i++) { 00196 if (g_strcmp0(tmp + 2, gdk_keyboard_buttons[i].identifier) == 0) { 00197 shortcut_key = gdk_keyboard_buttons[i].keyval; 00198 found = true; 00199 break; 00200 } 00201 } 00202 00203 for (unsigned int i = 0; i < LENGTH(gdk_mouse_buttons); i++) { 00204 if (!g_strcmp0(tmp + 2, gdk_mouse_buttons[i].identifier)) { 00205 shortcut_mouse_button = gdk_mouse_buttons[i].button; 00206 mouse_event = true; 00207 found = true; 00208 break; 00209 } 00210 } 00211 00212 for (unsigned int i = 0; i < LENGTH(event_types); i++) { 00213 if (!g_strcmp0(tmp + 2, event_types[i].identifier)) { 00214 event_type = event_types[i].event; 00215 mouse_event = true; 00216 found = true; 00217 break; 00218 } 00219 } 00220 00221 if (found == false) { 00222 girara_warning("Invalid special key value or mode: %s", tmp); 00223 girara_notify(session, GIRARA_ERROR, _("Invalid special key value for %s"), tmp); 00224 g_free(tmp); 00225 return false; 00226 } 00227 } 00228 /* Possible special key */ 00229 } else { 00230 bool found = false; 00231 for (unsigned int i = 0; i < LENGTH(gdk_keyboard_buttons); i++) { 00232 if (g_strcmp0(tmp, gdk_keyboard_buttons[i].identifier) == 0) { 00233 shortcut_key = gdk_keyboard_buttons[i].keyval; 00234 found = true; 00235 break; 00236 } 00237 } 00238 00239 for (unsigned int i = 0; i < LENGTH(gdk_mouse_buttons); i++) { 00240 if (!g_strcmp0(tmp, gdk_mouse_buttons[i].identifier)) { 00241 shortcut_mouse_button = gdk_mouse_buttons[i].button; 00242 mouse_event = true; 00243 found = true; 00244 break; 00245 } 00246 } 00247 00248 for (unsigned int i = 0; i < LENGTH(event_types); i++) { 00249 if (!g_strcmp0(tmp, event_types[i].identifier)) { 00250 event_type = event_types[i].event; 00251 mouse_event = true; 00252 found = true; 00253 break; 00254 } 00255 } 00256 00257 if (found == false) { 00258 girara_warning("Invalid special key value or mode: %s", tmp); 00259 girara_notify(session, GIRARA_ERROR, _("Invalid special key value or mode %s"), tmp); 00260 g_free(tmp); 00261 return false; 00262 } 00263 } 00264 00265 g_free(tmp); 00266 /* Single key shortcut */ 00267 } else if (tmp_length == 1) { 00268 shortcut_key = tmp[0]; 00269 /* Buffer command */ 00270 } else { 00271 shortcut_buffer_command = g_strdup(tmp); 00272 } 00273 00274 /* check for mouse mode */ 00275 bool mouse_mode = false; 00276 if (unmap == false) { 00277 if (++current_command < number_of_arguments) { 00278 tmp = girara_list_nth(argument_list, current_command); 00279 tmp_length = strlen(tmp); 00280 00281 if (tmp_length >= 3 && tmp[0] == '[' && tmp[tmp_length - 1] == ']') { 00282 mouse_mode = true; 00283 if (mouse_event == false) { 00284 girara_warning("Mode passed on non-mouse event: %s", tmp); 00285 return false; 00286 } 00287 00288 char* tmp_inner = g_strndup(tmp + 1, tmp_length - 2); 00289 00290 bool found = false; 00291 for (unsigned int i = 0; i < LENGTH(mouse_events); i++) { 00292 if (!g_strcmp0(tmp_inner, mouse_events[i].identifier)) { 00293 event_type = mouse_events[i].event; 00294 found = true; 00295 break; 00296 } 00297 } 00298 00299 if (found == false) { 00300 girara_warning("Invalid mouse event mode has been passed: %s", tmp_inner); 00301 g_free(tmp_inner); 00302 return false; 00303 } 00304 00305 g_free(tmp_inner); 00306 } 00307 } else { 00308 girara_warning("Invalid number of arguments passed"); 00309 return false; 00310 } 00311 } 00312 00313 if (unmap == false) { 00314 limit = (mouse_mode == true) ? 3 : 2; 00315 if (number_of_arguments < limit) { 00316 girara_warning("Invalid number of arguments passed: %zu instead of at least %u", number_of_arguments, limit); 00317 girara_notify(session, GIRARA_ERROR, 00318 _("Invalid number of arguments passed: %zu instead of at least %u"), number_of_arguments, limit); 00319 return false; 00320 } 00321 00322 if (mouse_mode == true) { 00323 tmp = girara_list_nth(argument_list, ++current_command); 00324 } 00325 } 00326 00327 /* Check for passed shortcut command */ 00328 if (unmap == false) { 00329 bool found_mapping = false; 00330 GIRARA_LIST_FOREACH(session->config.shortcut_mappings, girara_shortcut_mapping_t*, iter, mapping) 00331 if (!g_strcmp0(tmp, mapping->identifier)) { 00332 shortcut_function = mapping->function; 00333 found_mapping = true; 00334 break; 00335 } 00336 GIRARA_LIST_FOREACH_END(session->config.shortcut_mappings, girara_shortcut_mapping_t*, iter, mapping); 00337 00338 if (found_mapping == false) { 00339 girara_warning("Not a valid shortcut function: %s", tmp); 00340 girara_notify(session, GIRARA_ERROR, _("Not a valid shortcut function: %s"), tmp); 00341 if (shortcut_buffer_command) { 00342 g_free(shortcut_buffer_command); 00343 } 00344 return false; 00345 } 00346 } 00347 00348 /* Check for passed argument */ 00349 if (unmap == false) { 00350 if (++current_command < number_of_arguments) { 00351 tmp = (char*) girara_list_nth(argument_list, current_command); 00352 00353 GIRARA_LIST_FOREACH(session->config.argument_mappings, girara_argument_mapping_t*, iter, mapping) 00354 if (!g_strcmp0(tmp, mapping->identifier)) { 00355 shortcut_argument_n = mapping->value; 00356 break; 00357 } 00358 GIRARA_LIST_FOREACH_END(session->config.argument_mappings, girara_argument_mapping_t*, iter, mapping); 00359 00360 /* If no known argument is passed we save it in the data field */ 00361 if (shortcut_argument_n == 0) { 00362 shortcut_argument_data = tmp; 00363 /* If a known argument is passed and there are still more arguments, 00364 * we save the next one in the data field */ 00365 } else if (++current_command < number_of_arguments) { 00366 tmp = (char*) girara_list_nth(argument_list, current_command); 00367 shortcut_argument_data = tmp; 00368 } 00369 } 00370 } 00371 00372 if (mouse_event == false) { 00373 if (unmap == true) { 00374 girara_shortcut_remove(session, shortcut_mask, shortcut_key, 00375 shortcut_buffer_command, shortcut_mode); 00376 } else { 00377 girara_shortcut_add(session, shortcut_mask, shortcut_key, shortcut_buffer_command, 00378 shortcut_function, shortcut_mode, shortcut_argument_n, shortcut_argument_data); 00379 } 00380 } else { 00381 if (unmap == true) { 00382 girara_mouse_event_remove(session, shortcut_mask, shortcut_mouse_button, 00383 shortcut_mode); 00384 } else { 00385 girara_mouse_event_add(session, shortcut_mask, shortcut_mouse_button, 00386 shortcut_function, shortcut_mode, event_type, shortcut_argument_n, shortcut_argument_data); 00387 } 00388 } 00389 00390 if (shortcut_buffer_command) { 00391 g_free(shortcut_buffer_command); 00392 } 00393 00394 return true; 00395 } 00396 00397 bool 00398 girara_cmd_map(girara_session_t* session, girara_list_t* argument_list) 00399 { 00400 return girara_cmd_map_unmap(session, argument_list, false); 00401 } 00402 00403 bool 00404 girara_cmd_unmap(girara_session_t* session, girara_list_t* argument_list) 00405 { 00406 return girara_cmd_map_unmap(session, argument_list, true); 00407 } 00408 00409 00410 bool 00411 girara_cmd_quit(girara_session_t* session, girara_list_t* UNUSED(argument_list)) 00412 { 00413 girara_argument_t arg = { GIRARA_HIDE, NULL }; 00414 girara_isc_completion(session, &arg, NULL, 0); 00415 00416 gtk_main_quit(); 00417 00418 return true; 00419 } 00420 00421 bool 00422 girara_cmd_set(girara_session_t* session, girara_list_t* argument_list) 00423 { 00424 const size_t number_of_arguments = girara_list_size(argument_list); 00425 00426 if (number_of_arguments == 0) { 00427 girara_warning("Not enough arguments for :set."); 00428 girara_notify(session, GIRARA_ERROR, _("Not enough arguments.")); 00429 return false; 00430 } 00431 if (number_of_arguments > 2) { 00432 girara_warning("Too many arguments for :set."); 00433 girara_notify(session, GIRARA_ERROR, _("Too many arguments.")); 00434 return false; 00435 } 00436 00437 /* search for existing setting */ 00438 char* name = (char*) girara_list_nth(argument_list, 0); 00439 if (name == NULL) { 00440 return false; 00441 } 00442 00443 girara_setting_t* setting = girara_setting_find(session, name); 00444 if (setting == NULL) { 00445 girara_warning("Unknown option: %s", name); 00446 girara_notify(session, GIRARA_ERROR, _("Unknown option: %s"), name); 00447 return false; 00448 } 00449 00450 if (number_of_arguments == 1) { 00451 /* display setting*/ 00452 switch (girara_setting_get_type(setting)) { 00453 case BOOLEAN: 00454 { 00455 /* for compatibility reasons: toogle the setting */ 00456 bool value = false; 00457 girara_setting_get_value(setting, &value); 00458 bool tmp = !value; 00459 girara_setting_set_value(session, setting, &tmp); 00460 girara_notify(session, GIRARA_INFO, "%s: %s", name, tmp ? _("true") : _("false")); 00461 break; 00462 } 00463 case FLOAT: 00464 { 00465 float value = 0; 00466 girara_setting_get_value(setting, &value); 00467 girara_notify(session, GIRARA_INFO, "%s: %f", name, value); 00468 break; 00469 } 00470 case INT: 00471 { 00472 int value = 0; 00473 girara_setting_get_value(setting, &value); 00474 girara_notify(session, GIRARA_INFO, "%s: %i", name, value); 00475 break; 00476 } 00477 case STRING: 00478 { 00479 char* str = NULL; 00480 girara_setting_get_value(setting, &str); 00481 girara_notify(session, GIRARA_INFO, "%s: %s", name, str ? str : "(NULL)"); 00482 g_free(str); 00483 break; 00484 } 00485 default: 00486 return false; 00487 } 00488 } else { 00489 char* value = (char*) girara_list_nth(argument_list, 1); 00490 if (value == NULL) { 00491 girara_warning("No value defined for option: %s", name); 00492 girara_notify(session, GIRARA_ERROR, _("No value defined for option: %s"), name); 00493 return false; 00494 } 00495 00496 /* update value */ 00497 switch (girara_setting_get_type(setting)) { 00498 case BOOLEAN: 00499 if (g_strcmp0(value, "false") == 0 || g_strcmp0(value, "0") == 0) { 00500 bool b = false; 00501 girara_setting_set_value(session, setting, &b); 00502 } else if (g_strcmp0(value, "true") == 0 || g_strcmp0(value, "1") == 0) { 00503 bool b = true; 00504 girara_setting_set_value(session, setting, &b); 00505 } else { 00506 girara_warning("Unknown value for option: %s", name); 00507 girara_notify(session, GIRARA_ERROR, _("Unknown value for option: %s"), name); 00508 } 00509 break; 00510 case FLOAT: 00511 { 00512 float f = strtof(value, NULL); 00513 girara_setting_set_value(session, setting, &f); 00514 break; 00515 } 00516 case INT: 00517 { 00518 int i = atoi(value); 00519 girara_setting_set_value(session, setting, &i); 00520 break; 00521 } 00522 case STRING: 00523 girara_setting_set_value(session, setting, value); 00524 break; 00525 default: 00526 return false; 00527 } 00528 } 00529 00530 return true; 00531 } 00532 00533 bool 00534 girara_inputbar_command_add(girara_session_t* session, const char* command, 00535 const char* abbreviation, girara_command_function_t function, 00536 girara_completion_function_t completion, const char* description) 00537 { 00538 g_return_val_if_fail(session != NULL, false); 00539 g_return_val_if_fail(command != NULL, false); 00540 g_return_val_if_fail(function != NULL, false); 00541 00542 /* search for existing binding */ 00543 GIRARA_LIST_FOREACH(session->bindings.commands, girara_command_t*, iter, commands_it) 00544 if (g_strcmp0(commands_it->command, command) == 0) { 00545 g_free(commands_it->abbr); 00546 g_free(commands_it->description); 00547 00548 commands_it->abbr = abbreviation ? g_strdup(abbreviation) : NULL; 00549 commands_it->function = function; 00550 commands_it->completion = completion; 00551 commands_it->description = description ? g_strdup(description) : NULL; 00552 00553 girara_list_iterator_free(iter); 00554 return true; 00555 } 00556 GIRARA_LIST_FOREACH_END(session->bindings.commands, girara_command_t*, iter, commands_it); 00557 00558 /* add new inputbar command */ 00559 girara_command_t* new_command = g_slice_new(girara_command_t); 00560 00561 new_command->command = g_strdup(command); 00562 new_command->abbr = abbreviation ? g_strdup(abbreviation) : NULL; 00563 new_command->function = function; 00564 new_command->completion = completion; 00565 new_command->description = description ? g_strdup(description) : NULL; 00566 girara_list_append(session->bindings.commands, new_command); 00567 00568 return true; 00569 } 00570 00571 bool 00572 girara_special_command_add(girara_session_t* session, char identifier, girara_inputbar_special_function_t function, bool always, int argument_n, void* argument_data) 00573 { 00574 g_return_val_if_fail(session != NULL, false); 00575 g_return_val_if_fail(function != NULL, false); 00576 00577 girara_argument_t argument = {argument_n, argument_data}; 00578 00579 /* search for existing special command */ 00580 GIRARA_LIST_FOREACH(session->bindings.special_commands, girara_special_command_t*, iter, scommand_it) 00581 if (scommand_it->identifier == identifier) { 00582 scommand_it->function = function; 00583 scommand_it->always = always; 00584 scommand_it->argument = argument; 00585 girara_list_iterator_free(iter); 00586 return true; 00587 } 00588 GIRARA_LIST_FOREACH_END(session->bindings.special_commands, girara_special_command_t*, iter, scommand_it); 00589 00590 /* create new special command */ 00591 girara_special_command_t* special_command = g_slice_new(girara_special_command_t); 00592 00593 special_command->identifier = identifier; 00594 special_command->function = function; 00595 special_command->always = always; 00596 special_command->argument = argument; 00597 00598 girara_list_append(session->bindings.special_commands, special_command); 00599 00600 return true; 00601 } 00602 00603 void 00604 girara_special_command_free(girara_special_command_t* special_command) 00605 { 00606 if (special_command == NULL) { 00607 return; 00608 } 00609 g_slice_free(girara_special_command_t, special_command); 00610 } 00611 00612 void 00613 girara_command_free(girara_command_t* command) 00614 { 00615 if (command == NULL) { 00616 return; 00617 } 00618 00619 g_free(command->command); 00620 g_free(command->abbr); 00621 g_free(command->description); 00622 g_slice_free(girara_command_t, command); 00623 } 00624 00625 bool 00626 girara_cmd_exec(girara_session_t* session, girara_list_t* argument_list) 00627 { 00628 char* cmd = NULL; 00629 girara_setting_get(session, "exec-command", &cmd); 00630 if (cmd == NULL || strlen(cmd) == 0) { 00631 girara_warning("exec-command is invalid."); 00632 girara_notify(session, GIRARA_ERROR, _("exec-command is invalid.")); 00633 g_free(cmd); 00634 return false; 00635 } 00636 00637 GString* command = g_string_new(cmd); 00638 g_free(cmd); 00639 00640 GIRARA_LIST_FOREACH(argument_list, char*, iter, value) 00641 g_string_append_c(command, ' '); 00642 char* tmp = g_shell_quote(value); 00643 g_string_append(command, tmp); 00644 g_free(tmp); 00645 GIRARA_LIST_FOREACH_END(argument_list, char*, iter, value); 00646 00647 GError* error = NULL; 00648 gboolean ret = g_spawn_command_line_async(command->str, &error); 00649 if (error != NULL) { 00650 girara_warning("Failed to execute command: %s", error->message); 00651 girara_notify(session, GIRARA_ERROR, _("Failed to execute command: %s"), error->message); 00652 g_error_free(error); 00653 } 00654 00655 g_string_free(command, TRUE); 00656 return ret; 00657 }