win: Add autohide and ELM_POLICY_QUIT_LAST_WINDOW_HIDDEN

Summary:
Add the "autohide" property to elm_win. This property, when set to
EINA_TRUE, automatically hides the window upon a "delete,request" signal.

Create ELM_POLICY_QUIT_LAST_WINDOW_HIDDEN, a new quit policy that
automatically exit from the elm_run loop when all windows are hidden.
It is an alternative to autodel to conciliates the memory management
framework of Eo with any other memory management model the program may
be using (e.g. RAII principles of C++).

Create the auxiliary function "_elm_win_policy_quit_triggered" to check
triggering of quit policies.
The check in "smart_hide" is now necessary, since
ELM_POLICY_QUIT_LAST_WINDOW_HIDDEN can be triggered when a window
is hidden.

Create the auxiliary function "_elm_win_flush_cache_and_exit" to avoid
code repetition for exiting the elm_run loop.

Make a small update on documentation in elm_win.h to mention the new
autohide property.

@feature

Reviewers: raster, felipealmeida, cedric, tasn

Reviewed By: felipealmeida

Differential Revision: https://phab.enlightenment.org/D2751
This commit is contained in:
Vitor Sousa 2015-07-01 15:40:57 +01:00 committed by Tom Hacohen
parent f0fa3e0709
commit 5a737f7187
5 changed files with 219 additions and 9 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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 {
/*@

View File

@ -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

View File

@ -5,8 +5,58 @@
#define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
#define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
#include <Elementary.h>
#include <Ecore_X.h>
#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
}