Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/gui-wizard-gtk/main.c | 24 +-
src/gui-wizard-gtk/wizard.c | 1544 +++++++++++++++++----------------------
src/gui-wizard-gtk/wizard.glade | 10 +-
src/gui-wizard-gtk/wizard.h | 2 +
4 files changed, 703 insertions(+), 877 deletions(-)
diff --git a/src/gui-wizard-gtk/main.c b/src/gui-wizard-gtk/main.c
index 05d01e9..84b210e 100644
--- a/src/gui-wizard-gtk/main.c
+++ b/src/gui-wizard-gtk/main.c
@@ -22,12 +22,12 @@
#if HAVE_LOCALE_H
# include <locale.h>
#endif
+#include "run_event_list_thread.h"
char *g_glade_file = NULL;
char *g_dump_dir_name = NULL;
char *g_events = NULL;
GList *g_auto_event_list = NULL;
-int g_report_only = false;
problem_data_t *g_cd;
@@ -77,9 +77,14 @@ void reload_problem_data_from_dump_dir(void)
}
+struct elp_thread_args *g_event_process;
+
int main(int argc, char **argv)
{
const char *prgname = "abrt";
+
+ g_event_process = new_elp_thread_args();
+
abrt_init(argv);
/* I18n */
@@ -113,9 +118,8 @@ int main(int argc, char **argv)
OPT_v = 1 << 0,
OPT_g = 1 << 1,
OPT_p = 1 << 2,
- OPT_o = 1 << 3, // report only
- OPT_d = 1 << 4,
- OPT_e = 1 << 5,
+ OPT_d = 1 << 3,
+ OPT_e = 1 << 4,
};
/* Keep enum above and order of options below in sync! */
struct options program_options[] = {
@@ -123,7 +127,6 @@ int main(int argc, char **argv)
OPT_STRING('g', NULL, &g_glade_file, "FILE",
_("Alternate GUI file")),
OPT_BOOL( 'p', NULL, NULL, _("Add program
names to log")),
/* for use from 3rd party apps to show just a reporter selector */
- OPT_BOOL( 'o', "report-only", &g_report_only,
_("Skip analyze steps, go through report steps only")),
OPT_BOOL( 'd', "delete", NULL,
_("Remove DIR after reporting")),
OPT_LIST( 'e', "event", &g_auto_event_list,
"EVENT", _("Run only this event")),
OPT_END()
@@ -145,15 +148,24 @@ int main(int argc, char **argv)
reload_problem_data_from_dump_dir();
+ gdk_threads_init ();
+ gdk_threads_enter ();
+
+ if (elp_thread_init(g_event_process))
+ perror_msg_and_die("initializatoin of event process thread failed");
+
create_assistant();
g_custom_logger = &show_error_as_msgbox;
update_gui_state_from_problem_data();
-
/* Enter main loop */
gtk_main();
+ gdk_threads_leave();
+
+ free_elp_thread_args(g_event_process);
+
if (opts & OPT_d)
delete_dump_dir_possibly_using_abrtd(g_dump_dir_name);
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index 30c25ee..8ad8285 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -20,6 +20,9 @@
#include <gdk/gdkkeysyms.h>
#include "client.h"
#include "internal_libreport_gtk.h"
+#include "run_event.h"
+#include "run_event_list.h"
+#include "run_event_list_thread.h"
#include "wizard.h"
#define DEFAULT_WIDTH 800
@@ -30,7 +33,6 @@
# define GDK_KEY_Delete GDK_Delete
# define GDK_KEY_KP_Delete GDK_KP_Delete
#endif
-
typedef struct event_gui_data_t
{
char *event_name;
@@ -38,12 +40,55 @@ typedef struct event_gui_data_t
} event_gui_data_t;
-static char *g_event_selected;
-static unsigned g_black_event_count = 0;
+static enum elp_signal_ret gtk_next_event_selected(struct event_list_process *process);
+static enum elp_signal_ret gtk_review_data(struct event_list_process *process);
+static enum elp_signal_ret gtk_run_event(struct event_list_process *process);
+static enum elp_signal_ret gtk_event_done(struct event_list_process *process);
+static enum elp_signal_ret gtk_finished(struct event_list_process *process);
+static enum elp_signal_ret gtk_configuration_issue(struct event_list_process *process);
+
+static void gtk_alert(const char *msg, void *args);
+static char *gtk_ask(const char *msg, void *args);
+static int gtk_ask_yes_no(const char *msg, void *args);
+static int gtk_ask_password(const char *msg, char **password, void *args);
+static void gtk_command_started(pid_t pid, void *args);
+static void gtk_command_msg_processed(const char *msg, const char *raw_input, const char
*rsp, void *args);
+static void gtk_command_finished(int retval, int status, const char *err_msg, void
*args);
+
+static struct elp_signals_impl g_process_impl = {
+ .next_event_selected=gtk_next_event_selected,
+ .review_data=gtk_review_data,
+ .run_event=gtk_run_event,
+ .event_done=gtk_event_done,
+ .finished=gtk_finished,
+ .configuration_issue=gtk_configuration_issue,
+};
+
+static struct run_event_impl *g_run_impl;
+
+static struct run_event_impl g_gtk_run_impl = {
+ .alert=gtk_alert,
+ .ask=gtk_ask,
+ .ask_yes_no=gtk_ask_yes_no,
+ .ask_password=gtk_ask_password,
+ .args=NULL,
+};
+
+static struct run_event_observer *g_run_obs;
+
+static struct run_event_observer g_gtk_run_obs = {
+ .command_started=gtk_command_started,
+ .command_msg_processed=gtk_command_msg_processed,
+ .command_finished=gtk_command_finished,
+ .args=NULL,
+};
+
+static pthread_t g_gui_thread_id;
-static pid_t g_event_child_pid = 0;
+static char *g_event_selected;
static bool g_expert_mode;
+static bool g_reviewing_data;
static GtkNotebook *g_assistant;
static GtkWindow *g_wnd_assistant;
@@ -60,10 +105,6 @@ static GtkLabel *g_lbl_event_log;
static GtkTextView *g_tv_event_log;
/* List of event_gui_data's */
-
-/* List of event_gui_data's */
-static GList *g_list_selected_reporters;
-
static GtkContainer *g_container_details1;
static GtkContainer *g_container_details2;
@@ -157,13 +198,13 @@ enum {
* instead of strcmp.
*/
static const gchar PAGE_SUMMARY[] = "page_0";
-static const gchar PAGE_EVENT_SELECTOR[] = "page_2_report";
+static const gchar PAGE_EVENT_SELECTOR[] = "page_2";
static const gchar PAGE_EDIT_COMMENT[] = "page_1";
static const gchar PAGE_EDIT_ELEMENTS[] = "page_3";
-static const gchar PAGE_REVIEW_DATA[] = "page_4_report";
-static const gchar PAGE_EVENT_PROGRESS[] = "page_5_report";
-static const gchar PAGE_EVENT_DONE[] = "page_6_report";
-static const gchar PAGE_NOT_SHOWN[] = "page_7_report";
+static const gchar PAGE_REVIEW_DATA[] = "page_4";
+static const gchar PAGE_EVENT_PROGRESS[] = "page_5";
+static const gchar PAGE_EVENT_DONE[] = "page_6";
+static const gchar PAGE_NOT_SHOWN[] = "page_7";
static const gchar *const page_names[] =
{
@@ -188,9 +229,31 @@ typedef struct
static page_obj_t pages[NUM_PAGES];
-static struct strbuf *cmd_output = NULL;
+//static struct strbuf *cmd_output = NULL;
+
+static gint select_next_page_no(gint current_page_no);
+static void on_comment_changed(GtkTextBuffer *buffer, gpointer user_data);
/* Utility functions */
+static char *format_glist_of_strings(const GList *list, const char *item_format, const
char *delimiter)
+{
+ struct strbuf *buf = strbuf_new();
+
+ const GList *i = list;
+ if (i)
+ {
+ strbuf_append_strf(buf, item_format, i->data);
+ i = g_list_next(i);
+ }
+
+ for(; i; i = g_list_next(i))
+ {
+ strbuf_append_str(buf, delimiter);
+ strbuf_append_strf(buf, item_format, i->data);
+ }
+
+ return strbuf_free_nobuf(buf);
+}
static void wrap_fixer(GtkWidget *widget, gpointer data_unused)
{
@@ -254,17 +317,27 @@ static void on_configure_event_cb(GtkWidget *button, gpointer
user_data)
}
}
-static void show_event_opt_error_dialog(const char *event_name)
+static void show_event_list_opt_error_dialog(const GList *events)
{
- event_config_t *ec = get_event_config(event_name);
+ struct strbuf *buf = strbuf_new();
+ for(const GList *e = events; e; e = g_list_next(e))
+ {
+ event_config_t *ec = get_event_config(e->data);
+
+ if (e != events)
+ strbuf_append_strf(buf,",%s", ec ? ec->screen_name :
e->data);
+ else
+ strbuf_append_strf(buf,"%s", ec ? ec->screen_name :
e->data);
+ }
+
+ char *names = strbuf_free_nobuf(buf);
+
char *message = xasprintf(_("Wrong settings detected for %s, "
"reporting will probably fail if you continue "
- "with the current configuration."),
- ec->screen_name);
+ "with the current configuration."), names);
char *markup_message = xasprintf(_("Wrong settings detected for
<b>%s</b>, "
"reporting will probably fail if you continue "
- "with the current configuration."),
- ec->screen_name);
+ "with the current configuration."), names);
GtkWidget *wrong_settings = g_top_most_window =
gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING,
@@ -276,22 +349,36 @@ static void show_event_opt_error_dialog(const char *event_name)
markup_message);
free(message);
free(markup_message);
+ free(names);
GtkWidget *act_area = gtk_dialog_get_content_area(GTK_DIALOG(wrong_settings));
- char * conf_btn_lbl = xasprintf(_("Con_figure %s"), ec->screen_name);
- GtkWidget *configure_event_btn = gtk_button_new_with_mnemonic(conf_btn_lbl);
- g_signal_connect(configure_event_btn, "clicked",
G_CALLBACK(on_configure_event_cb), (gpointer)event_name);
- free(conf_btn_lbl);
-
- gtk_box_pack_start(GTK_BOX(act_area), configure_event_btn, false, false, 0);
- gtk_widget_show(configure_event_btn);
+ for(const GList *e = events; e; e = g_list_next(e))
+ {
+ event_config_t *ec = get_event_config(e->data);
+ char * conf_btn_lbl = xasprintf(_("Configure %s"),
ec->screen_name);
+ GtkWidget *configure_event_btn = gtk_button_new_with_mnemonic(conf_btn_lbl);
+ g_signal_connect(configure_event_btn, "clicked",
G_CALLBACK(on_configure_event_cb), (gpointer)e->data);
+ free(conf_btn_lbl);
+ gtk_box_pack_start(GTK_BOX(act_area), configure_event_btn, false, false, 0);
+ gtk_widget_show(configure_event_btn);
+ }
gtk_dialog_run(GTK_DIALOG(wrong_settings));
if (g_top_most_window)
gtk_widget_destroy(wrong_settings);
}
+static void show_event_opt_error_dialog(const char *event_name)
+{
+ GList *e = NULL;
+ log("%s", event_name);
+ e = g_list_append(e, (gpointer)event_name);
+ show_event_list_opt_error_dialog(e);
+ g_list_free(e);
+ return;
+}
+
static void update_window_title(void)
{
/* prgname can be null according to gtk documentation */
@@ -365,6 +452,7 @@ struct dump_dir *steal_if_needed(struct dump_dir *dd)
*/
char *old_name = g_dump_dir_name;
g_dump_dir_name = xstrdup(dd->dd_dirname);
+ VERB1 log("New dump dir path '%s'", g_dump_dir_name);
dd_close(dd);
update_window_title();
@@ -378,8 +466,11 @@ struct dump_dir *steal_if_needed(struct dump_dir *dd)
return dd;
}
-void show_error_as_msgbox(const char *msg)
+void show_error_as_msgbox_mts(const char *msg, bool need_lock)
{
+ if (need_lock)
+ gdk_threads_enter();
+
GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING,
@@ -388,6 +479,14 @@ void show_error_as_msgbox(const char *msg)
);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
+
+ if (need_lock)
+ gdk_threads_leave();
+}
+
+void show_error_as_msgbox(const char *msg)
+{
+ show_error_as_msgbox_mts(msg, !pthread_equal(g_gui_thread_id, pthread_self()));
}
static void load_text_to_text_view(GtkTextView *tv, const char *name)
@@ -715,38 +814,6 @@ static void event_rb_was_toggled(GtkButton *button, gpointer
user_data)
* Set "toggled" callback on each button to given GCallback if it's not
NULL.
* Return active button (or NULL if none created).
*/
-/* helper */
-static char *missing_items_in_comma_list(const char *input_item_list)
-{
- if (!input_item_list)
- return NULL;
-
- char *item_list = xstrdup(input_item_list);
- char *result = item_list;
- char *dst = item_list;
-
- while (item_list[0])
- {
- char *end = strchr(item_list, ',');
- if (end) *end = '\0';
- if (!get_problem_data_item_or_NULL(g_cd, item_list))
- {
- if (dst != result)
- *dst++ = ',';
- dst = stpcpy(dst, item_list);
- }
- if (!end)
- break;
- *end = ',';
- item_list = end + 1;
- }
- if (result == dst)
- {
- free(result);
- result = NULL;
- }
- return result;
-}
static event_gui_data_t *add_event_buttons(GtkBox *box,
GList **p_event_list,
char *event_name,
@@ -758,8 +825,6 @@ static event_gui_data_t *add_event_buttons(GtkBox *box,
g_list_free(*p_event_list);
*p_event_list = NULL;
- g_black_event_count = 0;
-
if (!event_name || !event_name[0])
{
GtkWidget *lbl = gtk_label_new(_("No reporting targets are defined for this
problem. Check configuration in /etc/libreport/*"));
@@ -795,31 +860,19 @@ static event_gui_data_t *add_event_buttons(GtkBox *box,
event_screen_name = cfg->screen_name;
event_description = cfg->description;
- char *missing = missing_items_in_comma_list(cfg->ec_requires_items);
- if (missing)
- {
- red_choice = true;
- event_description = tmp_description = xasprintf(_("(requires:
%s)"), missing);
- free(missing);
- }
- else
- if (cfg->ec_creates_items)
+ GList *issues = NULL;
+ enum event_usability_status status = check_event_usability(cfg, g_cd, NULL,
&issues, EUS_LOW);
+
+ red_choice = status == EUS_UNUSABLE;
+ green_choice = status == EUS_LOW;
+
+ if (issues)
{
- if (get_problem_data_item_or_NULL(g_cd, cfg->ec_creates_items))
- {
- char *missing =
missing_items_in_comma_list(cfg->ec_creates_items);
- if (missing)
- free(missing);
- else
- {
- green_choice = true;
- event_description = tmp_description = xasprintf(_("(not
needed, data already exist: %s)"), cfg->ec_creates_items);
- }
- }
+ event_description = tmp_description = format_glist_of_strings(issues,
"(%s)", ",");
+ tmp_description[strlen(tmp_description)-1] = '\0';
+ g_list_free_full(issues, (GDestroyNotify)free);
}
}
- if (!green_choice && !red_choice)
- g_black_event_count++;
//VERB2 log("adding button '%s' to box %p", event_name, box);
char *event_label = xasprintf("%s%s%s",
@@ -991,9 +1044,9 @@ static void append_item_to_ls_details(gpointer name, gpointer value,
gpointer da
}
/* Based on selected reporter, update item checkboxes */
-static void update_ls_details_checkboxes(void)
+static void update_ls_details_checkboxes(const char *event_name)
{
- event_config_t *cfg = get_event_config(g_event_selected);
+ event_config_t *cfg = get_event_config(event_name);
//log("%s: event:'%s', cfg:'%p'", __func__,
g_event_selected, cfg);
GHashTableIter iter;
char *name;
@@ -1117,32 +1170,6 @@ void update_gui_state_from_problem_data(void)
gtk_widget_show_all(GTK_WIDGET(g_wnd_assistant));
}
-
-/* start_event_run */
-
-struct analyze_event_data
-{
- struct run_event_state *run_state;
- const char *event_name;
- GList *env_list;
- GtkWidget *page_widget;
- GtkLabel *status_label;
- GtkTextView *tv_log;
- const char *success_msg;
- const char *error_msg;
- GIOChannel *channel;
- struct strbuf *event_log;
- int event_log_state;
- int fd;
- /*guint event_source_id;*/
-};
-enum {
- LOGSTATE_FIRSTLINE = 0,
- LOGSTATE_BEGLINE,
- LOGSTATE_ERRLINE,
- LOGSTATE_MIDLINE,
-};
-
static void set_excluded_envvar(void)
{
struct strbuf *item_list = strbuf_new();
@@ -1179,491 +1206,6 @@ static void set_excluded_envvar(void)
unsetenv("EXCLUDE_FROM_REPORT");
}
-static int spawn_next_command_in_evd(struct analyze_event_data *evd)
-{
- evd->env_list = export_event_config(evd->event_name);
- int r = spawn_next_command(evd->run_state, g_dump_dir_name, evd->event_name);
- if (r >= 0)
- {
- g_event_child_pid = evd->run_state->command_pid;
- }
- else
- {
- unexport_event_config(evd->env_list);
- evd->env_list = NULL;
- }
- return r;
-}
-
-static void save_to_event_log(struct analyze_event_data *evd, const char *str)
-{
- static const char delim[] = {
- [LOGSTATE_FIRSTLINE] = '>',
- [LOGSTATE_BEGLINE] = ' ',
- [LOGSTATE_ERRLINE] = '*',
- };
-
- while (str[0])
- {
- char *end = strchrnul(str, '\n');
- char end_char = *end;
- if (end_char == '\n')
- end++;
- switch (evd->event_log_state)
- {
- case LOGSTATE_FIRSTLINE:
- case LOGSTATE_BEGLINE:
- case LOGSTATE_ERRLINE:
- /* skip empty lines */
- if (str[0] == '\n')
- goto next;
- strbuf_append_strf(evd->event_log, "%s%c %.*s",
- iso_date_string(NULL),
- delim[evd->event_log_state],
- (int)(end - str), str
- );
- break;
- case LOGSTATE_MIDLINE:
- strbuf_append_strf(evd->event_log, "%.*s", (int)(end - str),
str);
- break;
- }
- evd->event_log_state = LOGSTATE_MIDLINE;
- if (end_char != '\n')
- break;
- evd->event_log_state = LOGSTATE_BEGLINE;
- next:
- str = end;
- }
-}
-
-static void update_event_log_on_disk(const char *str)
-{
- /* Load existing log */
- struct dump_dir *dd = dd_opendir(g_dump_dir_name, 0);
- if (!dd)
- return;
- char *event_log = dd_load_text_ext(dd, FILENAME_EVENT_LOG, DD_FAIL_QUIETLY_ENOENT);
-
- /* Append new log part to existing log */
- unsigned len = strlen(event_log);
- if (len != 0 && event_log[len - 1] != '\n')
- event_log = append_to_malloced_string(event_log, "\n");
- event_log = append_to_malloced_string(event_log, str);
-
- /* Trim log according to size watermarks */
- len = strlen(event_log);
- char *new_log = event_log;
- if (len > EVENT_LOG_HIGH_WATERMARK)
- {
- new_log += len - EVENT_LOG_LOW_WATERMARK;
- new_log = strchrnul(new_log, '\n');
- if (new_log[0])
- new_log++;
- }
-
- /* Save */
- dd_save_text(dd, FILENAME_EVENT_LOG, new_log);
- free(event_log);
- dd_close(dd);
-}
-
-static void on_btn_cancel_event(GtkButton *button)
-{
- if (g_event_child_pid > 0)
- kill(- g_event_child_pid, SIGTERM);
-}
-
-static gboolean consume_cmd_output(GIOChannel *source, GIOCondition condition, gpointer
data)
-{
- struct analyze_event_data *evd = data;
-
- /* Read and insert the output into the log pane */
- char buf[257]; /* usually we get one line, no need to have big buf */
- int r;
- int alert_prefix_len = strlen(REPORT_PREFIX_ALERT);
- int ask_prefix_len = strlen(REPORT_PREFIX_ASK);
- int ask_yes_no_prefix_len = strlen(REPORT_PREFIX_ASK_YES_NO);
- int ask_password_prefix_len = strlen(REPORT_PREFIX_ASK_PASSWORD);
-
- if (!cmd_output)
- cmd_output = strbuf_new();
-
- /* read buffered and split lines */
- while ((r = read(evd->fd, buf, sizeof(buf) - 1)) > 0)
- {
- char *newline;
- char *raw;
- buf[r] = '\0';
- raw = buf;
-
- /* split lines in the current buffer */
- while ((newline = strchr(raw, '\n')) != NULL)
- {
- *newline = '\0';
- strbuf_append_str(cmd_output, raw);
- char *msg = cmd_output->buf;
-
- /* In the code below:
- * response is always malloced,
- * log_response is always set to response
- * or to constant string.
- */
- char *response = NULL;
- const char *log_response = response;
- unsigned skip_chars = 0;
-
- char * tagged_msg = NULL;
-
- /* alert dialog */
- if (strncmp(REPORT_PREFIX_ALERT, msg, alert_prefix_len) == 0)
- {
- skip_chars = alert_prefix_len;
-
- GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_CLOSE,
- "%s", msg + skip_chars);
- tagged_msg = tag_url(msg + skip_chars, "\n");
- gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), tagged_msg);
-
- gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy(dialog);
- }
- /* ask dialog with textbox */
- else if (strncmp(REPORT_PREFIX_ASK, msg, ask_prefix_len) == 0)
- {
- skip_chars = ask_prefix_len;
-
- GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_OK_CANCEL,
- "%s", msg + skip_chars);
- tagged_msg = tag_url(msg + skip_chars, "\n");
- gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), tagged_msg);
-
- GtkWidget *vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
- GtkWidget *textbox = gtk_entry_new();
- /* gtk_entry_set_editable(GTK_ENTRY(textbox), TRUE);
- * is not available in gtk3, so please use the highlevel
- * g_object_set
- */
- g_object_set(G_OBJECT(textbox), "editable", TRUE, NULL);
- gtk_box_pack_start(GTK_BOX(vbox), textbox, TRUE, TRUE, 0);
- gtk_widget_show(textbox);
- if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
- {
- const char *text = gtk_entry_get_text(GTK_ENTRY(textbox));
- response = xstrdup(text);
- log_response = response;
- }
- else
- {
- response = xstrdup("");
- log_response = "";
- }
- gtk_widget_destroy(textbox);
- gtk_widget_destroy(dialog);
- }
- /* ask dialog with passwordbox */
- else if (strncmp(REPORT_PREFIX_ASK_PASSWORD, msg, ask_password_prefix_len) ==
0)
- {
- skip_chars = ask_password_prefix_len;
-
- GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_OK_CANCEL,
- "%s", msg + skip_chars);
- tagged_msg = tag_url(msg + skip_chars, "\n");
- gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), tagged_msg);
-
- GtkWidget *vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
- GtkWidget *textbox = gtk_entry_new();
- /* gtk_entry_set_editable(GTK_ENTRY(textbox), TRUE);
- * is not available in gtk3, so please use the highlevel
- * g_object_set
- */
- g_object_set(G_OBJECT(textbox), "editable", TRUE, NULL);
- gtk_entry_set_visibility(GTK_ENTRY(textbox), FALSE);
- gtk_box_pack_start(GTK_BOX(vbox), textbox, TRUE, TRUE, 0);
- gtk_widget_show(textbox);
- if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
- {
- const char *text = gtk_entry_get_text(GTK_ENTRY(textbox));
- response = xstrdup(text);
- log_response = "******"; /* don't log passwords! */
- }
- else
- {
- response = xstrdup("");
- log_response = "";
- }
- gtk_widget_destroy(textbox);
- gtk_widget_destroy(dialog);
- }
- /* yes/no dialog */
- else if (strncmp(REPORT_PREFIX_ASK_YES_NO, msg, ask_yes_no_prefix_len) == 0)
- {
- skip_chars = ask_yes_no_prefix_len;
-
- GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_YES_NO,
- "%s", msg + skip_chars);
- tagged_msg = tag_url(msg + skip_chars, "\n");
- gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), tagged_msg);
-
- if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
- {
- response = xstrdup(_("y"));
- log_response = "YES";
- }
- else
- {
- response = xstrdup("");
- log_response = "NO";
- }
- gtk_widget_destroy(dialog);
- }
- /* else: no special prefix, just forward to log */
-
- if (response)
- {
- unsigned len = strlen(response);
- response[len++] = '\n';
- if (full_write(evd->run_state->command_in_fd, response, len) !=
len)
- {
- VERB1 perror_msg("Can't write %u bytes to child's
stdin", len);
- free(response);
- response = xstrdup("<WRITE ERROR>");
- log_response = response;
- }
- strbuf_append_char(cmd_output, ' ');
- strbuf_append_str(cmd_output, log_response);
- free(response);
- }
-
- msg = cmd_output->buf;
- msg += skip_chars;
- gtk_label_set_text(g_lbl_event_log, msg);
-
- strbuf_append_char(cmd_output, '\n');
- msg = cmd_output->buf;
- msg += skip_chars;
- append_to_textview(evd->tv_log, msg);
- save_to_event_log(evd, msg);
-
- strbuf_clear(cmd_output);
-
- /* jump to next line */
- raw = newline + 1;
- free(tagged_msg);
- }
-
- /* beginning of next line. the line continues by next read() */
- strbuf_append_str(cmd_output, raw);
- }
-
- if (r < 0 && errno == EAGAIN)
- /* We got all buffered data, but fd is still open. Done for now */
- return TRUE; /* "please don't remove this event (yet)" */
-
- /* EOF/error */
-
- strbuf_clear(cmd_output);
-
- unexport_event_config(evd->env_list);
- evd->env_list = NULL;
-
- /* Wait for child to actually exit, collect status */
- int status;
- safe_waitpid(evd->run_state->command_pid, &status, 0);
- int retval = WEXITSTATUS(status);
- if (WIFSIGNALED(status))
- retval = WTERMSIG(status) + 128;
-
- /* Make sure "Cancel" button won't send anything (process is gone) */
- g_event_child_pid = -1;
- evd->run_state->command_pid = -1; /* just for consistency */
-
- /* Write a final message to the log */
- if (evd->event_log->len != 0 &&
evd->event_log->buf[evd->event_log->len - 1] != '\n')
- save_to_event_log(evd, "\n");
- /* If program failed, or if it finished successfully without saying anything... */
- if (retval != 0 || evd->event_log_state == LOGSTATE_FIRSTLINE)
- {
- if (retval != 0) /* If program failed, emit error line */
- evd->event_log_state = LOGSTATE_ERRLINE;
- char *msg;
- if (WIFSIGNALED(status))
- msg = xasprintf("(killed by signal %u)\n", WTERMSIG(status));
- else
- msg = xasprintf("(exited with %u)\n", retval);
- append_to_textview(evd->tv_log, msg);
- save_to_event_log(evd, msg);
- free(msg);
- }
-
- /* Append log to FILENAME_EVENT_LOG */
- update_event_log_on_disk(evd->event_log->buf);
- strbuf_clear(evd->event_log);
- evd->event_log_state = LOGSTATE_FIRSTLINE;
-
- if (geteuid() == 0)
- {
- /* Reset mode/uig/gid to correct values for all files created by event run */
- struct dump_dir *dd = dd_opendir(g_dump_dir_name, 0);
- if (dd)
- {
- dd_sanitize_mode_and_owner(dd);
- dd_close(dd);
- }
- }
-
- if (retval != 0)
- {
- /* If we were running -e EV1 -e EV2, stop if EV1 failed: */
- g_auto_event_list = NULL;
- }
-
- /* Stop if exit code is not 0, or no more commands */
- if (retval != 0
- || spawn_next_command_in_evd(evd) < 0
- ) {
- VERB1 log("done running event on '%s': %d", g_dump_dir_name,
retval);
- append_to_textview(evd->tv_log, "\n");
-
- if (retval)
- gtk_label_set_text(evd->status_label, evd->error_msg);
- else
- gtk_label_set_text(evd->status_label, evd->success_msg);
-
- /* Free child output buffer */
- strbuf_free(cmd_output);
- cmd_output = NULL;
-
- /* Hide spinner and stop btn */
- gtk_widget_hide(GTK_WIDGET(g_spinner_event_log));
- gtk_widget_hide(g_btn_stop);
- /* Enable (un-gray out) navigation buttons */
- gtk_widget_set_sensitive(g_btn_close, true);
- gtk_widget_set_sensitive(g_btn_next, true);
-
- /*g_source_remove(evd->event_source_id);*/
- close(evd->fd);
- free_run_event_state(evd->run_state);
- strbuf_free(evd->event_log);
- free(evd);
-
- reload_problem_data_from_dump_dir();
- update_gui_state_from_problem_data();
-
- /* Inform abrt-gui that it is a good idea to rescan the directory */
- kill(getppid(), SIGCHLD);
-
- return FALSE; /* "please remove this event" */
- }
-
- /* New command was started. Continue waiting for input */
-
- /* Transplant cmd's output fd onto old one, so that main loop
- * is none the wiser that fd it waits on has changed
- */
- xmove_fd(evd->run_state->command_out_fd, evd->fd);
- evd->run_state->command_out_fd = evd->fd; /* just to keep it consistent */
- ndelay_on(evd->fd);
-
- /* Revive "Cancel" button */
- g_event_child_pid = evd->run_state->command_pid;
-
- return TRUE; /* "please don't remove this event (yet)" */
-}
-
-static void start_event_run(const char *event_name,
- GtkWidget *page,
- GtkTextView *tv_log,
- GtkLabel *status_label,
- const char *start_msg,
- const char *error_msg,
- const char *success_msg
-) {
- /* Start event asynchronously on the dump dir
- * (synchronous run would freeze GUI until completion)
- */
- struct run_event_state *state = new_run_event_state();
-
- if (prepare_commands(state, g_dump_dir_name, event_name) == 0)
- {
- no_cmds:
- /* No commands needed?! (This is untypical) */
- free_run_event_state(state);
-//TODO: better msg?
- char *msg = xasprintf(_("No processing for event '%s' is
defined"), event_name);
- gtk_label_set_text(status_label, msg);
- free(msg);
- return;
- }
-
- struct dump_dir *dd = dd_opendir(g_dump_dir_name, DD_OPEN_READONLY);
- dd = steal_if_needed(dd);
- int locked = (dd && dd->locked);
- dd_close(dd);
- if (!locked)
- {
- free_run_event_state(state);
- return; /* user refused to steal, or write error, etc... */
- }
-
- set_excluded_envvar();
- GList *env_list = export_event_config(event_name);
-
- if (spawn_next_command(state, g_dump_dir_name, event_name) < 0)
- {
- unexport_event_config(env_list);
- goto no_cmds;
- }
- g_event_child_pid = state->command_pid;
-
- /* At least one command is needed, and we started first one.
- * Hook its output fd to the main loop.
- */
- struct analyze_event_data *evd = xzalloc(sizeof(*evd));
- evd->run_state = state;
- evd->event_name = event_name;
- evd->env_list = env_list;
- evd->page_widget = page;
- evd->status_label = status_label;
- evd->tv_log = tv_log;
- evd->error_msg = error_msg;
- evd->success_msg = success_msg;
- evd->event_log = strbuf_new();
- evd->fd = state->command_out_fd;
- ndelay_on(evd->fd);
- evd->channel = g_io_channel_unix_new(evd->fd);
- /*evd->event_source_id = */ g_io_add_watch(evd->channel,
- G_IO_IN | G_IO_ERR | G_IO_HUP, /* need HUP to detect EOF w/o any data */
- consume_cmd_output,
- evd
- );
-
- gtk_label_set_text(status_label, start_msg);
-
- VERB1 log("running event '%s' on '%s'", event_name,
g_dump_dir_name);
- char *msg = xasprintf("--- Running %s ---\n", event_name);
- append_to_textview(evd->tv_log, msg);
- free(msg);
-
- gtk_widget_show(GTK_WIDGET(g_spinner_event_log));
- gtk_widget_show(g_btn_stop);
- /* Disable (gray out) navigation buttons */
- gtk_widget_set_sensitive(g_btn_close, false);
- gtk_widget_set_sensitive(g_btn_next, false);
-}
-
-
/* Backtrace checkbox handling */
static void add_warning(const char *warning)
@@ -1693,127 +1235,12 @@ static void clear_warnings(void)
gtk_container_foreach(GTK_CONTAINER(g_box_warning_labels), &remove_child_widget,
NULL);
}
-static void check_bt_rating_and_allow_send(void)
-{
- int minimal_rating = 0;
- bool send = true;
-
- /*
- * FIXME: this should be bind to a reporter not to a compoment
- * but so far only oopses don't have rating, so for now we
- * skip the "kernel" manually
- */
- const char *analyzer = get_problem_item_content_or_NULL(g_cd, FILENAME_ANALYZER);
-//FIXME: say "no" to special casing!
- if (analyzer && strcmp(analyzer, "Kerneloops") != 0)
- {
- const char *rating_str = get_problem_item_content_or_NULL(g_cd,
FILENAME_RATING);
-//COMPAT, remove after 2.1 release
- if (!rating_str)
- rating_str = get_problem_item_content_or_NULL(g_cd, "rating");
-
- if (rating_str)
- {
- char *endptr;
- errno = 0;
- long rating = strtol(rating_str, &endptr, 10);
- if (errno != 0 || endptr == rating_str || *endptr != '\0')
- {
- add_warning(_("Reporting disabled because the rating does not
contain a number '%s'."));
- send = false;
- }
-
- GList *li = g_list_selected_reporters;
- while (li != NULL)
- {
- /* need to obey the highest minimal rating of all selected reporters
- * FIXME: check this when selecting the reporter and allow select
- * only usable ones
- */
- event_config_t *cfg = get_event_config((const char *)li->data);
- if (cfg->ec_minimal_rating > minimal_rating)
- {
- minimal_rating = cfg->ec_minimal_rating;
- VERB1 log("%s reporter sets the minimal rating to: %i",
(const char *)li->data, minimal_rating);
- }
-
- li = g_list_next(li);
- };
-
- if (rating == minimal_rating) /* bt is usable, but not complete, so show a
warning */
- {
- add_warning(_("The backtrace is incomplete, please make sure you
provide the steps to reproduce."));
- }
-
- if (rating < minimal_rating)
- {
- //FIXME: see CreporterAssistant: 394 for ideas
- add_warning(_("Reporting disabled because the backtrace is
unusable."));
- send = false;
- }
- }
- }
- gtk_widget_set_sensitive(g_btn_next, send);
-}
-
static void on_bt_approve_toggle(GtkToggleButton *togglebutton, gpointer user_data)
{
gtk_widget_set_sensitive(g_btn_next, gtk_toggle_button_get_active(g_tb_approve_bt));
}
-static void toggle_eb_comment(void)
-{
- /* The page doesn't exist with report-only option */
- if (pages[PAGENO_EDIT_COMMENT].page_widget == NULL)
- return;
-
- bool good =
- gtk_text_buffer_get_char_count(gtk_text_view_get_buffer(g_tv_comment)) >= 10
- || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_cb_no_comment));
-
- /* Allow next page only when the comment has at least 10 chars */
- gtk_widget_set_sensitive(g_btn_next, good);
-
- /* And show the eventbox with label */
- if (good)
- gtk_widget_hide(GTK_WIDGET(g_eb_comment));
- else
- gtk_widget_show(GTK_WIDGET(g_eb_comment));
-}
-
-static void on_comment_changed(GtkTextBuffer *buffer, gpointer user_data)
-{
- toggle_eb_comment();
-}
-
-static void on_no_comment_toggled(GtkToggleButton *togglebutton, gpointer user_data)
-{
- toggle_eb_comment();
-}
-
-
-static void on_show_event_list_cb(GtkWidget *button, gpointer user_data)
-{
- show_events_list_dialog(GTK_WINDOW(g_wnd_assistant));
-}
-
-#if 0
-static void log_ready_state(void)
-{
- char buf[NUM_PAGES+1];
- for (int i = 0; i < NUM_PAGES; i++)
- {
- char ch = '_';
- if (pages[i].page_widget)
- ch = gtk_assistant_get_page_complete(g_assistant, pages[i].page_widget) ?
'+' : '-';
- buf[i] = ch;
- }
- buf[NUM_PAGES] = 0;
- log("Completeness:[%s]", buf);
-}
-#endif
-
-static gboolean highligh_word_in_tabs(const char *search_word, int flags)
+static gboolean highligh_word_in_tabs(const char *search_word, int flags)
{
gboolean found = false;
GtkTextBuffer *buffer;
@@ -1926,45 +1353,460 @@ static void highlight_forbidden(void)
list_free_with_free(forbidden_words);
}
-static gint select_next_page_no(gint current_page_no, gpointer data);
+static void process_step_done_callback_fn(struct elp_thread_args *args)
+{
+ /*
+ if (PAGENO_EVENT_PROGRESS == gtk_notebook_get_current_page(g_assistant))
+ event_list_process_loop_next_step(args);
+ */
+}
+
+static void process_start_callback_fn(struct elp_thread_args *args)
+{
+ GList *need_config = NULL;
+ GHashTable *errors = NULL;
+ for(const GList* e = g_auto_event_list; e; e = g_list_next(e))
+ {
+ event_config_t *ec = get_event_config(e->data);
+ errors = validate_event_config(ec);
+ if (errors != NULL)
+ {
+ g_hash_table_unref(errors);
+ need_config = g_list_prepend(need_config, e->data);
+ }
+ }
-static void on_page_prepare(GtkNotebook *assistant, GtkWidget *page, gpointer user_data)
+ if (need_config)
+ {
+ gdk_threads_enter();
+ show_event_list_opt_error_dialog(need_config);
+ gdk_threads_leave();
+ g_list_free(need_config);
+ }
+
+ return;
+}
+
+static void process_finish_callback_fn(struct elp_thread_args *args)
+{
+ free_event_list_process(elp_thread_args_get_process(args));
+
+ gdk_threads_enter();
+
+ if (!g_expert_mode)
+ gtk_main_quit();
+ else
+ gtk_notebook_set_current_page(g_assistant,
pages[PAGENO_EVENT_SELECTOR].page_no);
+
+ gdk_threads_leave();
+}
+
+static void on_btn_cancel_event(GtkButton *button)
{
- //int page_no = gtk_assistant_get_current_page(g_assistant);
- //log_ready_state();
+ if (g_event_process)
+ elp_thread_loop_kill_command(g_event_process);
+}
+
+static void on_next_btn_cb(GtkWidget *btn, gpointer user_data)
+{
+ const gint current_page_no = gtk_notebook_get_current_page(g_assistant);
+ const gint next_page_no = select_next_page_no(current_page_no);
+
+ if (g_reviewing_data || !elp_thread_is_runnig(g_event_process))
+ gtk_notebook_set_current_page(g_assistant, next_page_no);
+ else
+ elp_thread_loop_next_step(g_event_process);
+}
+
+static void gtk_alert(const char *msg, void *args)
+{
+ gdk_threads_enter();
- /* This suppresses [Last] button: assistant thinks that
- * we never have this page ready unless we are on it
- * -> therefore there is at least one non-ready page
- * -> therefore it won't show [Last]
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE,
+ "%s", msg);
+ char *tagged_msg = tag_url(msg, "\n");
+ gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), tagged_msg);
+ free(tagged_msg);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+
+ gdk_threads_leave();
+}
+
+static char *gtk_ask(const char *msg, void *args)
+{
+ gdk_threads_enter();
+
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_OK_CANCEL,
+ "%s", msg);
+ char *tagged_msg = tag_url(msg, "\n");
+ gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), tagged_msg);
+ free(tagged_msg);
+
+ GtkWidget *vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ GtkWidget *textbox = gtk_entry_new();
+ /* gtk_entry_set_editable(GTK_ENTRY(textbox), TRUE);
+ * is not available in gtk3, so please use the highlevel
+ * g_object_set
*/
- // Doesn't work: if Completeness:[++++++-+++],
- // then [Last] btn will still be shown.
- //gtk_assistant_set_page_complete(g_assistant,
- // pages[PAGENO_REVIEW_DATA].page_widget,
- // pages[PAGENO_REVIEW_DATA].page_widget == page
- //);
+ g_object_set(G_OBJECT(textbox), "editable", TRUE, NULL);
+ gtk_box_pack_start(GTK_BOX(vbox), textbox, TRUE, TRUE, 0);
+ gtk_widget_show(textbox);
- if (pages[PAGENO_SUMMARY].page_widget == page)
+ char *response = NULL;
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
{
- if (!g_expert_mode)
- {
- /* Skip intro screen */
- int n = select_next_page_no(pages[PAGENO_SUMMARY].page_no, NULL);
- VERB2 log("switching to page_no:%d", n);
- gtk_notebook_set_current_page(assistant, n);
- return;
- }
+ const char *text = gtk_entry_get_text(GTK_ENTRY(textbox));
+ response = xstrdup(text);
}
+ else
+ response = xstrdup("");
+
+ gtk_widget_destroy(textbox);
+ gtk_widget_destroy(dialog);
- if (pages[PAGENO_EDIT_ELEMENTS].page_widget == page)
+ gdk_threads_leave();
+
+ return response;
+}
+
+static int gtk_ask_yes_no(const char *msg, void *args)
+{
+ gdk_threads_enter();
+
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "%s", msg);
+ char *tagged_msg = tag_url(msg, "\n");
+ gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), tagged_msg);
+ free(tagged_msg);
+
+ const int ret = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES;
+
+ gtk_widget_destroy(dialog);
+
+ gdk_threads_leave();
+
+ return ret;
+}
+
+static int gtk_ask_password(const char *msg, char **password, void *args)
+{
+ gdk_threads_enter();
+
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_OK_CANCEL,
+ "%s", msg);
+ char *tagged_msg = tag_url(msg, "\n");
+ gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), tagged_msg);
+ free(tagged_msg);
+
+ GtkWidget *vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ GtkWidget *textbox = gtk_entry_new();
+ /* gtk_entry_set_editable(GTK_ENTRY(textbox), TRUE);
+ * is not available in gtk3, so please use the highlevel
+ * g_object_set
+ */
+ g_object_set(G_OBJECT(textbox), "editable", TRUE, NULL);
+ gtk_entry_set_visibility(GTK_ENTRY(textbox), FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), textbox, TRUE, TRUE, 0);
+ gtk_widget_show(textbox);
+
+ char *response = NULL;
+ int ret = 0;
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
{
- clear_warnings();
- check_bt_rating_and_allow_send();
- highlight_forbidden();
- show_warnings();
+ ret = 1;
+ const char *text = gtk_entry_get_text(GTK_ENTRY(textbox));
+ response = xstrdup(text);
}
+ else
+ response = xstrdup("");
+
+ gtk_widget_destroy(textbox);
+ gtk_widget_destroy(dialog);
+
+ if (password)
+ *password = response;
+ else
+ free(response);
+
+ gdk_threads_leave();
+
+ return ret;
+}
+
+static void gtk_command_started(pid_t pid, void *args)
+{
+ gdk_threads_enter();
+
+ VERB3 log("Running event command %d", pid);
+
+ gdk_threads_leave();
+}
+
+static void gtk_command_msg_processed(const char *msg, const char *raw_input, const char
*rsp, void *args)
+{
+ gdk_threads_enter();
+
+ gtk_label_set_text(g_lbl_event_log, msg);
+ append_to_textview(g_tv_event_log, msg);
+ append_to_textview(g_tv_event_log, "\n");
+
+ gdk_threads_leave();
+}
+
+static void gtk_command_finished(int retval, int status, const char *err_msg, void
*args)
+{
+ gdk_threads_enter();
+
+ if (err_msg)
+ {
+ char *msg;
+ msg = xasprintf("(%s)\n", err_msg);
+ append_to_textview(g_tv_event_log, msg);
+ free(msg);
+ }
+
+ gdk_threads_leave();
+}
+
+static enum elp_signal_ret gtk_next_event_selected(struct event_list_process *process)
+{
+ gdk_threads_enter();
+
+ if (!g_expert_mode)
+ { /* In the expert mode an executed list was build from g_event_list */
+ /* therefore we have to care about a selected event only in not expert mode */
+ free(g_event_selected);
+ g_event_selected = xstrdup(elp_get_current_event(process));
+ }
+
+ gdk_threads_leave();
+
+ return ELPSR_CONTINUE;
+}
+
+static enum elp_signal_ret gtk_review_data(struct event_list_process *process)
+{
+ gdk_threads_enter();
+
+ g_reviewing_data = true;
+
+ if (get_problem_item_content_or_NULL(g_cd, FILENAME_COMMENT))
+ gtk_notebook_set_current_page(g_assistant, pages[PAGENO_EDIT_ELEMENTS].page_no);
+ else
+ gtk_notebook_set_current_page(g_assistant, pages[PAGENO_EDIT_COMMENT].page_no);
+
+ gdk_threads_leave();
+
+ return ELPSR_CONTINUE;
+}
+
+static enum elp_signal_ret gtk_run_event(struct event_list_process *process)
+{
+ gdk_threads_enter();
+
+ set_excluded_envvar();
+ const char *event_name = elp_get_current_event(process);
+ log("running event '%s' on '%s'", event_name,
g_dump_dir_name);
+ export_event_config(event_name);
+
+ gtk_label_set_text(g_lbl_event_log, _("Processing..."));
+
+ char *msg = xasprintf("--- Running %s ---\n", event_name);
+ append_to_textview(g_tv_event_log, msg);
+ free(msg);
+
+ gtk_widget_show(GTK_WIDGET(g_spinner_event_log));
+ gtk_widget_show(g_btn_stop);
+ /* Disable (gray out) navigation buttons */
+ gtk_widget_set_sensitive(g_btn_close, false);
+ gtk_widget_set_sensitive(g_btn_next, false);
+
+ gtk_notebook_set_current_page(g_assistant, PAGENO_EVENT_PROGRESS);
+
+ gdk_threads_leave();
+
+ return ELPSR_CONTINUE;
+}
+
+static void event_finished(const char *event_name, const char *message)
+{
+ //unexport_event_config(event_name);
+ VERB1 log("done running event on '%s'", g_dump_dir_name);
+ append_to_textview(g_tv_event_log, "\n");
+ gtk_label_set_text(g_lbl_event_log, message);
+
+ /* Hide spinner and stop btn */
+ gtk_widget_hide(GTK_WIDGET(g_spinner_event_log));
+ gtk_widget_hide(g_btn_stop);
+ /* Enable (un-gray out) navigation buttons */
+ gtk_widget_set_sensitive(g_btn_close, true);
+ gtk_widget_set_sensitive(g_btn_next, true);
+
+ reload_problem_data_from_dump_dir();
+ update_gui_state_from_problem_data();
+
+ /* Inform abrt-gui that it is a good idea to rescan the directory */
+ kill(getppid(), SIGCHLD);
+}
+
+static enum elp_signal_ret gtk_event_done(struct event_list_process *process)
+{
+ gdk_threads_enter();
+
+ const char *const event_name = elp_get_current_event(process);
+ const enum elp_event_run_status status = elp_get_last_event_status(process);
+ switch(status)
+ {
+ case ELP_ERS_SUCCESSFUL:
+ event_finished(event_name,
+ _("Processing finished, please proceed to the next
step."));
+ break;
+
+ case ELP_ERS_FAILED:
+ event_finished(event_name,
+ _("Processing failed. You can try another operation if
available."));
+ break;
+
+ case ELP_ERS_NOT_FOUND:
+ event_finished(event_name,
+ _("We are so sorry, it is not possible to find any
processing for this problem."));
+ break;
+
+ case ELP_ERS_NONE:
+ /* fall throug */
+ default:
+ error_msg_and_die("unexpected event return status '%d'",
status);
+ break;
+ }
+
+ gdk_threads_leave();
+ return ELPSR_CONTINUE;
+}
+
+static enum elp_signal_ret gtk_finished(struct event_list_process *process)
+{
+ gdk_threads_enter();
+
+ gtk_notebook_set_current_page(g_assistant, PAGENO_EVENT_PROGRESS);
+ gtk_label_set_text(g_lbl_event_log, _("Thank you!"));
+
+ gdk_threads_leave();
+
+ return ELPSR_CONTINUE;
+}
+
+static enum elp_signal_ret gtk_configuration_issue(struct event_list_process *process)
+{
+
+ enum elp_signal_ret ret = ELPSR_CONTINUE;
+
+ if (!g_expert_mode)
+ {
+ const struct elp_configuration_issue *last =
elp_get_last_configuration_issue(process);
+
+ char *detail = format_glist_of_strings(last->issues, "* %s",
"\n");
+ event_config_t *ec = get_event_config(last->event_name);
+
+ char *warning = xasprintf("Processing of '%s' has following
problems:\n%s",
+ ec ? ec->screen_name : last->event_name,
detail);
+
+ gdk_threads_enter();
+ if (last->usability == EUS_LOW)
+ add_warning(warning);
+ else if (last->usability == EUS_UNUSABLE)
+ show_error_as_msgbox_mts(warning, false);
+ gdk_threads_leave();
+
+ free(warning);
+ free(detail);
+ ret = last->usability == EUS_UNUSABLE ? ELPSR_FINISH : ELPSR_CONTINUE;
+ }
+
+ return ret;
+}
+
+static void toggle_eb_comment(void)
+{
+ /* The page doesn't exist with report-only option */
+ if (pages[PAGENO_EDIT_COMMENT].page_widget == NULL)
+ return;
+
+ bool good =
+ gtk_text_buffer_get_char_count(gtk_text_view_get_buffer(g_tv_comment)) >= 10
+ || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_cb_no_comment));
+
+ /* Allow next page only when the comment has at least 10 chars */
+ gtk_widget_set_sensitive(g_btn_next, good);
+
+ /* And show the eventbox with label */
+ if (good)
+ gtk_widget_hide(GTK_WIDGET(g_eb_comment));
+ else
+ gtk_widget_show(GTK_WIDGET(g_eb_comment));
+}
+
+static void on_comment_changed(GtkTextBuffer *buffer, gpointer user_data)
+{
+ toggle_eb_comment();
+}
+
+static void on_no_comment_toggled(GtkToggleButton *togglebutton, gpointer user_data)
+{
+ toggle_eb_comment();
+}
+
+
+static void on_show_event_list_cb(GtkWidget *button, gpointer user_data)
+{
+ show_events_list_dialog(GTK_WINDOW(g_wnd_assistant));
+}
+
+#if 0
+static void log_ready_state(void)
+{
+ char buf[NUM_PAGES+1];
+ for (int i = 0; i < NUM_PAGES; i++)
+ {
+ char ch = '_';
+ if (pages[i].page_widget)
+ ch = gtk_assistant_get_page_complete(g_assistant, pages[i].page_widget) ?
'+' : '-';
+ buf[i] = ch;
+ }
+ buf[NUM_PAGES] = 0;
+ log("Completeness:[%s]", buf);
+}
+#endif
+
+static void start_event_list_process(const GList *event_list)
+{
+ if (g_run_obs)
+ free_command_log_run_event_observer(g_run_obs);
+
+ g_run_obs = new_command_log_run_event_observer(g_dump_dir_name, &g_gtk_run_obs);
+
+ struct event_list_process *proc =
+ new_event_list_process(event_list, &g_process_impl, g_run_impl, g_run_obs,
g_dump_dir_name, NULL);
+
+ elp_thread_run(g_event_process, proc);
+}
+
+static void on_page_prepare(GtkNotebook *assistant, GtkWidget *page, gpointer user_data)
+{
/* Save text fields if changed */
save_items_from_notepad();
save_text_from_text_view(g_tv_comment, FILENAME_COMMENT);
@@ -1972,6 +1814,8 @@ static void on_page_prepare(GtkNotebook *assistant, GtkWidget *page,
gpointer us
if (pages[PAGENO_SUMMARY].page_widget == page
|| pages[PAGENO_REVIEW_DATA].page_widget == page
) {
+ elp_thread_loop_next_step(g_event_process);
+
GtkWidget *w = GTK_WIDGET(g_tv_details);
GtkContainer *c = GTK_CONTAINER(gtk_widget_get_parent(w));
if (c)
@@ -1988,139 +1832,67 @@ static void on_page_prepare(GtkNotebook *assistant, GtkWidget
*page, gpointer us
if (pages[PAGENO_REVIEW_DATA].page_widget == page)
{
gtk_widget_set_sensitive(g_btn_next,
gtk_toggle_button_get_active(g_tb_approve_bt));
- update_ls_details_checkboxes();
+ update_ls_details_checkboxes(g_event_selected);
}
}
- if (pages[PAGENO_EDIT_COMMENT].page_widget == page)
+ if (pages[PAGENO_EDIT_COMMENT].page_widget == page )
{
gtk_widget_set_sensitive(g_btn_next, false);
on_comment_changed(gtk_text_view_get_buffer(g_tv_comment), NULL);
}
- //log_ready_state();
- if (pages[PAGENO_EVENT_PROGRESS].page_widget == page)
+ if (pages[PAGENO_EDIT_ELEMENTS].page_widget == page )
{
- VERB2 log("g_event_selected:'%s'", g_event_selected);
- if (g_event_selected
- && g_event_selected[0]
- ) {
- start_event_run(g_event_selected,
- pages[PAGENO_EVENT_PROGRESS].page_widget,
- g_tv_event_log,
- g_lbl_event_log,
- _("Processing..."),
- _("Processing failed. You can try another operation if
available."),
- _("Processing finished, please proceed to the next step.")
- );
-
- if (g_auto_event_list)
- {
- g_auto_event_list = g_auto_event_list->next;
- VERB1 log("next -e EVENT:%s", g_auto_event_list ?
(char*)g_auto_event_list->data : "NULL");
- }
- }
+ clear_warnings();
+ highlight_forbidden();
+ show_warnings();
}
}
-static gint select_next_page_no(gint current_page_no, gpointer data)
+static gint select_next_page_no(gint current_page_no)
{
GtkWidget *page;
- if (g_report_only)
- {
- /* In only-report mode, we only need to wrap back at the end */
- page = gtk_notebook_get_nth_page(g_assistant, current_page_no);
- if (page == pages[PAGENO_EVENT_DONE].page_widget)
- current_page_no = 0;
- else
- current_page_no++;
- VERB1 log("%s: selected page #%d", __func__, current_page_no);
- return current_page_no;
- }
-
- again:
VERB1 log("%s: current_page_no:%d", __func__, current_page_no);
- current_page_no++;
page = gtk_notebook_get_nth_page(g_assistant, current_page_no);
if (pages[PAGENO_EVENT_SELECTOR].page_widget == page)
{
- if (!g_expert_mode)
- {
- VERB1 log("selected -e EVENT:%s on page: %d",
(char*)g_auto_event_list->data, current_page_no);
- free(g_event_selected);
- g_event_selected = xstrdup((char*)g_auto_event_list->data);
- /*
- * We don't remove the list element, because GTK calls
select_next_page_no()
- * spuriously (for example, it calls it twice for first page).
- */
-
- if (check_event_config(g_event_selected) != 0)
- {
- goto again;
- }
+ if(!g_expert_mode)
+ error_msg_and_die("Event selector is enabled only in export
mode.");
- current_page_no = pages[PAGENO_EVENT_SELECTOR].page_no + 1;
- goto event_was_selected;
+ struct dump_dir *dd = dd_opendir(g_dump_dir_name, DD_OPEN_READONLY);
+ dd = steal_if_needed(dd);
+ const int locked = dd && dd->locked;
+ dd_close(dd);
- }
- }
+ if (!locked)
+ return current_page_no;
- if (pages[PAGENO_EVENT_SELECTOR + 1].page_widget == page)
- {
- event_was_selected:
- if (!g_event_selected)
- {
- /* Go back to selectors */
- current_page_no = pages[PAGENO_EVENT_SELECTOR].page_no - 1;
- goto again;
- }
+ g_list_free(g_auto_event_list);
+ g_auto_event_list = NULL;
+ g_auto_event_list = g_list_prepend(g_auto_event_list, g_event_selected);
- event_config_t *cfg = get_event_config(g_event_selected);
- if (cfg && cfg->ec_skip_review)
- {
- current_page_no = pages[PAGENO_EVENT_PROGRESS].page_no - 1;
- goto again;
- }
- if (!get_problem_item_content_or_NULL(g_cd, FILENAME_BACKTRACE))
- goto again; /* no backtrace, skip this page */
+ start_event_list_process(g_auto_event_list);
}
-#if 0
- if (pages[PAGENO_EDIT_COMMENT].page_widget == page)
- {
- if (get_problem_item_content_or_NULL(g_cd, FILENAME_COMMENT))
- goto again; /* no comment, skip this page */
- }
-#endif
+ ++current_page_no;
+
+ if (pages[PAGENO_REVIEW_DATA].page_widget == page)
+ g_reviewing_data = false;
if (pages[PAGENO_EVENT_DONE].page_widget == page)
- {
- if (g_auto_event_list)
- {
- /* Go back to selectors */
- current_page_no = pages[PAGENO_SUMMARY].page_no;
- }
- goto again;
- }
+ current_page_no = pages[PAGENO_EVENT_SELECTOR].page_no;
if (pages[PAGENO_NOT_SHOWN].page_widget == page)
- {
- if (!g_expert_mode)
- exit(0);
- /* No! this would SEGV (infinitely recurse into select_next_page_no) */
- /*gtk_assistant_commit(g_assistant);*/
- current_page_no = pages[PAGENO_EVENT_SELECTOR].page_no - 1;
- goto again;
- }
+ current_page_no = pages[PAGENO_EVENT_SELECTOR].page_no;
VERB1 log("%s: selected page #%d", __func__, current_page_no);
return current_page_no;
}
-
static void highlight_widget(GtkWidget *widget, gpointer *user_data)
{
gtk_drag_highlight(widget);
@@ -2296,7 +2068,7 @@ static void on_btn_add_file(GtkButton *button)
reload_problem_data_from_dump_dir();
update_gui_state_from_problem_data();
/* Set flags for the new item */
- update_ls_details_checkboxes();
+ update_ls_details_checkboxes(g_event_selected);
}
}
free(new_name);
@@ -2381,18 +2153,6 @@ static gint on_key_press_event_in_item_list(GtkTreeView *treeview,
GdkEventKey *
/* wizard.glade file as a string WIZARD_GLADE_CONTENTS: */
#include "wizard_glade.c"
-static void on_next_btn_cb(GtkWidget *btn, gpointer user_data)
-{
- gint current_page_no = gtk_notebook_get_current_page(g_assistant);
- gint next_page_no = select_next_page_no(current_page_no, NULL);
-
- /* if pageno is not change 'switch-page' signal is not emitted */
- if (current_page_no == next_page_no)
- on_page_prepare(g_assistant, gtk_notebook_get_nth_page(g_assistant,
next_page_no), NULL);
- else
- gtk_notebook_set_current_page(g_assistant, next_page_no);
-}
-
static void add_pages(void)
{
GError *error = NULL;
@@ -2424,23 +2184,11 @@ static void add_pages(void)
dd_close(dd);
int i;
- int page_no = 0;
for (i = 0; page_names[i] != NULL; i++)
{
- char *delim = strrchr(page_names[i], '_');
- if (!not_reportable && delim)
- {
- if (g_report_only && (strncmp(delim + 1, "report",
strlen("report"))) != 0)
- {
- pages[i].page_widget = NULL;
- pages[i].page_no = -1;
- continue;
- }
- }
-
GtkWidget *page = GTK_WIDGET(gtk_builder_get_object(g_builder, page_names[i]));
pages[i].page_widget = page;
- pages[i].page_no = page_no++;
+ pages[i].page_no = i;
gtk_notebook_append_page(g_assistant, page, gtk_label_new(pages[i].title));
VERB1 log("added page: %s", page_names[i]);
}
@@ -2568,10 +2316,53 @@ static void init_pages(void)
init_page(&pages[7], PAGE_NOT_SHOWN , ""
);
}
+static gboolean gtk_g_idle_prepare(GSource *source_data, gint *timeout)
+{
+ return TRUE;
+}
+
+static gboolean gtk_g_idle_check(GSource *source)
+{
+ return TRUE;
+}
+
+static gboolean gtk_g_idle_dispatch(GSource *source, GSourceFunc callback, gpointer
user_data)
+{
+ /* Start processing of list of events */
+ gdk_threads_enter();
+
+ struct dump_dir *dd = dd_opendir(g_dump_dir_name, DD_OPEN_READONLY);
+ dd = steal_if_needed(dd);
+ const int locked = dd && dd->locked;
+ dd_close(dd);
+
+ gdk_threads_leave();
+
+ if (!locked)
+ {
+ gtk_main_quit();
+ return FALSE;
+ }
+
+ start_event_list_process(g_auto_event_list);
+ elp_thread_loop_next_step(g_event_process);
+ return FALSE;
+}
+
+struct gtk_assistant_source
+{
+ GSource source;
+};
+
void create_assistant(void)
{
+
g_expert_mode = !g_auto_event_list;
+ /* Run event callback for gtk are wrapped with logging implementation */
+ /* TODO : missing clean up */
+ g_run_impl = &g_gtk_run_impl;
+
g_monospace_font = pango_font_description_from_string("monospace");
g_builder = gtk_builder_new();
@@ -2599,6 +2390,7 @@ void create_assistant(void)
gtk_widget_hide(g_btn_stop);
g_wnd_assistant = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
+
gtk_container_add(GTK_CONTAINER(g_wnd_assistant), GTK_WIDGET(g_box_assistant));
gtk_window_set_default_size(g_wnd_assistant, DEFAULT_WIDTH, DEFAULT_HEIGHT);
@@ -2627,6 +2419,26 @@ void create_assistant(void)
g_signal_connect(g_search_entry_bt, "changed", G_CALLBACK(search_timeout),
NULL);
- /* switch to right starting page */
- on_page_prepare(g_assistant, gtk_notebook_get_nth_page(g_assistant, 0), NULL);
+ elp_thread_args_set_on_step_done(g_event_process, process_step_done_callback_fn);
+ elp_thread_args_set_on_start(g_event_process, process_start_callback_fn);
+ elp_thread_args_set_on_finish(g_event_process, process_finish_callback_fn);
+
+ g_gui_thread_id = pthread_self();
+
+ if (!g_expert_mode)
+ {
+ static GSourceFuncs idle_funcs = {
+ .prepare=gtk_g_idle_prepare,
+ .check=gtk_g_idle_check,
+ .dispatch=gtk_g_idle_dispatch,
+ .finalize=NULL,
+ .closure_callback=NULL,
+ .closure_marshal=NULL
+ };
+
+ struct gtk_assistant_source *const gtk_assistant_source =
+ (struct gtk_assistant_source*)g_source_new(&idle_funcs,
sizeof(*gtk_assistant_source));
+
+ g_source_attach((GSource*)gtk_assistant_source,
g_main_context_get_thread_default());
+ }
}
diff --git a/src/gui-wizard-gtk/wizard.glade b/src/gui-wizard-gtk/wizard.glade
index 41924eb..7029677 100644
--- a/src/gui-wizard-gtk/wizard.glade
+++ b/src/gui-wizard-gtk/wizard.glade
@@ -178,7 +178,7 @@
<object class="GtkWindow" id="window2">
<property name="can_focus">False</property>
<child>
- <object class="GtkVBox" id="page_2_report">
+ <object class="GtkVBox" id="page_2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
@@ -485,7 +485,7 @@
<object class="GtkWindow" id="window4">
<property name="can_focus">False</property>
<child>
- <object class="GtkVBox" id="page_4_report">
+ <object class="GtkVBox" id="page_4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
@@ -598,7 +598,7 @@
<object class="GtkWindow" id="window5">
<property name="can_focus">False</property>
<child>
- <object class="GtkVBox" id="page_5_report">
+ <object class="GtkVBox" id="page_5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
@@ -683,7 +683,7 @@
<object class="GtkWindow" id="window6">
<property name="can_focus">False</property>
<child>
- <object class="GtkVBox" id="page_6_report">
+ <object class="GtkVBox" id="page_6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
@@ -727,7 +727,7 @@
<object class="GtkWindow" id="window7">
<property name="can_focus">False</property>
<child>
- <object class="GtkVBox" id="page_7_report">
+ <object class="GtkVBox" id="page_7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
diff --git a/src/gui-wizard-gtk/wizard.h b/src/gui-wizard-gtk/wizard.h
index a818828..64e6a4b 100644
--- a/src/gui-wizard-gtk/wizard.h
+++ b/src/gui-wizard-gtk/wizard.h
@@ -25,6 +25,8 @@ void create_assistant(void);
void update_gui_state_from_problem_data(void);
void show_error_as_msgbox(const char *msg);
+struct elp_thread_args;
+extern struct elp_thread_args *g_event_process;
extern char *g_glade_file;
extern char *g_dump_dir_name;
--
1.7.10.2