diff --git a/legacy/elementary/src/lib/elm_general.eot b/legacy/elementary/src/lib/elm_general.eot index b492041b9e..9b7fe19b93 100644 --- a/legacy/elementary/src/lib/elm_general.eot +++ b/legacy/elementary/src/lib/elm_general.eot @@ -26,7 +26,8 @@ enum Elm.Policy.Quit { [[Possible values for the #ELM_POLICY_QUIT policy]] none = 0, [[never quit the application automatically]] - last_window_closed [[quit when the application's last window is closed]] + last_window_closed, [[quit when the application's last window is closed]] + last_window_hidden [[quit when the application's last window is hidden @since 1.14]] } enum Elm.Policy.Exit diff --git a/legacy/elementary/src/lib/elm_win.c b/legacy/elementary/src/lib/elm_win.c index e41113a7df..0b68128e5f 100644 --- a/legacy/elementary/src/lib/elm_win.c +++ b/legacy/elementary/src/lib/elm_win.c @@ -212,6 +212,7 @@ struct _Elm_Win_Data Eina_Bool modal : 1; Eina_Bool demand_attention : 1; Eina_Bool autodel : 1; + Eina_Bool autohide : 1; Eina_Bool constrain : 1; Eina_Bool resizing : 1; Eina_Bool iconified : 1; @@ -503,6 +504,41 @@ _elm_win_state_eval(void *data EINA_UNUSED) return EINA_FALSE; } +static Eina_Bool +_elm_win_policy_quit_triggered(Eo* triggering_obj) +{ + if ((!_elm_win_list) && + (elm_policy_get(ELM_POLICY_QUIT) == ELM_POLICY_QUIT_LAST_WINDOW_CLOSED)) + { + return EINA_TRUE; + } + + if (elm_policy_get(ELM_POLICY_QUIT) == ELM_POLICY_QUIT_LAST_WINDOW_HIDDEN) + { + Eina_List *l; + Evas_Object *win; + + EINA_LIST_FOREACH(_elm_win_list, l, win) + if (win != triggering_obj && evas_object_visible_get(win) == EINA_TRUE) + { + return EINA_FALSE; + } + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static void +_elm_win_flush_cache_and_exit(Eo *obj) +{ + edje_file_cache_flush(); + edje_collection_cache_flush(); + evas_image_cache_flush(evas_object_evas_get(obj)); + evas_font_cache_flush(evas_object_evas_get(obj)); + elm_exit(); +} + static void _elm_win_state_eval_queue(void) { @@ -1544,6 +1580,9 @@ _elm_win_evas_object_smart_hide(Eo *obj, Elm_Win_Data *sd) } if (_elm_config->atspi_mode) eo_do(obj, eo_event_callback_call(ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_DESTROYED, NULL)); + + if (_elm_win_policy_quit_triggered(obj)) + _elm_win_flush_cache_and_exit(obj); } static void @@ -1866,14 +1905,9 @@ _elm_win_evas_object_smart_del(Eo *obj, Elm_Win_Data *sd) eo_do_super(obj, MY_CLASS, evas_obj_smart_del()); - if ((!_elm_win_list) && - (elm_policy_get(ELM_POLICY_QUIT) == ELM_POLICY_QUIT_LAST_WINDOW_CLOSED)) + if (_elm_win_policy_quit_triggered(obj)) { - edje_file_cache_flush(); - edje_collection_cache_flush(); - evas_image_cache_flush(evas_object_evas_get(obj)); - evas_font_cache_flush(evas_object_evas_get(obj)); - elm_exit(); + _elm_win_flush_cache_and_exit(obj); } if (_elm_config->atspi_mode) @@ -1992,6 +2026,8 @@ _elm_win_delete_request(Ecore_Evas *ee) sd->autodel_clear = &autodel; evas_object_ref(obj); evas_object_smart_callback_call(obj, SIG_DELETE_REQUEST, NULL); + if (sd->autohide) + evas_object_hide(obj); // FIXME: if above callback deletes - then the below will be invalid if (_elm_config->atspi_mode) eo_do(obj, eo_event_callback_call(ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_DESTROYED, NULL)); @@ -2795,6 +2831,8 @@ _elm_win_frame_cb_close(void *data, sd->autodel_clear = &autodel; evas_object_ref(win); evas_object_smart_callback_call(win, SIG_DELETE_REQUEST, NULL); + if (sd->autohide) + evas_object_hide(win); // FIXME: if above callback deletes - then the below will be invalid if (autodel) evas_object_del(win); else sd->autodel_clear = NULL; @@ -3997,6 +4035,18 @@ _elm_win_autodel_get(Eo *obj EINA_UNUSED, Elm_Win_Data *sd) return sd->autodel; } +EOLIAN static void +_elm_win_autohide_set(Eo *obj EINA_UNUSED, Elm_Win_Data *sd, Eina_Bool autohide) +{ + sd->autohide = autohide; +} + +EOLIAN static Eina_Bool +_elm_win_autohide_get(Eo *obj EINA_UNUSED, Elm_Win_Data *sd) +{ + return sd->autohide; +} + EOLIAN static void _elm_win_activate(Eo *obj EINA_UNUSED, Elm_Win_Data *sd) { diff --git a/legacy/elementary/src/lib/elm_win.eo b/legacy/elementary/src/lib/elm_win.eo index 6bfa43f58e..eb39c84f25 100644 --- a/legacy/elementary/src/lib/elm_win.eo +++ b/legacy/elementary/src/lib/elm_win.eo @@ -211,6 +211,34 @@ class Elm.Win (Elm.Widget, Elm_Interface_Atspi_Window, closed */ } } + @property autohide { + [[Window's autohide state. + + This property works similarly to @c autodel, automatically handling + "delete,request" signals when set to @c EINA_TRUE, with the difference + that it will hide the window, instead of destroying it. + + It is specially designed to work together with @c ELM_POLICY_QUIT_LAST_WINDOW_HIDDEN + which allows exiting Elementary's main loop when all the windows + are hidden. + + @see elm_win_autodel_set() + + @note @c autodel and @c autohide are not mutually exclusive. The window + will be deleted if both are set to @c EINA_TRUE. + + @ingroup Win + ]] + + set { + } + get { + } + values { + autohide: bool; /*@ If true, the window will automatically hide itself when + closed */ + } + } @property override { set { /*@ diff --git a/legacy/elementary/src/lib/elm_win.h b/legacy/elementary/src/lib/elm_win.h index 3b43b18111..b94f6f9ad3 100644 --- a/legacy/elementary/src/lib/elm_win.h +++ b/legacy/elementary/src/lib/elm_win.h @@ -69,7 +69,7 @@ * Signals that you can add callbacks for are: * * @li "delete,request": the user requested to close the window. See - * elm_win_autodel_set(). + * elm_win_autodel_set() and elm_win_autohide_set(). * @li "focus,in": window got focus (deprecated. use "focused" instead.) * @li "focus,out": window lost focus (deprecated. use "unfocused" instead.) * @li "moved": window that holds the canvas was moved diff --git a/legacy/elementary/src/tests/elm_test_win.c b/legacy/elementary/src/tests/elm_test_win.c index 702d2c735e..6fc07ef81e 100644 --- a/legacy/elementary/src/tests/elm_test_win.c +++ b/legacy/elementary/src/tests/elm_test_win.c @@ -5,8 +5,58 @@ #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED #define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED #include +#include #include "elm_suite.h" +static const double _timeout1 = 0.01; +static const double _timeout2 = 0.02; +static const double _timeout_fail = 2.0; + +static void +_do_delete_request(Eo *win) +{ +#ifdef HAVE_ELEMENTARY_X + Ecore_X_Window xwin; + eo_do(win, xwin = elm_obj_win_xwindow_get()); + ecore_x_window_delete_request_send(xwin); +#endif + + (void) win; +} + + +static Eina_Bool +_timer_delete_request_cb(void *data) +{ + Eo *win = (Eo*) data; + _do_delete_request(win); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_timer_hide_window_cb(void *data) +{ + Eo *win = (Eo*) data; + eo_do(win, efl_gfx_visible_set(EINA_FALSE)); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_timer_exit_cb(void *data EINA_UNUSED) +{ + elm_exit(); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_timer_fail_flag_cb(void *data) +{ + Eina_Bool *fail_flag = (Eina_Bool*) data; + *fail_flag = EINA_TRUE; + elm_exit(); + return ECORE_CALLBACK_PASS_ON; +} + START_TEST (elm_atspi_role_get) { @@ -66,9 +116,90 @@ START_TEST (elm_atspi_component_size) } END_TEST +START_TEST (elm_win_autohide) +{ + elm_init(0, NULL); + + Eo *win = elm_win_add(NULL, "win", ELM_WIN_BASIC); + eo_do(win, elm_obj_win_autohide_set(EINA_TRUE)); + eo_do(win, efl_gfx_visible_set(EINA_TRUE)); + + Eina_Bool fail_flag = EINA_FALSE; + ecore_timer_add(_timeout1, _timer_delete_request_cb, win); + ecore_timer_add(_timeout2, _timer_exit_cb, &fail_flag); + + elm_run(); + + Eina_Bool visible; + eo_do(win, visible = efl_gfx_visible_get()); + + ck_assert(visible == EINA_FALSE); + + elm_shutdown(); +} +END_TEST + +START_TEST (elm_win_policy_quit_last_window_hidden) +{ + elm_init(0, NULL); + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_HIDDEN); + + Eo *win = elm_win_add(NULL, "win", ELM_WIN_BASIC); + eo_do(win, efl_gfx_visible_set(EINA_TRUE)); + + Eina_Bool fail_flag = EINA_FALSE; + ecore_timer_add(_timeout1, _timer_hide_window_cb, win); + ecore_timer_add(_timeout_fail, _timer_fail_flag_cb, &fail_flag); + + elm_run(); + + Eina_Bool visible; + eo_do(win, visible = efl_gfx_visible_get()); + + ck_assert(fail_flag == EINA_FALSE); + ck_assert(eo_ref_get(win) >= 1); + ck_assert(visible == EINA_FALSE); + + elm_shutdown(); +} +END_TEST + +START_TEST (elm_win_autohide_and_policy_quit_last_window_hidden) +{ + elm_init(0, NULL); + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_HIDDEN); + + Eo *win = elm_win_add(NULL, "win", ELM_WIN_BASIC); + eo_do(win, elm_obj_win_autohide_set(EINA_TRUE)); + eo_do(win, efl_gfx_visible_set(EINA_TRUE)); + + Eina_Bool fail_flag = EINA_FALSE; + ecore_timer_add(_timeout1, _timer_delete_request_cb, win); + ecore_timer_add(_timeout_fail, _timer_fail_flag_cb, &fail_flag); + + elm_run(); + + Eina_Bool visible; + eo_do(win, visible = efl_gfx_visible_get()); + + ck_assert(fail_flag == EINA_FALSE); + ck_assert(eo_ref_get(win) >= 1); + ck_assert(visible == EINA_FALSE); + + elm_shutdown(); +} +END_TEST + void elm_test_win(TCase *tc) { tcase_add_test(tc, elm_atspi_role_get); tcase_add_test(tc, elm_atspi_component_position); tcase_add_test(tc, elm_atspi_component_size); + tcase_add_test(tc, elm_win_policy_quit_last_window_hidden); +#ifdef HAVE_ELEMENTARY_X + tcase_add_test(tc, elm_win_autohide); + tcase_add_test(tc, elm_win_autohide_and_policy_quit_last_window_hidden); +#endif }