From 4b77796724895222b16a03518e50aa82973f6229 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sat, 21 Jan 2006 15:39:03 +0000 Subject: [PATCH] Exe error dialog. Still needs some work, but it's good enough for testing by the wider community. Currently only e_app started exe's get this. SVN revision: 19948 --- src/bin/Makefile.am | 1 + src/bin/e_apps.c | 34 ++++-- src/bin/e_apps.h | 10 ++ src/bin/e_apps_error.c | 259 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 296 insertions(+), 8 deletions(-) create mode 100644 src/bin/e_apps_error.c diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 5da65a267..050f077fa 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -208,6 +208,7 @@ e_widget_table.c \ e_widget_entry.c \ e_widget_image.c \ e_config_dialog.c \ +e_apps_error.c \ e_int_config_focus.c \ e_icon_grid.c \ e_icon_canvas.c \ diff --git a/src/bin/e_apps.c b/src/bin/e_apps.c index d59a2adb1..b374e8600 100644 --- a/src/bin/e_apps.c +++ b/src/bin/e_apps.c @@ -13,6 +13,9 @@ * - clean up the add app functions. To much similar code. */ +extern void _e_app_error_dialog(E_Container *con, E_App_Autopsy *app); + + /* local subsystem functions */ typedef struct _E_App_Change_Info E_App_Change_Info; typedef struct _E_App_Callback E_App_Callback; @@ -417,7 +420,8 @@ e_app_exec(E_App *a, int launch_id) * the eapp file */ inst = E_NEW(E_App_Instance, 1); if (!inst) return 0; - exe = ecore_exe_run(a->exe, inst); + /* We want the stdout and stderr as lines for the error dialog if it exits abnormally. */ + exe = ecore_exe_pipe_run(a->exe, ECORE_EXE_PIPE_AUTO| ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR | ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR_LINE_BUFFERED, inst); if (!exe) { free(inst); @@ -429,6 +433,8 @@ e_app_exec(E_App *a, int launch_id) a->exe); return 0; } + /* 20 lines at start and end, 20x100 limit on bytes at each end. */ + ecore_exe_auto_limits_set(exe, 2000, 2000, 20, 20); ecore_exe_tag_set(exe, "E/app"); inst->app = a; inst->exe = exe; @@ -1854,13 +1860,25 @@ _e_apps_cb_exit(void *data, int type, void *event) a = ai->app; if (!a) return 1; - /* FIXME: maybe we could capture stdout/stderr and display it here? */ - if (ev->exit_code == 127) /* /bin/sh uses this if cmd not found */ - e_error_dialog_show(_("Run Error"), - _("Enlightenment was unable to run the program:\n" - "\n" - "%s\n"), - a->exe); + if ( (ev->exited) && (ev->exit_code == 127) ) /* /bin/sh uses this if cmd not found */ + { + e_error_dialog_show(_("Run Error"), + _("Enlightenment was unable to run the program:\n" + "\n" + "%s\n"), + a->exe); + } + else if ( ! ((ev->exited) && (ev->exit_code == EXIT_SUCCESS)) ) /* Let's hope that everyhing returns this properly. */ + { /* Show the error dialog with details from the exe. */ + E_App_Autopsy *aut; + + aut = E_NEW(E_App_Autopsy, 1); + aut->app = a; + aut->del = *ev; + aut->read = ecore_exe_event_data_get(ai->exe, ECORE_FD_READ); + aut->error = ecore_exe_event_data_get(ai->exe, ECORE_FD_ERROR); + _e_app_error_dialog(NULL, aut); + } if (ai->expire_timer) ecore_timer_del(ai->expire_timer); free(ai); a->instances = evas_list_remove(a->instances, ai); diff --git a/src/bin/e_apps.h b/src/bin/e_apps.h index afb562e97..c84718ca3 100644 --- a/src/bin/e_apps.h +++ b/src/bin/e_apps.h @@ -17,6 +17,7 @@ typedef enum _E_App_Change typedef struct _E_App E_App; typedef struct _E_App_Instance E_App_Instance; +typedef struct _E_App_Autopsy E_App_Autopsy; #else #ifndef E_APPS_H @@ -76,6 +77,15 @@ struct _E_App_Instance Ecore_Timer *expire_timer; }; +struct _E_App_Autopsy +{ + E_App *app; + + Ecore_Exe_Event_Del del; + E_Config_Dialog *error_dialog; + Ecore_Exe_Event_Data *error, *read; +}; + EAPI int e_app_init (void); EAPI int e_app_shutdown (void); diff --git a/src/bin/e_apps_error.c b/src/bin/e_apps_error.c new file mode 100644 index 000000000..9fd818fe5 --- /dev/null +++ b/src/bin/e_apps_error.c @@ -0,0 +1,259 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ +#include "e.h" + + +struct _E_Config_Dialog_Data +{ + char *label; + char *exit; + char *signal; +}; + + +/* Protos */ +static void * _e_app_error_dialog_create_data(E_Config_Dialog *cfd); +static void _e_app_error_dialog_free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +static Evas_Object *_e_app_error_dialog_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata); +static Evas_Object *_e_app_error_dialog_advanced_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata); + +void +_e_app_error_dialog(E_Container *con, E_App_Autopsy *app) +{ + E_Config_Dialog *cfd; + E_Config_Dialog_View v; + + /* Dialog Methods */ + v.create_cfdata = _e_app_error_dialog_create_data; + v.free_cfdata = _e_app_error_dialog_free_data; + v.basic.apply_cfdata = NULL; + v.basic.create_widgets = _e_app_error_dialog_basic_create_widgets; + v.advanced.apply_cfdata = NULL; + v.advanced.create_widgets = _e_app_error_dialog_advanced_create_widgets; + + /* Create The Dialog */ + cfd = e_config_dialog_new(con, _("Run error"), NULL, 0, &v, app); + app->error_dialog = cfd; +} + +static void +_e_app_error_dialog_fill_data(E_App_Autopsy *app, E_Config_Dialog_Data *cfdata) +{ + int length; + + length = strlen(app->app->name); + if (!cfdata->label) + { + cfdata->label = malloc((length + 20) * sizeof(char)); + if (cfdata->label) + sprintf(cfdata->label, "%s may have crashed.", app->app->name); + } + + length = strlen(app->app->exe); + if ((app->del.exited) && (!cfdata->exit)) + { + cfdata->exit = malloc((length + 64) * sizeof(char)); + if (cfdata->exit) + sprintf(cfdata->exit, "An exit code of %i was return from %s", app->del.exit_code, app->app->exe); + } + if ((app->del.signalled) && (!cfdata->signal)) + { + cfdata->signal = malloc((length + 64) * sizeof(char)); + if (cfdata->signal) + sprintf(cfdata->signal, "%s was interupted by signal %i", app->app->exe, app->del.exit_signal); /* FIXME: add a description of the signal. */ +/* FIXME: Add sigchld_info stuff + * app->del.data + * siginfo_t + * { + * int si_signo; Signal number + * int si_errno; An errno value + * int si_code; Signal code + * pid_t si_pid; Sending process ID + * uid_t si_uid; Real user ID of sending process + * int si_status; Exit value or signal + * clock_t si_utime; User time consumed + * clock_t si_stime; System time consumed + * sigval_t si_value; Signal value + * int si_int; POSIX.1b signal + * void * si_ptr; POSIX.1b signal + * void * si_addr; Memory location which caused fault + * int si_band; Band event + * int si_fd; File descriptor + * } + */ + } +} + +static void * +_e_app_error_dialog_create_data(E_Config_Dialog *cfd) +{ + E_Config_Dialog_Data *cfdata; + E_App_Autopsy *app; + + app = cfd->data; + cfdata = E_NEW(E_Config_Dialog_Data, 1); + _e_app_error_dialog_fill_data(app, cfdata); + return cfdata; +} + +static void +_e_app_error_dialog_free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + E_App_Autopsy *app; + + app = cfd->data; + + if(app) + { + app->error_dialog = NULL; + if (app->error) + ecore_exe_event_data_free(app->error); + if (app->read) + ecore_exe_event_data_free(app->read); + free(app); + } + if (cfdata->label) + free(cfdata->signal); + if (cfdata->label) + free(cfdata->exit); + if (cfdata->label) + free(cfdata->label); + + free(cfdata); +} + +static void +_e_app_error_dialog_resize(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Coord mw, mh, vw, vh, w, h; + + e_scrollframe_child_viewport_size_get(obj, &vw, &vh); + e_widget_min_size_get(data, &mw, &mh); + evas_object_geometry_get(data, NULL, NULL, &w, &h); + if (vw >= mw) + { + if (w != vw) evas_object_resize(data, vw, h); + } +} + +static Evas_Object * +_e_app_error_dialog_scrolltext_create(Evas *evas, char *title, Ecore_Exe_Event_Data_Line *lines) +{ + int i; + Evas_Object *obj, *os; + + os = e_widget_framelist_add(evas, _(title), 0); + + obj = e_widget_ilist_add(evas, 0, 0, NULL); + + for (i = 0; lines[i].line != NULL; i++) + e_widget_ilist_append(obj, NULL, lines[i].line, NULL, NULL, NULL); + e_widget_min_size_set(obj, 100, 100); + + e_widget_framelist_object_append(os, obj); + + return os; +} + +static Evas_Object * +_e_app_error_dialog_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + int error_length = 0; + Evas_Object *o, *o2, *of, *ob, *os; + E_App_Autopsy *app; + + app = cfd->data; + _e_app_error_dialog_fill_data(app, cfdata); + + o = e_widget_list_add(evas, 0, 0); + + ob = e_widget_label_add(evas, cfdata->label); + e_widget_list_object_append(o, ob, 1, 1, 0.5); + + if (app->error) + error_length = app->error->size; + if (error_length) + { + os = _e_app_error_dialog_scrolltext_create(evas, "Error", app->error->lines); + e_widget_list_object_append(o, os, 1, 1, 0.5); + } + else + { + ob = e_widget_label_add(evas, _("There was no error message.")); + e_widget_list_object_append(o, ob, 1, 1, 0.5); + } + + return o; +} + +static Evas_Object * +_e_app_error_dialog_advanced_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + int read_length = 0; + int error_length = 0; + Evas_Object *o, *of, *ob, *ot, *os; + E_App_Autopsy *app; + + app = cfd->data; + _e_app_error_dialog_fill_data(app, cfdata); + + o = e_widget_list_add(evas, 0, 0); + ot = e_widget_table_add(evas, 0); + + ob = e_widget_label_add(evas, cfdata->label); + e_widget_list_object_append(o, ob, 1, 1, 0.5); + + if (cfdata->exit) + { + of = e_widget_framelist_add(evas, _("Exit code"), 0); + ob = e_widget_label_add(evas, _(cfdata->exit)); + e_widget_framelist_object_append(of, ob); + e_widget_list_object_append(o, of, 1, 1, 0.5); + } + + if (cfdata->signal) + { + of = e_widget_framelist_add(evas, _("Signal"), 0); + ob = e_widget_label_add(evas, _(cfdata->signal)); + e_widget_framelist_object_append(of, ob); + e_widget_list_object_append(o, of, 1, 1, 0.5); + } + + if (app->read) + read_length = app->read->size; + + if (read_length) + { + of = _e_app_error_dialog_scrolltext_create(evas, "Output", app->read->lines); +/* FIXME: Add stdout "start". */ +/* FIXME: Add stdout "end". */ + } + else + { + of = e_widget_framelist_add(evas, _("Output"), 0); + ob = e_widget_label_add(evas, _("There was no output.")); + e_widget_framelist_object_append(of, ob); + } + e_widget_table_object_append(ot, of, 0, 0, 1, 1, 1, 1, 1, 1); + + if (app->error) + error_length = app->error->size; + if (error_length) + { + of = _e_app_error_dialog_scrolltext_create(evas, "Error", app->error->lines); +/* FIXME: Add stderr "start". */ +/* FIXME: Add stderr "end". */ + } + else + { + of = e_widget_framelist_add(evas, _("Error"), 0); + ob = e_widget_label_add(evas, _("There was no error message.")); + e_widget_framelist_object_append(of, ob); + } + e_widget_table_object_append(ot, of, 1, 0, 1, 1, 1, 1, 1, 1); + + e_widget_list_object_append(o, ot, 1, 1, 0.5); + + return o; +}