efl/src/lib/elementary/elm_systray.c

525 lines
15 KiB
C

#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
#include "elm_systray_eo.h"
#include "elm_systray_watcher.h"
EAPI int ELM_EVENT_SYSTRAY_READY = 0;
typedef struct _Elm_Systray_Private_Data
{
Elm_Systray_Category cat;
Elm_Systray_Status status;
const char *att_icon_name;
const char *icon_name;
const char *icon_theme_path;
const char *id;
const char *title;
const char *menu;
const Eo *menu_obj;
} Elm_Systray_Private_Data;
static Elm_Systray_Private_Data _item = {
.cat = ELM_SYSTRAY_CATEGORY_APP_STATUS,
.status = ELM_SYSTRAY_STATUS_ACTIVE,
.att_icon_name = NULL,
.icon_name = NULL,
.icon_theme_path = NULL,
.id = NULL,
.title = NULL,
.menu = NULL,
.menu_obj = NULL
};
#define OBJ_PATH "/org/ayatana/NotificationItem/StatusNotifierItem"
#define INTERFACE "org.kde.StatusNotifierItem"
static Eina_Bool _elm_need_systray = EINA_FALSE;
static Eldbus_Connection *_conn = NULL;
static Eldbus_Service_Interface *_iface = NULL;
static const char *_Elm_Systray_Cat_Str[] = {
[ELM_SYSTRAY_CATEGORY_APP_STATUS] = "ApplicationStatus",
[ELM_SYSTRAY_CATEGORY_COMMUNICATIONS] = "Communications",
[ELM_SYSTRAY_CATEGORY_SYS_SERVICES] = "SystemServices",
[ELM_SYSTRAY_CATEGORY_HARDWARE] = "Hardware",
[ELM_SYSTRAY_CATEGORY_OTHER] = "Other"
};
static const char *_Elm_Systray_Status_Str[] = {
[ELM_SYSTRAY_STATUS_ACTIVE] = "Active",
[ELM_SYSTRAY_STATUS_PASSIVE] = "Passive",
[ELM_SYSTRAY_STATUS_ATTENTION] = "NeedsAttention"
};
// =============================================================================
// org.kde.StatusNotifierItem Service
// =============================================================================
// =============================================================================
// Methods
// =============================================================================
static Eldbus_Message *
_empty_method(const Eldbus_Service_Interface *iface EINA_UNUSED,
const Eldbus_Message *msg)
{
return eldbus_message_method_return_new(msg);
}
static const Eldbus_Method methods[] = {
{
"Scroll",
ELDBUS_ARGS({"i", "delta"}, {"s", "orientation"}),
NULL,
_empty_method,
0
},
{
"SecondaryActivate",
ELDBUS_ARGS({"i", "x"}, {"i", "y"}),
NULL,
_empty_method,
0
},
{
"XAyatanaSecondaryActivate",
ELDBUS_ARGS({"u", "timestamp"}),
NULL,
_empty_method,
0
},
{ NULL, NULL, NULL, NULL, 0 }
};
// =============================================================================
// Signals
// =============================================================================
typedef enum _Elm_Systray_Service_Signals
{
ELM_SYSTRAY_SIGNAL_NEWATTENTIONICON,
ELM_SYSTRAY_SIGNAL_NEWICON,
ELM_SYSTRAY_SIGNAL_NEWICONTHEMEPATH,
ELM_SYSTRAY_SIGNAL_NEWSTATUS,
ELM_SYSTRAY_SIGNAL_NEWTITLE,
ELM_SYSTRAY_SIGNAL_XAYATANANEWLABEL
} Elm_Systray_Service_Signals;
#define _elm_systray_signal_emit(sig, ...) \
eldbus_service_signal_emit(_iface, sig, __VA_ARGS__)
static const Eldbus_Signal signals[] = {
[ELM_SYSTRAY_SIGNAL_NEWATTENTIONICON] = {
"NewAttentionIcon", NULL, 0
},
[ELM_SYSTRAY_SIGNAL_NEWICON] = {
"NewIcon", NULL, 0
},
[ELM_SYSTRAY_SIGNAL_NEWICONTHEMEPATH] = {
"NewIconThemePath", ELDBUS_ARGS({"s", "icon_theme_path"}), 0
},
[ELM_SYSTRAY_SIGNAL_NEWSTATUS] = {
"NewStatus", ELDBUS_ARGS({"s", "status"}), 0
},
[ELM_SYSTRAY_SIGNAL_NEWTITLE] = {
"NewTitle", NULL, 0
},
[ELM_SYSTRAY_SIGNAL_XAYATANANEWLABEL] = {
"XAyatanaNewLabel", ELDBUS_ARGS({"s", "label"}, {"s", "guide"}), 0
},
{ NULL, NULL, 0 }
};
// =============================================================================
// Properties
// =============================================================================
static Eina_Bool
_prop_str_empty_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
eldbus_message_iter_basic_append(iter, 's', "");
return EINA_TRUE;
}
static Eina_Bool
_prop_attention_icon_name_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
const char *s = _item.att_icon_name ? _item.att_icon_name : "";
eldbus_message_iter_basic_append(iter, 's', s);
return EINA_TRUE;
}
static Eina_Bool
_prop_category_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
eldbus_message_iter_basic_append(iter, 's', _Elm_Systray_Cat_Str[_item.cat]);
return EINA_TRUE;
}
static Eina_Bool
_prop_icon_name_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
const char *s = _item.icon_name ? _item.icon_name : "";
eldbus_message_iter_basic_append(iter, 's', s);
return EINA_TRUE;
}
static Eina_Bool
_prop_icon_theme_path_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
const char *s = _item.icon_theme_path ? _item.icon_theme_path : "";
eldbus_message_iter_basic_append(iter, 's', s);
return EINA_TRUE;
}
static Eina_Bool
_prop_id_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
const char *s = _item.id ? _item.id : "";
eldbus_message_iter_basic_append(iter, 's', s);
return EINA_TRUE;
}
static Eina_Bool
_prop_menu_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
const char *s = _item.menu ? _item.menu : "/";
eldbus_message_iter_basic_append(iter, 'o', s);
return EINA_TRUE;
}
static Eina_Bool
_prop_status_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
eldbus_message_iter_basic_append(iter, 's',
_Elm_Systray_Status_Str[_item.status]);
return EINA_TRUE;
}
static Eina_Bool
_prop_title_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
const char *s = _item.title ? _item.title : "";
eldbus_message_iter_basic_append(iter, 's', s);
return EINA_TRUE;
}
static Eina_Bool
_prop_xayatana_orderindex_get(const Eldbus_Service_Interface *iface EINA_UNUSED,
const char *propname EINA_UNUSED,
Eldbus_Message_Iter *iter,
const Eldbus_Message *request_msg EINA_UNUSED,
Eldbus_Message **error EINA_UNUSED)
{
eldbus_message_iter_basic_append(iter, 'u', 0);
return EINA_TRUE;
}
static const Eldbus_Property properties[] = {
{ "AttentionAcessibleDesc", "s", _prop_str_empty_get, NULL, 0 },
{ "AttentionIconName", "s", _prop_attention_icon_name_get, NULL, 0 },
{ "Category", "s", _prop_category_get, NULL, 0 },
{ "IconAcessibleDesc", "s", _prop_str_empty_get, NULL, 0 },
{ "IconName", "s", _prop_icon_name_get, NULL, 0 },
{ "IconThemePath", "s", _prop_icon_theme_path_get, NULL, 0 },
{ "Id", "s", _prop_id_get, NULL, 0 },
{ "Menu", "o", _prop_menu_get, NULL, 0 },
{ "Status", "s", _prop_status_get, NULL, 0 },
{ "Title", "s", _prop_title_get, NULL, 0 },
{ "XAyatanaLabelGuide", "s", _prop_str_empty_get, NULL, 0 },
{ "XAyatanaLabel", "s", _prop_str_empty_get, NULL, 0 },
{ "XAyatanaOrderingIndex", "u", _prop_xayatana_orderindex_get, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Service_Interface_Desc _iface_desc = {
INTERFACE, methods, signals, properties, NULL, NULL
};
// =============================================================================
static void
_menu_died(void *data EINA_UNUSED,
Evas *e EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
_item.menu_obj = NULL;
eina_stringshare_replace(&(_item.menu), NULL);
eldbus_service_property_changed(_iface, "Menu");
}
EOLIAN static void
_elm_systray_category_set(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED, Elm_Systray_Category cat)
{
if (_item.cat == cat) return;
_item.cat = cat;
eldbus_service_property_changed(_iface, "Category");
}
EOLIAN static Elm_Systray_Category
_elm_systray_category_get(const Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
return _item.cat;
}
EOLIAN static void
_elm_systray_status_set(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED, Elm_Systray_Status st)
{
if (_item.status == st) return;
_item.status = st;
eldbus_service_property_changed(_iface, "Status");
_elm_systray_signal_emit(ELM_SYSTRAY_SIGNAL_NEWSTATUS,
_Elm_Systray_Status_Str[_item.status]);
}
EOLIAN static Elm_Systray_Status
_elm_systray_status_get(const Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
return _item.status;
}
EOLIAN static void
_elm_systray_att_icon_name_set(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED, const char *att_icon_name)
{
if (!eina_stringshare_replace(&(_item.att_icon_name), att_icon_name)) return;
eldbus_service_property_changed(_iface, "AttentionIconName");
_elm_systray_signal_emit(ELM_SYSTRAY_SIGNAL_NEWATTENTIONICON, NULL);
}
EOLIAN static const char*
_elm_systray_att_icon_name_get(const Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
return _item.att_icon_name;
}
EOLIAN static void
_elm_systray_icon_name_set(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED, const char *icon_name)
{
if (!eina_stringshare_replace(&(_item.icon_name), icon_name)) return;
eldbus_service_property_changed(_iface, "IconName");
_elm_systray_signal_emit(ELM_SYSTRAY_SIGNAL_NEWICON, NULL);
}
EOLIAN static const char*
_elm_systray_icon_name_get(const Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
return _item.icon_name;
}
EOLIAN static void
_elm_systray_icon_theme_path_set(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED, const char *icon_theme_path)
{
if (!eina_stringshare_replace(&(_item.icon_theme_path), icon_theme_path))
return;
eldbus_service_property_changed(_iface, "IconThemePath");
_elm_systray_signal_emit(ELM_SYSTRAY_SIGNAL_NEWICONTHEMEPATH,
_item.icon_theme_path);
}
EOLIAN static const char*
_elm_systray_icon_theme_path_get(const Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
return _item.icon_theme_path;
}
EOLIAN static void
_elm_systray_id_set(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED, const char *id)
{
if (!eina_stringshare_replace(&(_item.id), id)) return;
eldbus_service_property_changed(_iface, "Id");
}
EOLIAN static const char*
_elm_systray_id_get(const Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
return _item.id;
}
EOLIAN static void
_elm_systray_title_set(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED, const char *title)
{
if (!eina_stringshare_replace(&(_item.title), title)) return;
eldbus_service_property_changed(_iface, "Title");
_elm_systray_signal_emit(ELM_SYSTRAY_SIGNAL_NEWTITLE, NULL);
}
EOLIAN static const char*
_elm_systray_title_get(const Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
return _item.title;
}
EOLIAN static void
_elm_systray_menu_set(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED, const Eo *menu_obj)
{
const char *menu = NULL;
if (_item.menu_obj == menu_obj) return;
if (menu_obj)
{
menu = _elm_dbus_menu_register((Eo *) menu_obj);
evas_object_event_callback_add((Evas_Object *) menu_obj,
EVAS_CALLBACK_DEL, _menu_died, NULL);
}
eina_stringshare_replace(&(_item.menu), menu);
if (_item.menu_obj)
evas_object_event_callback_del_full((Evas_Object *) _item.menu_obj,
EVAS_CALLBACK_DEL, _menu_died, NULL);
_item.menu_obj = menu_obj;
eldbus_service_property_changed(_iface, "Menu");
}
EOLIAN static const Eo*
_elm_systray_menu_get(const Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
return _item.menu_obj;
}
EOLIAN static Eina_Bool
_elm_systray_register(Eo *obj EINA_UNUSED, void *priv EINA_UNUSED)
{
if (!_elm_need_systray) return EINA_FALSE;
return _elm_systray_watcher_status_notifier_item_register(OBJ_PATH);
}
EAPI Eina_Bool
elm_need_systray(void)
{
if (_elm_need_systray) return EINA_TRUE;
if (!elm_need_eldbus()) return EINA_FALSE;
ELM_EVENT_SYSTRAY_READY = ecore_event_type_new();
if (!_elm_systray_watcher_init()) return EINA_FALSE;
_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
if (!_conn) goto err;
_iface = eldbus_service_interface_register(_conn, OBJ_PATH, &_iface_desc);
if (!_iface) goto err;
_elm_need_systray = EINA_TRUE;
return EINA_TRUE;
err:
if (_conn)
{
eldbus_connection_unref(_conn);
_conn = NULL;
}
_elm_systray_watcher_shutdown();
return EINA_FALSE;
}
void
_elm_unneed_systray(void)
{
if (!_elm_need_systray) return;
ecore_event_type_flush(ELM_EVENT_SYSTRAY_READY);
_elm_need_systray = EINA_FALSE;
eldbus_service_interface_unregister(_iface);
eldbus_connection_unref(_conn);
_elm_systray_watcher_shutdown();
eina_stringshare_del(_item.att_icon_name);
eina_stringshare_del(_item.icon_name);
eina_stringshare_del(_item.icon_theme_path);
eina_stringshare_del(_item.id);
eina_stringshare_del(_item.title);
eina_stringshare_del(_item.menu);
if (_item.menu_obj)
{
evas_object_event_callback_del_full((Evas_Object *) _item.menu_obj,
EVAS_CALLBACK_DEL, _menu_died,
NULL);
_item.menu_obj = NULL;
}
}
EAPI Elm_Systray*
elm_systray_add(Evas_Object *win)
{
return efl_add(ELM_SYSTRAY_CLASS, win);
}
#include "elm_systray_eo.c"