#include "private.h" #include #include #include "main.h" #include "win.h" #include "termio.h" #include "termcmd.h" #include "config.h" #include "controls.h" #include "media.h" #include "utils.h" #include "ipc.h" typedef struct _Win Win; typedef struct _Term Term; struct _Win { Evas_Object *win; Evas_Object *conform; Evas_Object *backbg; // Evas_Object *table; // replace with whatever layout widget as needed Eina_List *terms; Config *config; Eina_Bool focused; }; struct _Term { Win *wn; Evas_Object *bg; Evas_Object *term; Evas_Object *media; Evas_Object *popmedia; Evas_Object *cmdbox; Ecore_Timer *cmdbox_focus_timer; Eina_List *popmedia_queue; Eina_Bool focused; Eina_Bool cmdbox_up; Eina_Bool hold; }; int _log_domain = -1; static Eina_List *wins = NULL; static Ecore_Timer *flush_timer = NULL; static void _popmedia_queue_process(Term *term); static void main_win_free(Win *wn); static void main_term_free(Term *term); static Term * main_win_focused_term_get(Win *wn) { Term *term; Eina_List *l; EINA_LIST_FOREACH(wn->terms, l, term) { if (term->focused) return term; } return NULL; } static void _cb_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { Win *wn = data; wins = eina_list_remove(wins, wn); // already obj here is deleted - dont do it again wn->win = NULL; main_win_free(wn); } static void _cb_focus_in(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { Win *wn = data; Term *term; if (!wn->focused) elm_win_urgent_set(wn->win, EINA_FALSE); wn->focused = EINA_TRUE; term = main_win_focused_term_get(wn); if (!term) return; edje_object_signal_emit(term->bg, "focus,in", "terminology"); if (term->cmdbox_up) elm_object_focus_set(term->cmdbox, EINA_TRUE); else elm_object_focus_set(term->term, EINA_TRUE); } static void _cb_focus_out(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { Win *wn = data; Term *term; wn->focused = EINA_FALSE; term = main_win_focused_term_get(wn); if (!term) return; edje_object_signal_emit(term->bg, "focus,out", "terminology"); if (term->cmdbox_up) elm_object_focus_set(term->cmdbox, EINA_FALSE); else elm_object_focus_set(term->term, EINA_FALSE); elm_cache_all_flush(); } static void _cb_size_hint(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event __UNUSED__) { Term *term = data; Evas_Coord mw, mh, rw, rh, w = 0, h = 0; evas_object_size_hint_min_get(obj, &mw, &mh); evas_object_size_hint_request_get(obj, &rw, &rh); edje_object_size_min_calc(term->bg, &w, &h); evas_object_size_hint_min_set(term->bg, w, h); // XXX: this is wrong for a container with conform or multiple // terminals inside a single window elm_win_size_base_set(term->wn->win, w - mw, h - mh); elm_win_size_step_set(term->wn->win, mw, mh); if (!evas_object_data_get(obj, "sizedone")) { evas_object_resize(term->wn->win, w - mw + rw, h - mh + rh); evas_object_data_set(obj, "sizedone", obj); } } static void _cb_options(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { Term *term = data; controls_toggle(term->wn->win, term->bg, term->term); } static Eina_Bool _cb_flush(void *data __UNUSED__) { flush_timer = NULL; elm_cache_all_flush(); return EINA_FALSE; } static void _cb_change(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { if (!flush_timer) flush_timer = ecore_timer_add(0.25, _cb_flush, NULL); else ecore_timer_delay(flush_timer, 0.25); } static void _cb_exited(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { Term *term = data; if (!term->hold) { Win *wn = term->wn; wn->terms = eina_list_remove(wn->terms, term); main_term_free(term); if (!wn->terms) evas_object_del(wn->win); } } static void _cb_bell(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { Term *term = data; Config *config = termio_config_get(term->term); if (!config->disable_visual_bell) edje_object_signal_emit(term->bg, "bell", "terminology"); if (!config) return; if (config->urg_bell) { if (!term->wn->focused) elm_win_urgent_set(term->wn->win, EINA_TRUE); } } static void _cb_popmedia_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { Term *term = data; edje_object_signal_emit(term->bg, "popmedia,off", "terminology"); } static void _cb_popmedia_done(void *data, Evas_Object *obj __UNUSED__, const char *sig __UNUSED__, const char *src __UNUSED__) { Term *term = data; if (term->popmedia) { evas_object_event_callback_del(term->popmedia, EVAS_CALLBACK_DEL, _cb_popmedia_del); evas_object_del(term->popmedia); term->popmedia = NULL; termio_mouseover_suspend_pushpop(term->term, -1); _popmedia_queue_process(term); } } static void _cb_media_loop(void *data, Evas_Object *obj __UNUSED__, void *info __UNUSED__) { Term *term = data; if (term->popmedia_queue) { if (term->popmedia) media_play_set(term->popmedia, EINA_FALSE); edje_object_signal_emit(term->bg, "popmedia,off", "terminology"); } } static void _popmedia_show(Term *term, const char *src) { Evas_Object *o; Config *config = termio_config_get(term->term); int type = 0; if (!config) return; if (term->popmedia) { const char *s; EINA_LIST_FREE(term->popmedia_queue, s) { eina_stringshare_del(s); } term->popmedia_queue = eina_list_append(term->popmedia_queue, eina_stringshare_add(src)); edje_object_signal_emit(term->bg, "popmedia,off", "terminology"); return; } termio_mouseover_suspend_pushpop(term->term, 1); term->popmedia = o = media_add(term->wn->win, src, config, MEDIA_POP, &type); evas_object_smart_callback_add(o, "loop", _cb_media_loop, term); evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _cb_popmedia_del, term); edje_object_part_swallow(term->bg, "terminology.popmedia", o); evas_object_show(o); if (type == TYPE_IMG) edje_object_signal_emit(term->bg, "popmedia,image", "terminology"); else if (type == TYPE_SCALE) edje_object_signal_emit(term->bg, "popmedia,scale", "terminology"); else if (type == TYPE_EDJE) edje_object_signal_emit(term->bg, "popmedia,edje", "terminology"); else if (type == TYPE_MOV) edje_object_signal_emit(term->bg, "popmedia,movie", "terminology"); } static void _popmedia_queue_process(Term *term) { const char *src; if (!term->popmedia_queue) return; src = term->popmedia_queue->data; term->popmedia_queue = eina_list_remove_list(term->popmedia_queue, term->popmedia_queue); if (!src) return; _popmedia_show(term, src); eina_stringshare_del(src); } static void _popmedia_queue_add(Term *term, const char *src) { term->popmedia_queue = eina_list_append(term->popmedia_queue, eina_stringshare_add(src)); if (!term->popmedia) _popmedia_queue_process(term); } static void _cb_popup(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { Term *term = data; const char *src = termio_link_get(term->term); if (!src) return; _popmedia_show(term, src); } static void _cb_command(void *data, Evas_Object *obj __UNUSED__, void *event) { Term *term = data; const char *cmd = event; if (cmd[0] == 'p') // popmedia { if (cmd[1] == 'n') // now { _popmedia_show(term, cmd + 2); } else if (cmd[1] == 'q') // queue it to display after current one { _popmedia_queue_add(term, cmd + 2); } } else if (cmd[0] == 'b') // set background { if (cmd[1] == 't') // temporary { Config *config = termio_config_get(term->term); if (config) { config->temporary = EINA_TRUE; eina_stringshare_replace(&(config->background), cmd + 2); main_media_update(config); } } else if (cmd[1] == 'p') // permanent { Config *config = termio_config_get(term->term); if (config) { config->temporary = EINA_FALSE; eina_stringshare_replace(&(config->background), cmd + 2); main_media_update(config); } } } else if (cmd[0] == 'a') // set alpha { if (cmd[1] == 't') // temporary { Config *config = termio_config_get(term->term); if (config) { config->temporary = EINA_TRUE; if ((cmd[2] == '1') || (!strcasecmp(cmd + 2, "on")) || (!strcasecmp(cmd + 2, "true")) || (!strcasecmp(cmd + 2, "yes"))) config->translucent = EINA_FALSE; else config->translucent = EINA_FALSE; main_trans_update(config); } } else if (cmd[1] == 'p') // permanent { Config *config = termio_config_get(term->term); if (config) { config->temporary = EINA_FALSE; if ((cmd[2] == '1') || (!strcasecmp(cmd + 2, "on")) || (!strcasecmp(cmd + 2, "true")) || (!strcasecmp(cmd + 2, "yes"))) config->translucent = EINA_FALSE; else config->translucent = EINA_FALSE; main_trans_update(config); } } } } static Eina_Bool _cb_cmd_focus(void *data) { Term *term = data; term->cmdbox_focus_timer = NULL; elm_object_focus_set(term->cmdbox, EINA_TRUE); return EINA_FALSE; } static void _cb_cmdbox(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { Term *term = data; term->cmdbox_up = EINA_TRUE; elm_object_focus_set(term->term, EINA_FALSE); edje_object_signal_emit(term->bg, "cmdbox,show", "terminology"); elm_entry_entry_set(term->cmdbox, ""); evas_object_show(term->cmdbox); if (term->cmdbox_focus_timer) ecore_timer_del(term->cmdbox_focus_timer); term->cmdbox_focus_timer = ecore_timer_add(0.1, _cb_cmd_focus, term); } static void _cb_cmd_activated(void *data, Evas_Object *obj, void *event __UNUSED__) { Term *term = data; char *cmd; elm_object_focus_set(term->cmdbox, EINA_FALSE); edje_object_signal_emit(term->bg, "cmdbox,hide", "terminology"); elm_object_focus_set(term->term, EINA_TRUE); cmd = (char *)elm_entry_entry_get(term->cmdbox); if (cmd) { cmd = elm_entry_markup_to_utf8(cmd); if (cmd) { termcmd_do(term->term, term->wn->win, term->bg, cmd); free(cmd); } } if (term->cmdbox_focus_timer) { ecore_timer_del(term->cmdbox_focus_timer); term->cmdbox_focus_timer = NULL; } term->cmdbox_up = EINA_FALSE; } static void _cb_cmd_aborted(void *data, Evas_Object *obj, void *event __UNUSED__) { Term *term = data; elm_object_focus_set(term->cmdbox, EINA_FALSE); edje_object_signal_emit(term->bg, "cmdbox,hide", "terminology"); elm_object_focus_set(term->term, EINA_TRUE); if (term->cmdbox_focus_timer) { ecore_timer_del(term->cmdbox_focus_timer); term->cmdbox_focus_timer = NULL; } term->cmdbox_up = EINA_FALSE; } static void _cb_cmd_changed(void *data, Evas_Object *obj, void *event __UNUSED__) { Term *term = data; char *cmd; cmd = (char *)elm_entry_entry_get(term->cmdbox); if (cmd) { cmd = elm_entry_markup_to_utf8(cmd); if (cmd) { termcmd_watch(term->term, term->wn->win, term->bg, cmd); free(cmd); } } } static void _cb_cmd_hints_changed(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) { Term *term = data; evas_object_show(term->cmdbox); edje_object_part_swallow(term->bg, "terminology.cmdbox", term->cmdbox); } void main_trans_update(const Config *config) { Win *wn; Term *term; Eina_List *l, *ll; EINA_LIST_FOREACH(wins, l, wn) { if (config->translucent) { EINA_LIST_FOREACH(wn->terms, ll, term) { edje_object_signal_emit(term->bg, "translucent,on", "terminology"); } elm_win_alpha_set(wn->win, EINA_TRUE); evas_object_hide(wn->backbg); } else { EINA_LIST_FOREACH(wn->terms, ll, term) { edje_object_signal_emit(term->bg, "translucent,off", "terminology"); } elm_win_alpha_set(wn->win, EINA_FALSE); evas_object_show(wn->backbg); } } } static void _cb_media_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { Term *term = data; Config *config = termio_config_get(term->term); term->media = NULL; edje_object_signal_emit(term->bg, "media,off", "terminology"); if (!config) return; if (config->temporary) eina_stringshare_replace(&(config->background), NULL); } void main_media_update(const Config *config) { Win *wn; Term *term; Eina_List *l, *ll; EINA_LIST_FOREACH(wins, l, wn) { EINA_LIST_FOREACH(wn->terms, ll, term) { if ((config->background) && (config->background[0])) { Evas_Object *o; int type = 0; if (term->media) { evas_object_event_callback_del(term->media, EVAS_CALLBACK_DEL, _cb_media_del); evas_object_del(term->media); } term->media = o = media_add(term->wn->win, config->background, config, MEDIA_BG, &type); evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _cb_media_del, term); edje_object_part_swallow(term->bg, "terminology.background", o); evas_object_show(o); if (type == TYPE_IMG) edje_object_signal_emit(term->bg, "media,image", "terminology"); else if (type == TYPE_SCALE) edje_object_signal_emit(term->bg, "media,scale", "terminology"); else if (type == TYPE_EDJE) edje_object_signal_emit(term->bg, "media,edje", "terminology"); else if (type == TYPE_MOV) edje_object_signal_emit(term->bg, "media,movie", "terminology"); } else { if (term->media) { edje_object_signal_emit(term->bg, "media,off", "terminology"); evas_object_del(term->media); term->media = NULL; } } } } } void main_media_mute_update(const Config *config) { Win *wn; Term *term; Eina_List *l, *ll; EINA_LIST_FOREACH(wins, l, wn) { EINA_LIST_FOREACH(wn->terms, ll, term) { if (term->media) media_mute_set(term->media, config->mute); } } } static void main_win_free(Win *wn) { Term *term; EINA_LIST_FREE(wn->terms, term) { main_term_free(term); } if (wn->win) evas_object_del(wn->win); if (wn->config) config_del(wn->config); free(wn); } static Win * main_win_new(const char *name, const char *role, const char *title, const char *icon_name, Eina_Bool fullscreen, Eina_Bool iconic, Eina_Bool borderless, Eina_Bool override, Eina_Bool maximized) { Win *wn; Evas_Object *o; wn = calloc(1, sizeof(Win)); if (!wn) return NULL; wn->win = tg_win_add(name, role, title, icon_name); if (!wn->win) { free(wn); return NULL; } evas_object_event_callback_add(wn->win, EVAS_CALLBACK_DEL, _cb_del, wn); if (fullscreen) elm_win_fullscreen_set(wn->win, EINA_TRUE); if (iconic) elm_win_iconified_set(wn->win, EINA_TRUE); if (borderless) elm_win_borderless_set(wn->win, EINA_TRUE); if (override) elm_win_override_set(wn->win, EINA_TRUE); if (maximized) elm_win_maximized_set(wn->win, EINA_TRUE); wn->backbg = o = evas_object_rectangle_add(evas_object_evas_get(wn->win)); evas_object_color_set(o, 0, 0, 0, 255); evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_win_resize_object_add(wn->win, o); evas_object_show(o); wn->conform = o = elm_conformant_add(wn->win); evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_win_resize_object_add(wn->win, o); evas_object_show(o); evas_object_smart_callback_add(wn->win, "focus,in", _cb_focus_in, wn); evas_object_smart_callback_add(wn->win, "focus,out", _cb_focus_out, wn); wins = eina_list_append(wins, wn); return wn; } static void main_term_free(Term *term) { evas_object_del(term->term); evas_object_del(term->cmdbox); evas_object_del(term->bg); if (term->media) evas_object_del(term->media); free(term); } static Term * main_term_new(Win *wn, Config *config, const char *cmd, Eina_Bool login_shell, const char *cd, int size_w, int size_h, Eina_Bool hold) { Term *term; Evas_Object *o; term = calloc(1, sizeof(Term)); if (!term) return NULL; term->wn = wn; term->hold = hold; term->bg = o = edje_object_add(evas_object_evas_get(wn->win)); evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); if (!theme_apply(o, config, "terminology/background")) { CRITICAL("Couldn't find terminology theme! Forgot 'make install'?"); evas_object_del(term->bg); free(term); return NULL; } theme_auto_reload_enable(o); evas_object_show(o); edje_object_signal_callback_add(o, "popmedia,done", "terminology", _cb_popmedia_done, term); term->cmdbox = o = elm_entry_add(wn->win); elm_entry_single_line_set(o, EINA_TRUE); elm_entry_scrollable_set(o, EINA_FALSE); elm_scroller_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF); elm_entry_input_panel_layout_set(o, ELM_INPUT_PANEL_LAYOUT_TERMINAL); elm_entry_autocapital_type_set(o, ELM_AUTOCAPITAL_TYPE_NONE); elm_entry_input_panel_enabled_set(o, EINA_TRUE); elm_entry_input_panel_language_set(o, ELM_INPUT_PANEL_LANG_ALPHABET); elm_entry_input_panel_return_key_type_set(o, ELM_INPUT_PANEL_RETURN_KEY_TYPE_GO); elm_entry_prediction_allow_set(o, EINA_FALSE); evas_object_show(o); evas_object_smart_callback_add(o, "activated", _cb_cmd_activated, term); evas_object_smart_callback_add(o, "aborted", _cb_cmd_aborted, term); evas_object_smart_callback_add(o, "changed,user", _cb_cmd_changed, term); evas_object_event_callback_add(o, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _cb_cmd_hints_changed, term); edje_object_part_swallow(term->bg, "terminology.cmdbox", o); term->term = o = termio_add(wn->win, config, cmd, login_shell, cd, size_w, size_h); termio_win_set(o, wn->win); termio_theme_set(o, term->bg); evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_event_callback_add(o, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _cb_size_hint, term); edje_object_part_swallow(term->bg, "terminology.content", o); evas_object_smart_callback_add(o, "options", _cb_options, term); evas_object_smart_callback_add(o, "change", _cb_change, term); evas_object_smart_callback_add(o, "exited", _cb_exited, term); evas_object_smart_callback_add(o, "bell", _cb_bell, term); evas_object_smart_callback_add(o, "popup", _cb_popup, term); evas_object_smart_callback_add(o, "cmdbox", _cb_cmdbox, term); evas_object_smart_callback_add(o, "command", _cb_command, term); evas_object_show(o); if (!wn->terms) { term->focused = EINA_TRUE; // edje_object_signal_emit(term->bg, "focus,in", "terminology"); } wn->terms = eina_list_append(wn->terms, term); return term; } static void main_ipc_new(Ipc_Instance *inst) { Win *wn; Term *term; Config *config; if (inst->startup_id) { char buf[4096]; snprintf(buf, sizeof(buf), "DESKTOP_STARTUP_ID=%s", inst->startup_id); putenv(buf); } wn = main_win_new(inst->name, inst->role, inst->title, inst->icon_name, inst->fullscreen, inst->iconic, inst->borderless, inst->override, inst->maximized); if (!wn) return; config = config_load("config"); wn->config = config; unsetenv("DESKTOP_STARTUP_ID"); if (inst->background) { eina_stringshare_replace(&(config->background), inst->background); config->temporary = EINA_TRUE; } if (inst->font) { if (strchr(inst->font, '/')) { char *fname = alloca(strlen(inst->font) + 1); char *p; strcpy(fname, inst->font); p = strrchr(fname, '/'); if (p) { int sz; *p = 0; p++; sz = atoi(p); if (sz > 0) config->font.size = sz; eina_stringshare_replace(&(config->font.name), fname); } config->font.bitmap = 0; } else { char buf[4096], *file; Eina_List *files; int n = strlen(inst->font); snprintf(buf, sizeof(buf), "%s/fonts", elm_app_data_dir_get()); files = ecore_file_ls(buf); EINA_LIST_FREE(files, file) { if (n > 0) { if (!strncasecmp(file, inst->font, n)) { n = -1; eina_stringshare_replace(&(config->font.name), file); config->font.bitmap = 1; } } free(file); } } config->temporary = EINA_TRUE; } term = main_term_new(wn, config, inst->cmd, inst->login_shell, inst->cd, inst->w, inst->h, inst->hold); if (!term) { main_win_free(wn); return; } else { elm_object_content_set(wn->conform, term->bg); _cb_size_hint(term, evas_object_evas_get(wn->win), term->term, NULL); } main_trans_update(config); main_media_update(config); if (inst->pos) { int screen_w, screen_h; elm_win_screen_size_get(wn->win, NULL, NULL, &screen_w, &screen_h); if (inst->x < 0) inst->x = screen_w + inst->x; if (inst->y < 0) inst->y = screen_h + inst->y; evas_object_move(wn->win, inst->x, inst->y); } evas_object_show(wn->win); if (inst->nowm) ecore_evas_focus_set (ecore_evas_ecore_evas_get(evas_object_evas_get(wn->win)), 1); } static void _dummy_exit3(void *data __UNUSED__) { elm_exit(); } static Eina_Bool _dummy_exit2(void *data __UNUSED__) { ecore_job_add(_dummy_exit3, NULL); return EINA_FALSE; } static Eina_Bool _dummy_exit(void *data __UNUSED__) { ecore_idler_add(_dummy_exit2, NULL); return EINA_FALSE; } static const char *emotion_choices[] = { "auto", "gstreamer", "xine", "generic", NULL }; static const Ecore_Getopt options = { PACKAGE_NAME, "%prog [options]", PACKAGE_VERSION, "(C) 2012 Carsten Haitzler and others", "BSD 2-Clause", "Terminal emulator written with Enlightenment Foundation Libraries.", EINA_TRUE, { #if (ECORE_VERSION_MAJOR >= 1) || (ECORE_VERSION_MINOR >= 8) ECORE_GETOPT_BREAK_STR ('e', "exec", #else ECORE_GETOPT_STORE_STR ('e', "exec", #endif "command to execute. " "Defaults to $SHELL (or passwd shel or /bin/sh)"), ECORE_GETOPT_STORE_STR ('d', "current-directory", "Change to directory for execution of terminal command."), ECORE_GETOPT_STORE_STR ('t', "theme", "Use the named edje theme or path to theme file."), ECORE_GETOPT_STORE_STR ('b', "background", "Use the named file as a background wallpaper."), ECORE_GETOPT_STORE_STR ('g', "geometry", "Terminal geometry to use (eg 80x24 or 80x24+50+20 etc.)."), ECORE_GETOPT_STORE_STR ('n', "name", "Set window name."), ECORE_GETOPT_STORE_STR ('r', "role", "Set window role."), ECORE_GETOPT_STORE_STR ('T', "title", "Set window title."), ECORE_GETOPT_STORE_STR ('i', "icon-name", "Set icon name."), ECORE_GETOPT_STORE_STR ('f', "font", "Set font (NAME/SIZE for scalable, NAME for bitmap."), ECORE_GETOPT_CHOICE ('v', "video-module", "Set emotion module to use.", emotion_choices), ECORE_GETOPT_STORE_BOOL('l', "login", "Run the shell as a login shell."), ECORE_GETOPT_STORE_BOOL('m', "video-mute", "Set mute mode for video playback."), ECORE_GETOPT_STORE_BOOL('c', "cursor-blink", "Set cursor blink mode."), ECORE_GETOPT_STORE_BOOL('G', "visual-bell", "Set visual bell mode."), ECORE_GETOPT_STORE_TRUE('F', "fullscreen", "Go into the fullscreen mode from start."), ECORE_GETOPT_STORE_TRUE('I', "iconic", "Go into an iconic state from the start."), ECORE_GETOPT_STORE_TRUE('B', "borderless", "Become a borderless managed window."), ECORE_GETOPT_STORE_TRUE('O', "override", "Become an override-redirect window."), ECORE_GETOPT_STORE_TRUE('M', "maximized", "Become maximized from the start."), ECORE_GETOPT_STORE_TRUE('W', "nowm", "Terminology is run without a wm."), ECORE_GETOPT_STORE_TRUE('H', "hold", "Don't exit when the command process exits."), ECORE_GETOPT_STORE_TRUE('s', "single", "Force single executable if multi-instance is enabled.."), ECORE_GETOPT_VERSION ('V', "version"), ECORE_GETOPT_COPYRIGHT ('C', "copyright"), ECORE_GETOPT_LICENSE ('L', "license"), ECORE_GETOPT_HELP ('h', "help"), ECORE_GETOPT_SENTINEL } }; EAPI_MAIN int elm_main(int argc, char **argv) { Win *wn; Term *term; char *cmd = NULL; char *cd = NULL; char *theme = NULL; char *background = NULL; char *geometry = NULL; char *name = NULL; char *role = NULL; char *title = NULL; char *icon_name = NULL; char *font = NULL; char *video_module = NULL; Eina_Bool login_shell = 0xff; /* unset */ Eina_Bool video_mute = 0xff; /* unset */ Eina_Bool cursor_blink = 0xff; /* unset */ Eina_Bool visual_bell = 0xff; /* unset */ Eina_Bool fullscreen = EINA_FALSE; Eina_Bool iconic = EINA_FALSE; Eina_Bool borderless = EINA_FALSE; Eina_Bool override = EINA_FALSE; Eina_Bool maximized = EINA_FALSE; Eina_Bool nowm = EINA_FALSE; Eina_Bool quit_option = EINA_FALSE; Eina_Bool hold = EINA_FALSE; Eina_Bool single = EINA_FALSE; #if (ECORE_VERSION_MAJOR >= 1) || (ECORE_VERSION_MINOR >= 8) Eina_Bool cmd_options = EINA_FALSE; #endif Ecore_Getopt_Value values[] = { #if (ECORE_VERSION_MAJOR >= 1) || (ECORE_VERSION_MINOR >= 8) ECORE_GETOPT_VALUE_BOOL(cmd_options), #else ECORE_GETOPT_VALUE_STR(cmd), #endif ECORE_GETOPT_VALUE_STR(cd), ECORE_GETOPT_VALUE_STR(theme), ECORE_GETOPT_VALUE_STR(background), ECORE_GETOPT_VALUE_STR(geometry), ECORE_GETOPT_VALUE_STR(name), ECORE_GETOPT_VALUE_STR(role), ECORE_GETOPT_VALUE_STR(title), ECORE_GETOPT_VALUE_STR(icon_name), ECORE_GETOPT_VALUE_STR(font), ECORE_GETOPT_VALUE_STR(video_module), ECORE_GETOPT_VALUE_BOOL(login_shell), ECORE_GETOPT_VALUE_BOOL(video_mute), ECORE_GETOPT_VALUE_BOOL(cursor_blink), ECORE_GETOPT_VALUE_BOOL(visual_bell), ECORE_GETOPT_VALUE_BOOL(fullscreen), ECORE_GETOPT_VALUE_BOOL(iconic), ECORE_GETOPT_VALUE_BOOL(borderless), ECORE_GETOPT_VALUE_BOOL(override), ECORE_GETOPT_VALUE_BOOL(maximized), ECORE_GETOPT_VALUE_BOOL(nowm), ECORE_GETOPT_VALUE_BOOL(hold), ECORE_GETOPT_VALUE_BOOL(single), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_NONE }; int args, retval = EXIT_SUCCESS; Config *config; Evas_Object *o; int pos_set = 0, size_set = 0; int pos_x = 0, pos_y = 0; int size_w = 1, size_h = 1; _log_domain = eina_log_domain_register("terminology", NULL); if (_log_domain < 0) { EINA_LOG_CRIT("could not create log domain 'terminology'."); elm_shutdown(); return EXIT_FAILURE; } config_init(); config = config_load("config"); elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR); elm_app_compile_data_dir_set(PACKAGE_DATA_DIR); elm_app_info_set(elm_main, "terminology", "themes/default.edj"); args = ecore_getopt_parse(&options, values, argc, argv); if (args < 0) { ERR("Could not parse command line options."); retval = EXIT_FAILURE; goto end; } if (quit_option) goto end; #if (ECORE_VERSION_MAJOR >= 1) || (ECORE_VERSION_MINOR >= 8) if (cmd_options) { int i; Eina_Strbuf *strb; if (args == argc) { fprintf(stdout, "ERROR: option %s requires an argument!\n", argv[args-1]); fprintf(stdout, "ERROR: invalid options found. See --help.\n"); goto end; } strb = eina_strbuf_new(); for(i = args; i < argc; i++) { eina_strbuf_append(strb, argv[i]); eina_strbuf_append_char(strb, ' '); } cmd = eina_strbuf_string_steal(strb); eina_strbuf_free(strb); } #endif if (theme) { char path[PATH_MAX]; char nom[PATH_MAX]; if (eina_str_has_suffix(theme, ".edj")) eina_strlcpy(nom, theme, sizeof(nom)); else snprintf(nom, sizeof(nom), "%s.edj", theme); if (strchr(nom, '/')) eina_strlcpy(path, nom, sizeof(path)); else snprintf(path, sizeof(path), "%s/themes/%s", elm_app_data_dir_get(), nom); eina_stringshare_replace(&(config->theme), path); config->temporary = EINA_TRUE; } if (background) { eina_stringshare_replace(&(config->background), background); config->temporary = EINA_TRUE; } if (font) { if (strchr(font, '/')) { char *fname = alloca(strlen(font) + 1); char *p; strcpy(fname, font); p = strrchr(fname, '/'); if (p) { int sz; *p = 0; p++; sz = atoi(p); if (sz > 0) config->font.size = sz; eina_stringshare_replace(&(config->font.name), fname); } config->font.bitmap = 0; } else { char buf[4096], *file; Eina_List *files; int n = strlen(font); snprintf(buf, sizeof(buf), "%s/fonts", elm_app_data_dir_get()); files = ecore_file_ls(buf); EINA_LIST_FREE(files, file) { if (n > 0) { if (!strncasecmp(file, font, n)) { n = -1; eina_stringshare_replace(&(config->font.name), file); config->font.bitmap = 1; } } free(file); } } config->temporary = EINA_TRUE; } if (video_module) { int i; for (i = 0; i < (int)EINA_C_ARRAY_LENGTH(emotion_choices); i++) { if (video_module == emotion_choices[i]) break; } if (i == EINA_C_ARRAY_LENGTH(emotion_choices)) i = 0; /* ecore getopt shouldn't let this happen, but... */ config->vidmod = i; config->temporary = EINA_TRUE; } if (video_mute != 0xff) { config->mute = video_mute; config->temporary = EINA_TRUE; } if (cursor_blink != 0xff) { config->disable_cursor_blink = !cursor_blink; config->temporary = EINA_TRUE; } if (visual_bell != 0xff) { config->disable_visual_bell = !visual_bell; config->temporary = EINA_TRUE; } if (geometry) { if (sscanf(geometry,"%ix%i+%i+%i", &size_w, &size_h, &pos_x, &pos_y) == 4) { pos_set = 1; size_set = 1; } else if (sscanf(geometry,"%ix%i-%i+%i", &size_w, &size_h, &pos_x, &pos_y) == 4) { pos_x = -pos_x; pos_set = 1; size_set = 1; } else if (sscanf(geometry,"%ix%i-%i-%i", &size_w, &size_h, &pos_x, &pos_y) == 4) { pos_x = -pos_x; pos_y = -pos_y; pos_set = 1; size_set = 1; } else if (sscanf(geometry,"%ix%i+%i-%i", &size_w, &size_h, &pos_x, &pos_y) == 4) { pos_y = -pos_y; pos_set = 1; size_set = 1; } else if (sscanf(geometry,"%ix%i", &size_w, &size_h) == 2) { size_set = 1; } else if (sscanf(geometry,"+%i+%i", &pos_x, &pos_y) == 2) { pos_set = 1; } else if (sscanf(geometry,"-%i+%i", &pos_x, &pos_y) == 2) { pos_x = -pos_x; pos_set = 1; } else if (sscanf(geometry,"+%i-%i", &pos_x, &pos_y) == 2) { pos_y = -pos_y; pos_set = 1; } else if (sscanf(geometry,"-%i-%i", &pos_x, &pos_y) == 2) { pos_x = -pos_x; pos_y = -pos_y; pos_set = 1; } } // later allow default size to be configured if (!size_set) { size_w = 80; size_h = 24; } // for now if not set - dont do login shell - later from config if (login_shell == 0xff) login_shell = EINA_FALSE; ipc_init(); if ((!single) && (config->multi_instance)) { Ipc_Instance inst; char cwdbuf[4096]; memset(&inst, 0, sizeof(Ipc_Instance)); inst.cmd = cmd; if (cd) inst.cd = cd; else { getcwd(cwdbuf, sizeof(cwdbuf)); inst.cd = cwdbuf; } inst.background = background; inst.name = name; inst.role = role; inst.title = title; inst.icon_name = icon_name; inst.font = font; inst.startup_id = getenv("DESKTOP_STARTUP_ID"); inst.x = pos_x; inst.y = pos_y; inst.w = size_w; inst.h = size_h; inst.pos = pos_set; inst.login_shell = login_shell; inst.fullscreen = fullscreen; inst.iconic = iconic; inst.borderless = borderless; inst.override = override; inst.maximized = maximized; inst.hold = hold; inst.nowm = nowm; if (ipc_instance_add(&inst)) { ecore_timer_add(0.1, _dummy_exit, NULL); elm_run(); goto end; } } if ((!single) && (config->multi_instance)) { ipc_instance_new_func_set(main_ipc_new); ipc_serve(); } wn = main_win_new(name, role, title, icon_name, fullscreen, iconic, borderless, override, maximized); // set an env so terminal apps can detect they are in terminology :) putenv("TERMINOLOGY=1"); unsetenv("DESKTOP_STARTUP_ID"); if (!wn) { config_del(config); retval = EXIT_FAILURE; goto end; } wn->config = config; term = main_term_new(wn, config, cmd, login_shell, cd, size_w, size_h, hold); if (!term) { retval = EXIT_FAILURE; goto end; } else { elm_object_content_set(wn->conform, term->bg); _cb_size_hint(term, evas_object_evas_get(wn->win), term->term, NULL); } main_trans_update(config); main_media_update(config); if (pos_set) { int screen_w, screen_h; elm_win_screen_size_get(wn->win, NULL, NULL, &screen_w, &screen_h); if (pos_x < 0) pos_x = screen_w + pos_x; if (pos_y < 0) pos_y = screen_h + pos_y; evas_object_move(wn->win, pos_x, pos_y); } evas_object_show(wn->win); if (nowm) ecore_evas_focus_set (ecore_evas_ecore_evas_get(evas_object_evas_get(wn->win)), 1); elm_run(); end: #if (ECORE_VERSION_MAJOR >= 1) || (ECORE_VERSION_MINOR >= 8) free(cmd); #endif ipc_shutdown(); EINA_LIST_FREE(wins, wn) { main_win_free(wn); } config_shutdown(); eina_log_domain_unregister(_log_domain); _log_domain = -1; // efreet/edbus... you are being bad! :( disable shutdown for now // to avoid segs. elm_shutdown(); return retval; } ELM_MAIN()