raster pushed a commit to branch master.

http://git.enlightenment.org/core/enlightenment.git/commit/?id=2e5be79c451fae48f97456369c12b3c0af08b5d8

commit 2e5be79c451fae48f97456369c12b3c0af08b5d8
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
Date:   Thu May 10 13:52:06 2018 +0900

    bluez5 support - a new module with gadget etc.
    
    Summary:
    bluez4 support is now basically dead. nothing ships it anymore. bluez5
    is a new api that is rather different so new code. also a new gui with
    more complete features etc.
    
    not everything is done as i'd like. need:
    
    1. many more icons for device types (60-70 maybe?)
    2. a few specific custom icons for some action buttons (like
    pair/unpair)
    3. icons for group headers
    4. gadget status - the gagdte itself displays zero status. it's a
    button to display a popup. that's all.
    
    Reviewers: zmike!
    
    Subscribers: devilhorns, cedric
    
    Tags: #enlightenment-git
    
    Differential Revision: https://phab.enlightenment.org/D6148
---
 meson_options.txt                      |   4 +
 src/bin/e_config.c                     |  38 ++
 src/bin/e_config.h                     |   2 +-
 src/bin/e_module.c                     |   1 +
 src/modules/bluez5/bz.c                | 109 +++++
 src/modules/bluez5/bz.h                | 234 ++++++++++
 src/modules/bluez5/bz_agent.c          | 346 +++++++++++++++
 src/modules/bluez5/bz_obj.c            | 760 +++++++++++++++++++++++++++++++++
 src/modules/bluez5/e-module-bluez5.edj | Bin 0 -> 59845 bytes
 src/modules/bluez5/e_mod_agent.c       | 143 +++++++
 src/modules/bluez5/e_mod_main.c        | 305 +++++++++++++
 src/modules/bluez5/e_mod_main.h        |  68 +++
 src/modules/bluez5/e_mod_popup.c       | 714 +++++++++++++++++++++++++++++++
 src/modules/bluez5/e_mod_util.c        | 262 ++++++++++++
 src/modules/bluez5/meson.build         |   9 +
 src/modules/bluez5/module.desktop      |  13 +
 src/modules/meson.build                |   1 +
 17 files changed, 3008 insertions(+), 1 deletion(-)

diff --git a/meson_options.txt b/meson_options.txt
index 234802766..c570b0522 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -111,6 +111,10 @@ option('bluez4',
        type: 'boolean',
        value: true,
        description: 'enable bluez4 module: (default=true)')
+option('bluez5',
+       type: 'boolean',
+       value: true,
+       description: 'enable bluez5 module: (default=true)')
 option('clock',
        type: 'boolean',
        value: true,
diff --git a/src/bin/e_config.c b/src/bin/e_config.c
index 1feb31bbc..5abf91bae 100644
--- a/src/bin/e_config.c
+++ b/src/bin/e_config.c
@@ -1525,6 +1525,44 @@ e_config_load(void)
                CONFIG_VERSION_UPDATE_INFO(25);
                e_config_save_queue();
             }
+          CONFIG_VERSION_CHECK(26)
+            {
+               // move from bluez4 to bluez5 automatically. you can manually
+               // move back if that works better for you...
+               Eina_List *l, *ll;
+               E_Config_Module *em;
+               E_Config_Gadcon *gc;
+               E_Config_Gadcon_Client *gcc;
+
+               EINA_LIST_FOREACH(e_config->modules, l, em)
+                 {
+                    if (!em->enabled) continue;
+                    if (!em->name) continue;
+                    if (eina_streq(em->name, "bluez4"))
+                      {
+                         eina_stringshare_replace(&(em->name), "bluez5");
+                      }
+                 }
+               EINA_LIST_FOREACH(e_config->gadcons, l, gc)
+                 {
+                    EINA_LIST_FOREACH(gc->clients, ll, gcc)
+                      {
+                         if (!gcc->name) continue;
+                         if (!strncmp(gcc->name, "bluez4", 6))
+                           {
+                              char *tmp = strdup(gcc->name);
+                              if (tmp)
+                                {
+                                   tmp[5] = '5';
+                                   eina_stringshare_replace(&(gcc->name), tmp);
+                                   free(tmp);
+                                }
+                           }
+                      }
+                 }
+               CONFIG_VERSION_UPDATE_INFO(26);
+               e_config_save_queue();
+            }
      }
    elm_config_profile_set(_e_config_profile);
    if (!e_config->remember_internal_fm_windows)
diff --git a/src/bin/e_config.h b/src/bin/e_config.h
index a4af30c5c..0ac67f144 100644
--- a/src/bin/e_config.h
+++ b/src/bin/e_config.h
@@ -46,7 +46,7 @@ typedef enum
 /* increment this whenever a new set of config values are added but the users
  * config doesn't need to be wiped - simply new values need to be put in
  */
-#define E_CONFIG_FILE_GENERATION 25
+#define E_CONFIG_FILE_GENERATION 26
 #define E_CONFIG_FILE_VERSION    ((E_CONFIG_FILE_EPOCH * 1000000) + 
E_CONFIG_FILE_GENERATION)
 
 #define E_CONFIG_BINDINGS_VERSION 0 // DO NOT INCREMENT UNLESS YOU WANT TO 
WIPE ALL BINDINGS!!!!!
diff --git a/src/bin/e_module.c b/src/bin/e_module.c
index 96ddcb67a..8c65f1185 100644
--- a/src/bin/e_module.c
+++ b/src/bin/e_module.c
@@ -997,6 +997,7 @@ _e_module_whitelist_check(void)
       "backlight",
       "battery",
       "bluez4",
+      "bluez5",
       "clock",
       "conf",
       "conf_applications",
diff --git a/src/modules/bluez5/bz.c b/src/modules/bluez5/bz.c
new file mode 100644
index 000000000..d0a7e083d
--- /dev/null
+++ b/src/modules/bluez5/bz.c
@@ -0,0 +1,109 @@
+#include "e_mod_main.h"
+
+Eldbus_Connection *bz_conn = NULL;
+
+static Ecore_Timer *owner_gain_timer = NULL;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static Eina_Bool
+cb_name_owner_new(void *data EINA_UNUSED)
+{
+   owner_gain_timer = NULL;
+   bz_obj_init();
+   bz_agent_init();
+   return EINA_FALSE;
+}
+
+static void
+cb_name_owner_changed(void *data EINA_UNUSED,
+                      const char *bus EINA_UNUSED,
+                      const char *from EINA_UNUSED,
+                      const char *to)
+{
+   static Eina_Bool first = EINA_TRUE;
+   if (to[0])
+     {
+        if (owner_gain_timer) ecore_timer_del(owner_gain_timer);
+        // on first start try and re-init quickly because we get a name
+        // owner change even if all is good when we register to listen for it,
+        // so start fast
+        if (first)
+          owner_gain_timer = ecore_timer_add(0.1, cb_name_owner_new, NULL);
+        // but if we gegt a name owner change later it's probably because
+        // bluez was restarted or crashed. a new bz daemon will (or should)
+        // come up. so re-init more slowly here giving the daemon some time
+        // to come up before pestering it.
+        else
+          owner_gain_timer = ecore_timer_add(1.0, cb_name_owner_new, NULL);
+        first = EINA_FALSE;
+     }
+   else
+     {
+        if (owner_gain_timer) ecore_timer_del(owner_gain_timer);
+        owner_gain_timer = NULL;
+        ebluze5_popup_clear();
+        bz_agent_shutdown();
+        bz_obj_shutdown();
+     }
+}
+
+static void
+cb_obj_add(Obj *o)
+{
+   if (o->type == BZ_OBJ_ADAPTER)
+     {
+        o->fn_change = ebluez5_popup_adapter_change;
+        o->fn_del = ebluez5_popup_adapter_del;
+        ebluez5_popup_adapter_add(o);
+        return;
+     }
+   if (o->type == BZ_OBJ_DEVICE)
+     {
+        o->fn_change = ebluez5_popup_device_change;
+        o->fn_del = ebluez5_popup_device_del;
+        ebluez5_popup_device_add(o);
+        return;
+     }
+}
+
+void
+bz_init(void)
+{
+   bz_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
+   bz_obj_add_func_set(cb_obj_add);
+   bz_agent_release_func_set(ebluez5_agent_agent_release);
+   bz_agent_cancel_func_set(ebluez5_agent_agent_cancel);
+   bz_agent_req_pin_func_set(ebluez5_agent_agent_req_pin);
+   bz_agent_disp_pin_func_set(ebluez5_agent_agent_disp_pin);
+   bz_agent_req_pass_func_set(ebluez5_agent_req_pass);
+   bz_agent_disp_pass_func_set(ebluez5_agent_disp_pass);
+   bz_agent_req_confirm_func_set(ebluez5_agent_req_confirm);
+   bz_agent_req_auth_func_set(ebluez5_agent_req_auth);
+   bz_agent_auth_service_func_set(ebluez5_agent_auth_service);
+   eldbus_name_owner_changed_callback_add(bz_conn, "org.bluez",
+                                          cb_name_owner_changed,
+                                          NULL, EINA_TRUE);
+}
+
+void
+bz_shutdown(void)
+{
+   eldbus_name_owner_changed_callback_del(bz_conn, "org.bluez",
+                                          cb_name_owner_changed, NULL);
+   bz_agent_release_func_set(NULL);
+   bz_agent_cancel_func_set(NULL);
+   bz_agent_req_pin_func_set(NULL);
+   bz_agent_disp_pin_func_set(NULL);
+   bz_agent_req_pass_func_set(NULL);
+   bz_agent_disp_pass_func_set(NULL);
+   bz_agent_req_confirm_func_set(NULL);
+   bz_agent_req_auth_func_set(NULL);
+   bz_agent_auth_service_func_set(NULL);
+   bz_obj_add_func_set(NULL);
+   ebluze5_popup_clear();
+   bz_agent_shutdown();
+   bz_obj_shutdown();
+   eldbus_connection_unref(bz_conn);
+   bz_conn = NULL;
+}
diff --git a/src/modules/bluez5/bz.h b/src/modules/bluez5/bz.h
new file mode 100644
index 000000000..252f20180
--- /dev/null
+++ b/src/modules/bluez5/bz.h
@@ -0,0 +1,234 @@
+#ifndef BZ_H
+# define BZ_H
+# include <Elementary.h>
+
+typedef enum {
+   BZ_OBJ_UNKNOWN,
+   BZ_OBJ_BLUEZ,
+   BZ_OBJ_ADAPTER,
+   BZ_OBJ_DEVICE
+} Obj_Type;
+
+typedef struct _Obj Obj;
+
+struct _Obj {
+   //// internal object data
+   Eldbus_Proxy *proxy;
+   Eldbus_Proxy *prop_proxy;
+   Eldbus_Signal_Handler *prop_sig;
+   unsigned int ref;
+   Eina_Bool in_table : 1;
+   Eina_Bool add_called : 1;
+   //// public data to read
+   const char *path;
+   Obj_Type type;
+   //// data to be set by users of the obj
+   void *data; // custom data
+   void (*fn_change) (Obj *o);
+   void (*fn_del) (Obj *o);
+   //// obj properties
+   Eina_Array *uuids;
+   const char *address;
+   const char *address_type;
+   const char *name;
+   const char *icon;
+   const char *alias;
+   const char *adapter;
+   const char *modalias;
+   unsigned int klass;
+   unsigned short appearance;
+   unsigned short txpower;
+   short rssi;
+   Eina_Bool paired : 1;
+   Eina_Bool connected : 1;
+   Eina_Bool trusted : 1;
+   Eina_Bool blocked : 1;
+   Eina_Bool legacy_pairing : 1;
+   Eina_Bool services_resolved : 1;
+   //// adapter specific properties
+   unsigned int discoverable_timeout;
+   unsigned int pairable_timeout;
+   Eina_Bool discoverable : 1;
+   Eina_Bool discovering : 1;
+   Eina_Bool pairable : 1;
+   Eina_Bool powered : 1;
+   //// agent data for when devices ask to pair etc.
+   const char *agent_request;
+   Eldbus_Message *agent_msg_ok;
+   Eldbus_Message *agent_msg_err;
+   void (*agent_entry_fn) (Eldbus_Message *msg, const char *str);
+   Eina_Bool agent_alert : 1;
+};
+
+#define BZ_OBJ_CLASS_SERVICE_LIMITED_DISCOVERABLE  (1 << 13)
+#define BZ_OBJ_CLASS_SERVICE_POSITIONING_BIT       (1 << 16)
+#define BZ_OBJ_CLASS_SERVICE_NETWORKING_BIT        (1 << 17)
+#define BZ_OBJ_CLASS_SERVICE_RENDERING_BIT         (1 << 18)
+#define BZ_OBJ_CLASS_SERVICE_CAPTURING_BIT         (1 << 19)
+#define BZ_OBJ_CLASS_SERVICE_OBJECT_TRANSFER_BIT   (1 << 20)
+#define BZ_OBJ_CLASS_SERVICE_AUDIO_BIT             (1 << 21)
+#define BZ_OBJ_CLASS_SERVICE_TELEPHONY_BIT         (1 << 22)
+#define BZ_OBJ_CLASS_SERVICE_INFORMATION_BIT       (1 << 23)
+
+#define BZ_OBJ_CLASS_MAJ_MASK                      (0x1f << 8)
+#define BZ_OBJ_CLASS_MAJ_MISC                      ( 0 << 8)
+#define BZ_OBJ_CLASS_MAJ_COMPUTER                  ( 1 << 8)
+#define BZ_OBJ_CLASS_MAJ_PHONE                     ( 2 << 8)
+#define BZ_OBJ_CLASS_MAJ_LAN                       ( 3 << 8)
+#define BZ_OBJ_CLASS_MAJ_AV                        ( 4 << 8)
+#define BZ_OBJ_CLASS_MAJ_PERIPHERAL                ( 5 << 8)
+#define BZ_OBJ_CLASS_MAJ_IMAGING                   ( 6 << 8)
+#define BZ_OBJ_CLASS_MAJ_WEARABLE                  ( 7 << 8)
+#define BZ_OBJ_CLASS_MAJ_TOY                       ( 8 << 8)
+#define BZ_OBJ_CLASS_MAJ_HEALTH                    ( 9 << 8)
+
+#define BZ_OBJ_CLASS_MIN_COMPUTER_MASK             (0x3f << 2)
+#define BZ_OBJ_CLASS_MIN_COMPUTER_DESKTOP          ( 1 << 2)
+#define BZ_OBJ_CLASS_MIN_COMPUTER_SERVER           ( 2 << 2)
+#define BZ_OBJ_CLASS_MIN_COMPUTER_LAPTOP           ( 3 << 2)
+#define BZ_OBJ_CLASS_MIN_COMPUTER_CLAMSHELL        ( 4 << 2)
+#define BZ_OBJ_CLASS_MIN_COMPUTER_PDA              ( 5 << 2)
+#define BZ_OBJ_CLASS_MIN_COMPUTER_WEARABLE         ( 6 << 2)
+#define BZ_OBJ_CLASS_MIN_COMPUTER_TABLET           ( 7 << 2)
+
+#define BZ_OBJ_CLASS_MIN_PHONE_MASK                (0x3f << 2)
+#define BZ_OBJ_CLASS_MIN_PHONE_CELL                ( 1 << 2)
+#define BZ_OBJ_CLASS_MIN_PHONE_CORDLESS            ( 2 << 2)
+#define BZ_OBJ_CLASS_MIN_PHONE_SMARTPHONE          ( 3 << 2)
+#define BZ_OBJ_CLASS_MIN_PHONE_WIRED               ( 4 << 2)
+#define BZ_OBJ_CLASS_MIN_PHONE_ISDN                ( 5 << 2)
+
+#define BZ_OBJ_CLASS_MIN_LAN_MASK                  (0x07 << 5)
+#define BZ_OBJ_CLASS_MIN_LAN_AVAIL_7               ( 0 << 5)
+#define BZ_OBJ_CLASS_MIN_LAN_AVAIL_6               ( 1 << 5)
+#define BZ_OBJ_CLASS_MIN_LAN_AVAIL_5               ( 2 << 5)
+#define BZ_OBJ_CLASS_MIN_LAN_AVAIL_4               ( 3 << 5)
+#define BZ_OBJ_CLASS_MIN_LAN_AVAIL_3               ( 4 << 5)
+#define BZ_OBJ_CLASS_MIN_LAN_AVAIL_2               ( 5 << 5)
+#define BZ_OBJ_CLASS_MIN_LAN_AVAIL_1               ( 6 << 5)
+#define BZ_OBJ_CLASS_MIN_LAN_AVAIL_0               ( 7 << 5)
+
+#define BZ_OBJ_CLASS_MIN_AV_MASK                   (0x3f << 2)
+#define BZ_OBJ_CLASS_MIN_AV_WEARABLE_HEADSET       ( 1 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_HANDS_FREE             ( 2 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_MIC                    ( 4 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_SPEAKER                ( 5 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_HEADPHONES             ( 6 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_PORTABLE_AUDIO         ( 7 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_CAR_AUDIO              ( 8 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_SET_TOP_BOX            ( 9 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_HIFI_AUDIO             (10 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_VCR                    (11 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_VIDEO_CAMERA           (12 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_CAMCORDER              (13 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_VIDEO_MONITOR          (14 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_VIDEO_DISPLAY_SPEAKER  (15 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_VIDEO_CONFERENCE       (16 << 2)
+#define BZ_OBJ_CLASS_MIN_AV_GAMING                 (18 << 2)
+
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_KEYBOARD_BIT   ( 1 << 6)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_MOUSE_BIT      ( 1 << 7)
+
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_MASK2          (0x0f << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_JOYSTICK       ( 1 << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_GAMEPAD        ( 2 << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_REMOTE         ( 3 << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_SENSING        ( 4 << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_DIGITIZER_TAB  ( 5 << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_CARD_READER    ( 6 << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_PEN            ( 7 << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_SCANNER        ( 8 << 2)
+#define BZ_OBJ_CLASS_MIN_PERIPHERAL_WAND           ( 9 << 2)
+
+#define BZ_OBJ_CLASS_MIN_IMAGING_DISPLAY_BIT       ( 1 << 4)
+#define BZ_OBJ_CLASS_MIN_IMAGING_CAMERA_BIT        ( 1 << 5)
+#define BZ_OBJ_CLASS_MIN_IMAGING_SCANNER_BIT       ( 1 << 6)
+#define BZ_OBJ_CLASS_MIN_IMAGING_PRINTER_BIT       ( 1 << 7)
+
+#define BZ_OBJ_CLASS_MIN_WEARABLE_MASK             (0x3f << 2)
+#define BZ_OBJ_CLASS_MIN_WEARABLE_WATCH            ( 1 << 2)
+#define BZ_OBJ_CLASS_MIN_WEARABLE_PAGER            ( 2 << 2)
+#define BZ_OBJ_CLASS_MIN_WEARABLE_JACKET           ( 3 << 2)
+#define BZ_OBJ_CLASS_MIN_WEARABLE_HELMET           ( 4 << 2)
+#define BZ_OBJ_CLASS_MIN_WEARABLE_GLASSES          ( 5 << 2)
+
+#define BZ_OBJ_CLASS_MIN_TOY_MASK                  (0x3f << 2)
+#define BZ_OBJ_CLASS_MIN_TOY_ROBOT                 ( 1 << 2)
+#define BZ_OBJ_CLASS_MIN_TOY_VEHICLE               ( 2 << 2)
+#define BZ_OBJ_CLASS_MIN_TOY_DOLL                  ( 3 << 2)
+#define BZ_OBJ_CLASS_MIN_TOY_CONTROLLER            ( 4 << 2)
+#define BZ_OBJ_CLASS_MIN_TOY_GAME                  ( 5 << 2)
+
+#define BZ_OBJ_CLASS_MIN_HEALTH_MASK               (0x3f << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_BLOOD_PRESSURE     ( 1 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_THERMOMETER        ( 2 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_SCALES             ( 3 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_GLUCOSE            ( 4 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_PULSE_OXIMITER     ( 5 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_HEART_RATE         ( 6 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_HEALTH_DATA_DISP   ( 7 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_STEP               ( 8 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_BODY_COMPOSITION   ( 9 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_PEAK_FLOW          (10 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_MEDICATION         (11 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_KNEE_PROSTHESIS    (12 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_ANKLE_PROSTHESIS   (13 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_GENERIC_HEALTH     (14 << 2)
+#define BZ_OBJ_CLASS_MIN_HEALTH_PRESONAL_MOBILITY  (15 << 2)
+
+
+extern Eldbus_Connection *bz_conn;
+
+void bz_init(void);
+void bz_shutdown(void);
+
+Obj  *bz_obj_add(const char *path);
+Obj  *bz_obj_find(const char *path);
+void  bz_obj_power_on(Obj *o);
+void  bz_obj_power_off(Obj *o);
+void  bz_obj_discoverable(Obj *o);
+void  bz_obj_undiscoverable(Obj *o);
+void  bz_obj_pairable(Obj *o);
+void  bz_obj_unpairable(Obj *o);
+void  bz_obj_trust(Obj *o);
+void  bz_obj_distrust(Obj *o);
+void  bz_obj_pair(Obj *o);
+void  bz_obj_pair_cancel(Obj *o);
+void  bz_obj_connect(Obj *o);
+void  bz_obj_disconnect(Obj *o);
+void  bz_obj_remove(Obj *o);
+void  bz_obj_profile_connect(Obj *o, const char *uuid);
+void  bz_obj_profile_disconnect(Obj *o, const char *uuid);
+void  bz_obj_ref(Obj *o);
+void  bz_obj_unref(Obj *o);
+void  bz_obj_discover_start(Obj *o);
+void  bz_obj_discover_stop(Obj *o);
+void  bz_obj_agent_request(Obj *o, const char *req, void (*fn) (Eldbus_Message 
*msg, const char *str), Eldbus_Message *ok_msg, Eldbus_Message *err_msg);
+
+void  bz_obj_init(void);
+void  bz_obj_shutdown(void);
+void  bz_obj_add_func_set(void (*fn) (Obj *o));
+
+void  bz_agent_msg_reply(Eldbus_Message *msg);
+void  bz_agent_msg_drop(Eldbus_Message *msg);
+Eldbus_Message *bz_agent_msg_err(Eldbus_Message *msg);
+Eldbus_Message *bz_agent_msg_ok(Eldbus_Message *msg);
+const char *bz_agent_msg_path(Eldbus_Message *msg);
+const char *bz_agent_msg_path_str(Eldbus_Message *msg, const char **str);
+const char *bz_agent_msg_path_u32(Eldbus_Message *msg, unsigned int *u32);
+const char *bz_agent_msg_path_u32_u16(Eldbus_Message *msg, unsigned int *u32, 
unsigned short *u16);
+void  bz_agent_msg_str_add(Eldbus_Message *msg, const char *str);
+void  bz_agent_msg_u32_add(Eldbus_Message *msg, unsigned int u32);
+
+void  bz_agent_init(void);
+void  bz_agent_shutdown(void);
+void  bz_agent_release_func_set(void (*fn) (void));
+void  bz_agent_cancel_func_set(void (*fn) (void));
+void  bz_agent_req_pin_func_set(void (*fn) (Eldbus_Message *msg));
+void  bz_agent_disp_pin_func_set(void (*fn) (Eldbus_Message *msg));
+void  bz_agent_req_pass_func_set(void (*fn) (Eldbus_Message *msg));
+void  bz_agent_disp_pass_func_set(void (*fn) (Eldbus_Message *msg));
+void  bz_agent_req_confirm_func_set(void (*fn) (Eldbus_Message *msg));
+void  bz_agent_req_auth_func_set(void (*fn) (Eldbus_Message *msg));
+void  bz_agent_auth_service_func_set(void (*fn) (Eldbus_Message *msg));
+#endif
diff --git a/src/modules/bluez5/bz_agent.c b/src/modules/bluez5/bz_agent.c
new file mode 100644
index 000000000..8eb0489cb
--- /dev/null
+++ b/src/modules/bluez5/bz_agent.c
@@ -0,0 +1,346 @@
+#include "bz.h"
+#include "e.h"
+
+static Eldbus_Service_Interface *agent_iface = NULL;
+static Eldbus_Proxy *agent_proxy = NULL;
+static void (*fn_release) (void) = NULL;
+static void (*fn_cancel) (void) = NULL;
+static void (*fn_req_pin) (Eldbus_Message *msg) = NULL;
+static void (*fn_disp_pin) (Eldbus_Message *msg) = NULL;
+static void (*fn_req_pass) (Eldbus_Message *msg) = NULL;
+static void (*fn_disp_pass) (Eldbus_Message *msg) = NULL;
+static void (*fn_req_confirm) (Eldbus_Message *msg) = NULL;
+static void (*fn_req_auth) (Eldbus_Message *msg) = NULL;
+static void (*fn_auth_service) (Eldbus_Message *msg) = NULL;
+
+static Eldbus_Message *
+cb_agent_release(const Eldbus_Service_Interface *iface EINA_UNUSED,
+                 const Eldbus_Message *msg)
+{
+   Eldbus_Message *reply = eldbus_message_method_return_new(msg);
+
+   if (fn_release) fn_release();
+   return reply;
+}
+
+static Eldbus_Message *
+cb_agent_cancel(const Eldbus_Service_Interface *iface EINA_UNUSED,
+                const Eldbus_Message *msg)
+{
+   Eldbus_Message *reply = eldbus_message_method_return_new(msg);
+
+   if (fn_cancel) fn_cancel();
+   return reply;
+}
+
+static Eldbus_Message *
+cb_agent_request_pin_code(const Eldbus_Service_Interface *iface EINA_UNUSED,
+                          const Eldbus_Message *msg)
+{
+   if (fn_req_pin) fn_req_pin((Eldbus_Message *)msg);
+   return NULL;
+}
+
+static Eldbus_Message *
+cb_agent_display_pin_code(const Eldbus_Service_Interface *iface EINA_UNUSED,
+                          const Eldbus_Message *msg)
+{
+   if (fn_disp_pin) fn_disp_pin((Eldbus_Message *)msg);
+   return NULL;
+}
+
+static Eldbus_Message *
+cb_agent_request_pass_key(const Eldbus_Service_Interface *iface EINA_UNUSED,
+                          const Eldbus_Message *msg)
+{
+   if (fn_req_pass) fn_req_pass((Eldbus_Message *)msg);
+   return NULL;
+}
+
+static Eldbus_Message *
+cb_agent_display_pass_key(const Eldbus_Service_Interface *iface EINA_UNUSED,
+                          const Eldbus_Message *msg)
+{
+   if (fn_disp_pass) fn_disp_pass((Eldbus_Message *)msg);
+   return NULL;
+}
+
+static Eldbus_Message *
+cb_agent_request_confirmation(const Eldbus_Service_Interface *iface 
EINA_UNUSED,
+                              const Eldbus_Message *msg)
+{
+   if (fn_req_confirm) fn_req_confirm((Eldbus_Message *)msg);
+   return NULL;
+}
+
+static Eldbus_Message *
+cb_agent_request_authorization(const Eldbus_Service_Interface *iface 
EINA_UNUSED,
+                               const Eldbus_Message *msg)
+{
+   if (fn_req_auth) fn_req_auth((Eldbus_Message *)msg);
+   return NULL;
+}
+
+static Eldbus_Message *
+cb_agent_authorize_service(const Eldbus_Service_Interface *iface EINA_UNUSED,
+                           const Eldbus_Message *msg)
+{
+   if (fn_auth_service) fn_auth_service((Eldbus_Message *)msg);
+   return NULL;
+/* Not done yet... don't even know what services are with bt...
+   Eldbus_Message *reply = eldbus_message_method_return_new(msg);
+   const char *path = NULL, *uuid = NULL;
+
+   printf("Agent authorize service\n");
+   if (!eldbus_message_arguments_get(msg, "os", &path, &uuid)) return reply;
+   printf("  %s %s\n", path, uuid);
+   // if ok return this reply, or make it an error...
+   // reply = eldbus_message_error_new(msg, "org.bluez.Error.Rejected", "");
+   return reply;
+   // really return NULL and defer above reply with:
+   // eldbus_connection_send(bz_conn, reply, NULL, NULL, -1);
+ */
+}
+
+static void
+cb_default(void *data EINA_UNUSED, const Eldbus_Message *msg,
+           Eldbus_Pending *pending EINA_UNUSED)
+{
+   const char *name, *text;
+
+   if (eldbus_message_error_get(msg, &name, &text))
+     {
+        // XXX: should have a visual e log...
+        e_util_dialog_show(_("Bluetooth"),
+                           _("Could not register default agent:<br>%s %s"),
+                           name, text);
+        return;
+     }
+}
+
+static void
+cb_register(void *data EINA_UNUSED, const Eldbus_Message *msg,
+            Eldbus_Pending *pending EINA_UNUSED)
+{
+   const char *name, *text;
+
+   if (eldbus_message_error_get(msg, &name, &text))
+     {
+        // XXX: should have a visual e log...
+        e_util_dialog_show(_("Bluetooth"),
+                           _("Could not register agent:<br>%s %s\n"),
+                           name, text);
+        return;
+     }
+   if (!agent_proxy) return;
+   eldbus_proxy_call(agent_proxy, "RequestDefaultAgent",
+                     cb_default, NULL, -1,
+                     "o", "/org/enlightenment/bluez5/agent");
+}
+
+static void
+cb_unregister(void *data EINA_UNUSED, const Eldbus_Message *msg,
+            Eldbus_Pending *pending EINA_UNUSED)
+{
+   const char *name, *text;
+
+   if (agent_proxy)
+     {
+        eldbus_proxy_unref(agent_proxy);
+        agent_proxy = NULL;
+     }
+   if (agent_iface)
+     {
+        eldbus_service_object_unregister(agent_iface);
+        agent_iface = NULL;
+     }
+   if (eldbus_message_error_get(msg, &name, &text))
+     {
+        // just debug for developers
+        printf("Could not unregister agent.\n %s:\n %s\n", name, text);
+        return;
+     }
+}
+
+static const Eldbus_Method agent_methods[] = {
+   { "Release",              NULL,                                             
                      NULL,                            cb_agent_release, 0 },
+   { "RequestPinCode",       ELDBUS_ARGS({ "o", "device" }),                   
                      ELDBUS_ARGS({ "s", "pincode" }), 
cb_agent_request_pin_code, 0 },
+   { "DisplayPinCode",       ELDBUS_ARGS({ "o", "device" }, { "s", "pincode" 
}),                     NULL,                            
cb_agent_display_pin_code, 0 },
+   { "RequestPasskey",       ELDBUS_ARGS({ "o", "device" }),                   
                      ELDBUS_ARGS({ "u", "passkey" }), 
cb_agent_request_pass_key, 0 },
+   { "DisplayPasskey",       ELDBUS_ARGS({ "o", "device" }, { "u", "passkey" 
}, { "q", "entered" }), NULL,                            
cb_agent_display_pass_key, 0 },
+   { "RequestConfirmation",  ELDBUS_ARGS({ "o", "device" }, { "u", "passkey" 
}),                     NULL,                            
cb_agent_request_confirmation, 0 },
+   { "RequestAuthorization", ELDBUS_ARGS({ "o", "device" }),                   
                      NULL,                            
cb_agent_request_authorization, 0 },
+   { "AuthorizeService",     ELDBUS_ARGS({ "o", "device" }, { "s", "uuid" }),  
                      NULL,                            
cb_agent_authorize_service, 0 },
+   { "Cancel",               NULL,                                             
                      NULL,                            cb_agent_cancel, 0 },
+
+   { NULL,                   NULL, NULL, NULL, 0 }
+};
+static const Eldbus_Service_Interface_Desc agent_desc = {
+   "org.bluez.Agent1", agent_methods, NULL, NULL, NULL, NULL
+};
+
+void
+bz_agent_msg_reply(Eldbus_Message *msg)
+{
+   if (!bz_conn)
+     {
+        eldbus_message_unref(msg);
+        return;
+     }
+   eldbus_connection_send(bz_conn, msg, NULL, NULL, -1);
+}
+
+void
+bz_agent_msg_drop(Eldbus_Message *msg)
+{
+   eldbus_message_unref(msg);
+}
+
+Eldbus_Message *
+bz_agent_msg_err(Eldbus_Message *msg)
+{
+   return eldbus_message_error_new(msg, "org.bluez.Error.Rejected", "");
+}
+
+Eldbus_Message *
+bz_agent_msg_ok(Eldbus_Message *msg)
+{
+   return eldbus_message_method_return_new(msg);
+}
+
+const char *
+bz_agent_msg_path(Eldbus_Message *msg)
+{
+   const char *s = NULL;
+
+   if (!eldbus_message_arguments_get(msg, "o", &s)) return NULL;
+   return s;
+}
+
+const char *
+bz_agent_msg_path_str(Eldbus_Message *msg, const char **str)
+{
+   const char *s = NULL, *s2 = NULL;
+
+   if (!eldbus_message_arguments_get(msg, "os", &s, &s2)) return NULL;
+   if (str) *str = s2;
+   return s;
+}
+
+const char *
+bz_agent_msg_path_u32(Eldbus_Message *msg, unsigned int *u32)
+{
+   const char *s = NULL;
+   unsigned int uu32 = 0;
+
+   if (!eldbus_message_arguments_get(msg, "ou", &s, &uu32)) return NULL;
+   if (u32) *u32 = uu32;
+   return s;
+}
+
+const char *
+bz_agent_msg_path_u32_u16(Eldbus_Message *msg, unsigned int *u32, unsigned 
short *u16)
+{
+   const char *s = NULL;
+   unsigned int uu32 = 0;
+   unsigned short uu16 = 0;
+
+   if (!eldbus_message_arguments_get(msg, "ouq", &s, &uu32, &uu16)) return 
NULL;
+   if (u32) *u32 = uu32;
+   if (u16) *u16 = uu16;
+   return s;
+}
+
+void
+bz_agent_msg_str_add(Eldbus_Message *msg, const char *str)
+{
+   eldbus_message_arguments_append(msg, "s", str);
+}
+
+void
+bz_agent_msg_u32_add(Eldbus_Message *msg, unsigned int u32)
+{
+   eldbus_message_arguments_append(msg, "u", &u32);
+}
+
+void
+bz_agent_init(void)
+{
+   Eldbus_Object *obj;
+
+   obj = eldbus_object_get(bz_conn, "org.bluez", "/org/bluez");
+   agent_proxy = eldbus_proxy_get(obj, "org.bluez.AgentManager1");
+   agent_iface = eldbus_service_interface_register
+     (bz_conn, "/org/enlightenment/bluez5/agent", &agent_desc);
+   if (agent_proxy)
+     eldbus_proxy_call(agent_proxy, "RegisterAgent",
+                       cb_register, NULL, -1,
+                       "os", "/org/enlightenment/bluez5/agent",
+                       "KeyboardDisplay");
+   else
+     e_util_dialog_show(_("Bluetooth"),
+                        _("Could not call RegisterAgent\n"));
+}
+
+void
+bz_agent_shutdown(void)
+{
+   if (!agent_proxy) return;
+   eldbus_proxy_call(agent_proxy, "UnregisterAgent",
+                     cb_unregister, NULL, -1,
+                     "o", "/org/enlightenment/bluez5/agent");
+}
+
+void
+bz_agent_release_func_set(void (*fn) (void))
+{
+   fn_release = fn;
+}
+
+void
+bz_agent_cancel_func_set(void (*fn) (void))
+{
+   fn_cancel = fn;
+}
+
+void
+bz_agent_req_pin_func_set(void (*fn) (Eldbus_Message *msg))
+{
+   fn_req_pin = fn;
+}
+
+void
+bz_agent_disp_pin_func_set(void (*fn) (Eldbus_Message *msg))
+{
+   fn_disp_pin = fn;
+}
+
+void
+bz_agent_req_pass_func_set(void (*fn) (Eldbus_Message *msg))
+{
+   fn_req_pass = fn;
+}
+
+void
+bz_agent_disp_pass_func_set(void (*fn) (Eldbus_Message *msg))
+{
+   fn_disp_pass = fn;
+}
+
+void
+bz_agent_req_confirm_func_set(void (*fn) (Eldbus_Message *msg))
+{
+   fn_req_confirm = fn;
+}
+
+void
+bz_agent_req_auth_func_set(void (*fn) (Eldbus_Message *msg))
+{
+   fn_req_auth = fn;
+}
+
+void
+bz_agent_auth_service_func_set(void (*fn) (Eldbus_Message *msg))
+{
+   fn_auth_service = fn;
+}
diff --git a/src/modules/bluez5/bz_obj.c b/src/modules/bluez5/bz_obj.c
new file mode 100644
index 000000000..24552bb2b
--- /dev/null
+++ b/src/modules/bluez5/bz_obj.c
@@ -0,0 +1,760 @@
+#include "bz.h"
+
+static Eldbus_Proxy *objman_proxy = NULL;
+static Eldbus_Signal_Handler *sig_ifadd = NULL;
+static Eldbus_Signal_Handler *sig_ifdel = NULL;
+static Eldbus_Pending *pend_getobj = NULL;
+static Eina_Hash *obj_table = NULL;
+static void (*fn_obj_add) (Obj *o) = NULL;
+
+/*
+static void
+cb_obj_prop_mandata(void *data, const void *key, Eldbus_Message_Iter *var)
+{
+   Obj *o = data;
+   unsigned short *skey = key;
+
+   printf("    M KEY %x\n", (int)*skey);
+}
+*/
+
+static void
+cb_obj_prop_entry(void *data, const void *key, Eldbus_Message_Iter *var)
+{
+   Obj *o = data;
+   const char *skey = key;
+
+   if (!strcmp(skey, "Paired"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->paired = val;
+     }
+   if (!strcmp(skey, "Connected"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->connected = val;
+     }
+   if (!strcmp(skey, "Trusted"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->trusted = val;
+     }
+   if (!strcmp(skey, "Blocked"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->blocked = val;
+     }
+   if (!strcmp(skey, "LegacyPairing"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->legacy_pairing = val;
+     }
+   if (!strcmp(skey, "ServicesResolved"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->services_resolved = val;
+     }
+   if (!strcmp(skey, "Address"))
+     {
+        const char *val = NULL;
+        if (eldbus_message_iter_arguments_get(var, "s", &val))
+          o->address = eina_stringshare_add(val);
+     }
+   if (!strcmp(skey, "AddressType"))
+     {
+        const char *val = NULL;
+        if (eldbus_message_iter_arguments_get(var, "s", &val))
+          o->address_type = eina_stringshare_add(val);
+     }
+   if (!strcmp(skey, "Name"))
+     {
+        const char *val = NULL;
+        if (eldbus_message_iter_arguments_get(var, "s", &val))
+          o->name = eina_stringshare_add(val);
+     }
+   if (!strcmp(skey, "Icon"))
+     {
+        const char *val = NULL;
+        if (eldbus_message_iter_arguments_get(var, "s", &val))
+          o->icon = eina_stringshare_add(val);
+     }
+   if (!strcmp(skey, "Alias"))
+     {
+        const char *val = NULL;
+        if (eldbus_message_iter_arguments_get(var, "s", &val))
+          o->alias = eina_stringshare_add(val);
+     }
+   if (!strcmp(skey, "Modalias"))
+     {
+        const char *val = NULL;
+        if (eldbus_message_iter_arguments_get(var, "s", &val))
+          o->modalias = eina_stringshare_add(val);
+     }
+   if (!strcmp(skey, "Adapter"))
+     {
+        const char *val = NULL;
+        if (eldbus_message_iter_arguments_get(var, "o", &val))
+          o->adapter = eina_stringshare_add(val);
+     }
+   if (!strcmp(skey, "Class"))
+     {
+        unsigned int val = 0;
+        if (eldbus_message_iter_arguments_get(var, "u", &val))
+          o->klass = val;
+     }
+   if (!strcmp(skey, "Appearance"))
+     {
+        unsigned short val = 0;
+        if (eldbus_message_iter_arguments_get(var, "q", &val))
+          o->appearance = val;
+     }
+   if (!strcmp(skey, "RSSI"))
+     {
+        short val = 0;
+        if (eldbus_message_iter_arguments_get(var, "n", &val))
+          o->rssi = val;
+     }
+   if (!strcmp(skey, "TxPower"))
+     {
+        unsigned short val = 0;
+        if (eldbus_message_iter_arguments_get(var, "n", &val))
+          o->txpower = val;
+     }
+   if (!strcmp(skey, "UUIDs"))
+     {
+        Eldbus_Message_Iter *array = NULL;
+
+        if (eldbus_message_iter_arguments_get(var, "as", &array))
+          {
+             const char *val = NULL;
+
+             while (eldbus_message_iter_get_and_next(array, 's', &val))
+               {
+                  if (!o->uuids) o->uuids = eina_array_new(1);
+                  eina_array_push(o->uuids, eina_stringshare_add(val));
+               }
+          }
+     }
+   if (!strcmp(skey, "Discoverable"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->discoverable = val;
+     }
+   if (!strcmp(skey, "Discovering"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->discovering = val;
+     }
+   if (!strcmp(skey, "Pairable"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->pairable = val;
+     }
+   if (!strcmp(skey, "Powered"))
+     {
+        Eina_Bool val = EINA_FALSE;
+        if (eldbus_message_iter_arguments_get(var, "b", &val))
+          o->powered = val;
+     }
+   if (!strcmp(skey, "DiscoverableTimeout"))
+     {
+        unsigned int val = 0;
+        if (eldbus_message_iter_arguments_get(var, "u", &val))
+          o->discoverable_timeout = val;
+     }
+   if (!strcmp(skey, "PairableTimeout"))
+     {
+        unsigned int val = 0;
+        if (eldbus_message_iter_arguments_get(var, "u", &val))
+          o->pairable_timeout = val;
+     }
+   // dict ManufacturerData [readonly, optional]
+   //  Manufacturer specific advertisement data. Keys are
+   //  16 bits Manufacturer ID followed by its byte array
+   //  value.
+/*
+   if (!strcmp(skey, "ManufacturerData"))
+     {
+        Eldbus_Message_Iter *array = NULL;
+
+        if (eldbus_message_iter_arguments_get(var, "a{qv}", &array))
+          eldbus_message_iter_dict_iterate(array, "qv", cb_obj_prop_mandata, 
o);
+     }
+ */
+   // dict ServiceData [readonly, optional]
+   //  Service advertisement data. Keys are the UUIDs in
+   //  string format followed by its byte array value.
+   // 
+   // array{byte} AdvertisingFlags [readonly, experimental]
+   //  The Advertising Data Flags of the remote device.
+   // 
+   // dict AdvertisingData [readonly, experimental]
+   //  The Advertising Data of the remote device. Keys are
+   //  are 8 bits AD Type followed by data as byte array.
+}
+
+static void
+_obj_clear(Obj *o)
+{
+   o->paired = EINA_FALSE;
+   o->connected = EINA_FALSE;
+   o->trusted = EINA_FALSE;
+   o->blocked = EINA_FALSE;
+   o->legacy_pairing = EINA_FALSE;
+   o->services_resolved = EINA_FALSE;
+   eina_stringshare_del(o->address);
+   o->address = NULL;
+   eina_stringshare_del(o->address_type);
+   o->address_type = NULL;
+   eina_stringshare_del(o->name);
+   o->name = NULL;
+   eina_stringshare_del(o->icon);
+   o->icon = NULL;
+   eina_stringshare_del(o->alias);
+   o->alias = NULL;
+   eina_stringshare_del(o->adapter);
+   o->adapter = NULL;
+   eina_stringshare_del(o->modalias);
+   o->modalias = NULL;
+   eina_stringshare_del(o->modalias);
+   o->modalias = NULL;
+   o->klass = 0;
+   o->appearance = 0;
+   o->txpower = 0;
+   o->rssi = 0;
+   if (o->uuids)
+     {
+        const char *val;
+
+        while ((val = eina_array_pop(o->uuids)))
+          eina_stringshare_del(val);
+        eina_array_free(o->uuids);
+        o->uuids = NULL;
+     }
+}
+
+#define ERR_PRINT(str) \
+   do { const char *name, *text; \
+      if (eldbus_message_error_get(msg, &name, &text)) { \
+         printf("Error: %s.\n %s:\n %s\n", str, name, text); \
+         return; \
+      } \
+   } while(0)
+
+
+static void
+cb_obj_prop(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending 
EINA_UNUSED)
+{
+   Obj *o = data;
+   Eldbus_Message_Iter *array;
+
+   if (eldbus_message_error_get(msg, NULL, NULL)) return;
+   _obj_clear(o);
+   if (eldbus_message_arguments_get(msg, "a{sv}", &array))
+     eldbus_message_iter_dict_iterate(array, "sv", cb_obj_prop_entry, o);
+   bz_obj_ref(o);
+   if (!o->add_called)
+     {
+        o->add_called = EINA_TRUE;
+        if (fn_obj_add) fn_obj_add(o);
+     }
+   if (o->fn_change) o->fn_change(o);
+   bz_obj_unref(o);
+}
+
+static void
+cb_obj_prop_changed(void *data EINA_UNUSED, const Eldbus_Message *msg 
EINA_UNUSED)
+{
+   Obj *o = data;
+   if (!o->proxy) return;
+   eldbus_proxy_property_get_all(o->proxy, cb_obj_prop, o);
+}
+
+Obj *
+bz_obj_add(const char *path)
+{
+   Eldbus_Object *obj;
+
+   Obj *o = calloc(1, sizeof(Obj));
+   o->ref = 1;
+   o->path = eina_stringshare_add(path);
+   obj = eldbus_object_get(bz_conn, "org.bluez", o->path);
+   o->type = BZ_OBJ_UNKNOWN;
+   o->in_table = EINA_TRUE;
+   eina_hash_add(obj_table, o->path, o);
+   if (!strcmp(o->path, "/org/bluez"))
+     {
+        o->proxy = eldbus_proxy_get(obj, "org.bluez.AgentManager1");
+        o->type = BZ_OBJ_BLUEZ;
+        o->add_called = EINA_TRUE;
+        bz_obj_ref(o);
+        if (fn_obj_add) fn_obj_add(o);
+        bz_obj_unref(o);
+        goto done;
+     }
+   // all devices are /org/bluez/XXX/dev_XXX so look for /dev_
+   else if (strstr(o->path, "/dev_"))
+     {
+        o->proxy = eldbus_proxy_get(obj, "org.bluez.Device1");
+        o->type = BZ_OBJ_DEVICE;
+        if (o->proxy)
+          {
+             eldbus_proxy_property_get_all(o->proxy, cb_obj_prop, o);
+             o->prop_proxy = eldbus_proxy_get(obj,
+                                              
"org.freedesktop.DBus.Properties");
+             if (o->prop_proxy)
+               o->prop_sig = eldbus_proxy_signal_handler_add(o->prop_proxy,
+                                                             
"PropertiesChanged",
+                                                             
cb_obj_prop_changed, o);
+          }
+        goto done;
+     }
+   // all dadapters begin with /org/bluez/
+   else if (!strncmp(o->path, "/org/bluez/", 11))
+     {
+        o->proxy = eldbus_proxy_get(obj, "org.bluez.Adapter1");
+        o->type = BZ_OBJ_ADAPTER;
+        if (o->proxy)
+          {
+             eldbus_proxy_property_get_all(o->proxy, cb_obj_prop, o);
+             o->prop_proxy = eldbus_proxy_get(obj,
+                                              
"org.freedesktop.DBus.Properties");
+             if (o->prop_proxy)
+               o->prop_sig = eldbus_proxy_signal_handler_add(o->prop_proxy,
+                                                             
"PropertiesChanged",
+                                                             
cb_obj_prop_changed, o);
+          }
+        goto done;
+     }
+done:
+   return o;
+}
+
+Obj *
+bz_obj_find(const char *path)
+{
+   return eina_hash_find(obj_table, path);
+}
+
+static void
+cb_power_on(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Power On");
+}
+
+void
+bz_obj_power_on(Obj *o)
+{
+   Eina_Bool val = EINA_TRUE;
+   if (!o->proxy) return;
+   eldbus_proxy_property_set
+     (o->proxy, "Powered", "b", (void *)(uintptr_t)val, cb_power_on, o);
+}
+
+static void
+cb_power_off(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Power Off");
+}
+
+void
+bz_obj_power_off(Obj *o)
+{
+   Eina_Bool val = EINA_FALSE;
+   if (!o->proxy) return;
+   eldbus_proxy_property_set
+     (o->proxy, "Powered", "b", (void *)(uintptr_t)val, cb_power_off, o);
+}
+
+static void
+cb_discoverable(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Discoverable");
+}
+
+void
+bz_obj_discoverable(Obj *o)
+{
+   Eina_Bool val = EINA_TRUE;
+   if (!o->proxy) return;
+   eldbus_proxy_property_set
+     (o->proxy, "Discoverable", "b", (void *)(uintptr_t)val, cb_discoverable, 
o);
+}
+
+static void
+cb_undiscoverable(void *data EINA_UNUSED, const Eldbus_Message *msg 
EINA_UNUSED, Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Undiscoverable");
+}
+
+void
+bz_obj_undiscoverable(Obj *o)
+{
+   Eina_Bool val = EINA_FALSE;
+   if (!o->proxy) return;
+   eldbus_proxy_property_set
+     (o->proxy, "Discoverable", "b", (void *)(uintptr_t)val, 
cb_undiscoverable, o);
+}
+
+static void
+cb_pairable(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Pairable");
+}
+
+void
+bz_obj_pairable(Obj *o)
+{
+   Eina_Bool val = EINA_TRUE;
+   if (!o->proxy) return;
+   eldbus_proxy_property_set
+     (o->proxy, "Pairable", "b", (void *)(uintptr_t)val, cb_pairable, o);
+}
+
+static void
+cb_unpairable(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Unpairable");
+}
+
+void
+bz_obj_unpairable(Obj *o)
+{
+   Eina_Bool val = EINA_FALSE;
+   if (!o->proxy) return;
+   eldbus_proxy_property_set
+     (o->proxy, "Pairable", "b", (void *)(uintptr_t)val, cb_unpairable, o);
+}
+
+static void
+cb_trust(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Trust");
+}
+
+void
+bz_obj_trust(Obj *o)
+{
+   Eina_Bool val = EINA_TRUE;
+   if (!o->proxy) return;
+   eldbus_proxy_property_set
+     (o->proxy, "Trusted", "b", (void *)(uintptr_t)val, cb_trust, o);
+}
+
+static void
+cb_distrust(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Distrust");
+}
+
+void
+bz_obj_distrust(Obj *o)
+{
+   Eina_Bool val = EINA_FALSE;
+   if (!o->proxy) return;
+   eldbus_proxy_property_set
+     (o->proxy, "Trusted", "b", (void *)(uintptr_t)val, cb_distrust, o);
+}
+
+static void
+cb_pair(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Pair");
+}
+
+void
+bz_obj_pair(Obj *o)
+{
+   if (!o->proxy) return;
+   eldbus_proxy_call(o->proxy, "Pair", cb_pair, o, -1, "");
+}
+
+static void
+cb_pair_cancel(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Pair Cancel");
+}
+
+void
+bz_obj_pair_cancel(Obj *o)
+{
+   if (!o->proxy) return;
+   eldbus_proxy_call
+     (o->proxy, "CancelPairing", cb_pair_cancel, o, -1, "");
+}
+
+static void
+cb_connect(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Connect");
+}
+
+void
+bz_obj_connect(Obj *o)
+{
+   if (!o->proxy) return;
+   eldbus_proxy_call
+     (o->proxy, "Connect", cb_connect, o, -1, "");
+}
+
+static void
+cb_disconnect(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Disconnect");
+}
+
+void
+bz_obj_disconnect(Obj *o)
+{
+   if (!o->proxy) return;
+   eldbus_proxy_call
+     (o->proxy, "Disconnect", cb_disconnect, o, -1, "");
+}
+/*
+void
+bz_obj_profile_connect(Obj *o, const char *uuid)
+{
+   if (!o->proxy) return;
+   eldbus_proxy_call(o->proxy, "ConnectProfile", NULL, NULL, -1, "s", uuid);
+}
+
+void
+bz_obj_profile_disconnect(Obj *o, const char *uuid)
+{
+   if (!o->proxy) return;
+   eldbus_proxy_call(o->proxy, "DisconnectProfile", NULL, NULL, -1, "s", uuid);
+}
+*/
+static void
+cb_remove(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Remove");
+}
+
+void
+bz_obj_remove(Obj *o)
+{
+   if (o->adapter)
+     {
+        Obj *adapter = bz_obj_find(o->adapter);
+        if (adapter)
+          {
+             if (!adapter->proxy) return;
+             eldbus_proxy_call(adapter->proxy, "RemoveDevice",
+                               cb_remove, adapter, -1,
+                               "o", o->path);
+          }
+     }
+}
+
+void
+bz_obj_ref(Obj *o)
+{
+   o->ref++;
+}
+
+void
+bz_obj_unref(Obj *o)
+{
+   o->ref--;
+   if (o->ref > 0) return;
+   if (o->in_table)
+     {
+        o->in_table = EINA_FALSE;
+        eina_hash_del(obj_table, o->path, o);
+     }
+   _obj_clear(o);
+   if (o->prop_sig)
+     {
+        eldbus_signal_handler_del(o->prop_sig);
+        o->prop_sig = NULL;
+     }
+   if (o->proxy)
+     {
+        eldbus_proxy_unref(o->proxy);
+        o->proxy = NULL;
+     }
+   if (o->prop_proxy)
+     {
+        eldbus_proxy_unref(o->prop_proxy);
+        o->prop_proxy = NULL;
+     }
+   if (o->path)
+     {
+        eina_stringshare_del(o->path);
+        o->path = NULL;
+     }
+   if (o->agent_request)
+     {
+        eina_stringshare_del(o->agent_request);
+        o->agent_request = NULL;
+     }
+   if (o->agent_msg_err)
+     {
+        bz_agent_msg_drop(o->agent_msg_err);
+        o->agent_msg_err = NULL;
+     }
+   if (o->agent_msg_ok)
+     {
+        bz_agent_msg_drop(o->agent_msg_ok);
+        o->agent_msg_ok = NULL;
+     }
+   free(o);
+}
+
+static void
+cb_discovery_start(void *data EINA_UNUSED, const Eldbus_Message *msg, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Discovery Start");
+}
+
+void
+bz_obj_discover_start(Obj *o)
+{
+   if (!o->proxy) return;
+   eldbus_proxy_call
+     (o->proxy, "StartDiscovery", cb_discovery_start, o, -1, "");
+}
+
+static void
+cb_discovery_stop(void *data EINA_UNUSED, const Eldbus_Message *msg, 
Eldbus_Pending *pending EINA_UNUSED)
+{
+   ERR_PRINT("Discovery Stop");
+}
+
+void
+bz_obj_discover_stop(Obj *o)
+{
+   if (!o->proxy) return;
+   eldbus_proxy_call
+     (o->proxy, "StopDiscovery", cb_discovery_stop, o, -1, "");
+}
+
+void
+bz_obj_agent_request(Obj *o, const char *req, void (*fn) (Eldbus_Message *msg, 
const char *str), Eldbus_Message *msg_ok, Eldbus_Message *msg_err)
+{
+   if (o->agent_msg_ok) bz_agent_msg_drop(o->agent_msg_ok);
+   if (o->agent_msg_err) bz_agent_msg_reply(o->agent_msg_err);
+   o->agent_msg_ok = msg_ok;
+   o->agent_msg_err = msg_err;
+   o->agent_entry_fn = fn;
+   o->agent_alert = EINA_TRUE;
+   eina_stringshare_replace(&(o->agent_request), req);
+   bz_obj_ref(o);
+   if (o->fn_change) o->fn_change(o);
+   bz_obj_unref(o);
+}
+
+static void
+cb_obj_add(void *data EINA_UNUSED, const Eldbus_Message *msg)
+{
+   const char *path = NULL;
+
+   if (!eldbus_message_arguments_get(msg, "o", &path)) return;
+   if (bz_obj_find(path)) return;
+   bz_obj_add(path);
+}
+
+static void
+cb_obj_del(void *data EINA_UNUSED, const Eldbus_Message *msg)
+{
+   Obj *o;
+   const char *path = NULL;
+
+   if (!eldbus_message_arguments_get(msg, "o", &path)) return;
+   o = bz_obj_find(path);
+   if (o)
+     {
+        bz_obj_ref(o);
+        if (o->fn_del) o->fn_del(o);
+        bz_obj_unref(o);
+        bz_obj_unref(o);
+     }
+}
+
+static void
+cb_getobj(void *data EINA_UNUSED, const Eldbus_Message *msg,
+          Eldbus_Pending *pending EINA_UNUSED)
+{
+   Eldbus_Message_Iter *prop, *dict;
+
+   pend_getobj = NULL;
+   ERR_PRINT("Get Objects");
+   if (eldbus_message_arguments_get(msg, "a{oa{sa{sv}}}", &prop))
+     {
+        while (eldbus_message_iter_get_and_next(prop, 'e', &dict))
+          {
+             const char *path;
+
+             path = NULL;
+             if (!eldbus_message_iter_arguments_get(dict, "o", &path))
+               {
+                  return;
+               }
+             bz_obj_add(path);
+          }
+     }
+}
+
+static void
+_obj_hash_free(Obj *o)
+{
+   o->in_table = 0;
+   bz_obj_unref(o);
+}
+
+void
+bz_obj_init(void)
+{
+   Eldbus_Object *obj;
+
+   obj_table = eina_hash_string_superfast_new((void *)_obj_hash_free);
+
+   obj = eldbus_object_get(bz_conn, "org.bluez", "/");
+   objman_proxy = eldbus_proxy_get(obj, "org.freedesktop.DBus.ObjectManager");
+   sig_ifadd = eldbus_proxy_signal_handler_add(objman_proxy, "InterfacesAdded",
+                                               cb_obj_add, NULL);
+   sig_ifdel = eldbus_proxy_signal_handler_add(objman_proxy, 
"InterfacesRemoved",
+                                               cb_obj_del, NULL);
+   pend_getobj = eldbus_proxy_call(objman_proxy, "GetManagedObjects",
+                                   cb_getobj, NULL, -1, "");
+}
+
+void
+bz_obj_shutdown(void)
+{
+   eina_hash_free(obj_table);
+   obj_table = NULL;
+   if (pend_getobj)
+     {
+        eldbus_pending_cancel(pend_getobj);
+        pend_getobj = NULL;
+     }
+   if (sig_ifadd)
+     {
+        eldbus_signal_handler_del(sig_ifadd);
+        sig_ifadd = NULL;
+     }
+   if (sig_ifdel)
+     {
+        eldbus_signal_handler_del(sig_ifdel);
+        sig_ifdel = NULL;
+     }
+   eldbus_proxy_unref(objman_proxy);
+   objman_proxy = NULL;
+}
+
+void
+bz_obj_add_func_set(void (*fn) (Obj *o))
+{
+   fn_obj_add = fn;
+}
diff --git a/src/modules/bluez5/e-module-bluez5.edj 
b/src/modules/bluez5/e-module-bluez5.edj
new file mode 100644
index 000000000..383b4460e
Binary files /dev/null and b/src/modules/bluez5/e-module-bluez5.edj differ
diff --git a/src/modules/bluez5/e_mod_agent.c b/src/modules/bluez5/e_mod_agent.c
new file mode 100644
index 000000000..a5524ad11
--- /dev/null
+++ b/src/modules/bluez5/e_mod_agent.c
@@ -0,0 +1,143 @@
+#include "e_mod_main.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+static void
+cb_get_pass(Eldbus_Message *msg, const char *str)
+{
+   if (!str) return;
+   bz_agent_msg_str_add(msg, str);
+}
+
+static void
+cb_get_pin(Eldbus_Message *msg, const char *str)
+{
+   unsigned int pin;
+   if (!str) return;
+   pin = atoi(str);
+   bz_agent_msg_u32_add(msg, pin);
+}
+
+void
+ebluez5_agent_agent_release(void)
+{
+   // just debugging
+   printf("BZ5 Agent Release\n");
+}
+
+void
+ebluez5_agent_agent_cancel(void)
+{
+   // just debugging
+   printf("BZ5 Agent Cancel\n");
+}
+
+void
+ebluez5_agent_agent_req_pin(Eldbus_Message *msg)
+{
+   const char *path;
+   Obj *o;
+
+   if (!(path = bz_agent_msg_path(msg))) goto error;
+   if (!(o = bz_obj_find(path))) goto error;
+   bz_obj_agent_request(o, _("Supply PIN"), cb_get_pass,
+                        bz_agent_msg_ok(msg), bz_agent_msg_err(msg));
+   return;
+error:
+   bz_agent_msg_reply(bz_agent_msg_err(msg));
+}
+
+void
+ebluez5_agent_agent_disp_pin(Eldbus_Message *msg)
+{
+   const char *path, *s = "";
+   Obj *o;
+   char buf[1024];
+
+   if (!(path = bz_agent_msg_path_str(msg, &s))) goto error;
+   if (!(o = bz_obj_find(path))) goto error;
+   snprintf(buf, sizeof(buf), _("Pair? PIN: <hilight>%s</hilight>"), s);
+   bz_obj_agent_request(o, buf, NULL,
+                        bz_agent_msg_ok(msg), bz_agent_msg_err(msg));
+   return;
+error:
+   bz_agent_msg_reply(bz_agent_msg_err(msg));
+}
+
+void
+ebluez5_agent_req_pass(Eldbus_Message *msg)
+{
+   const char *path;
+   Obj *o;
+
+   if (!(path = bz_agent_msg_path(msg))) goto error;
+   if (!(o = bz_obj_find(path))) goto error;
+   bz_obj_agent_request(o, _("Enter PIN"), cb_get_pin,
+                        bz_agent_msg_ok(msg), bz_agent_msg_err(msg));
+   return;
+error:
+   bz_agent_msg_reply(bz_agent_msg_err(msg));
+}
+
+void
+ebluez5_agent_disp_pass(Eldbus_Message *msg)
+{
+   const char *path;
+   unsigned int pin = 0;
+   unsigned short entered = 0;
+   Obj *o;
+   char buf[1024];
+
+   if (!(path = bz_agent_msg_path_u32_u16(msg, &pin, &entered))) goto error;
+   if (!(o = bz_obj_find(path))) goto error;
+   snprintf(buf, sizeof(buf), _("Pair? PIN: <hilight>%06u</hilight>"), pin);
+   bz_obj_agent_request(o, buf, NULL,
+                        bz_agent_msg_ok(msg), bz_agent_msg_err(msg));
+   return;
+error:
+   bz_agent_msg_reply(bz_agent_msg_err(msg));
+}
+
+void
+ebluez5_agent_req_confirm(Eldbus_Message *msg)
+{
+   const char *path;
+   unsigned int pin = 0;
+   Obj *o;
+   char buf[1024];
+
+   if (!(path = bz_agent_msg_path_u32(msg, &pin))) goto error;
+   if (!(o = bz_obj_find(path))) goto error;
+   snprintf(buf, sizeof(buf), _("Pair? PIN: <hilight>%06u</hilight>"), pin);
+   bz_obj_agent_request(o, buf, NULL,
+                        bz_agent_msg_ok(msg), bz_agent_msg_err(msg));
+   return;
+error:
+   bz_agent_msg_reply(bz_agent_msg_err(msg));
+}
+
+void
+ebluez5_agent_req_auth(Eldbus_Message *msg)
+{
+   const char *path;
+   Obj *o;
+
+   if (!(path = bz_agent_msg_path(msg))) goto error;
+   if (!(o = bz_obj_find(path))) goto error;
+   bz_obj_agent_request(o, _("Connect?"), NULL,
+                        bz_agent_msg_ok(msg), bz_agent_msg_err(msg));
+   return;
+error:
+   bz_agent_msg_reply(bz_agent_msg_err(msg));
+}
+
+void
+ebluez5_agent_auth_service(Eldbus_Message *msg)
+{
+   // if "ask for service" on then ask, otherwise always auth
+   // always auth:
+//   if (!(path = bz_agent_msg_path_str(msg, &s))) goto error;
+   Eldbus_Message *ok;
+   ok = bz_agent_msg_ok(msg);
+   bz_agent_msg_reply(ok);
+}
diff --git a/src/modules/bluez5/e_mod_main.c b/src/modules/bluez5/e_mod_main.c
new file mode 100644
index 000000000..6d779e0ea
--- /dev/null
+++ b/src/modules/bluez5/e_mod_main.c
@@ -0,0 +1,305 @@
+#include "e_mod_main.h"
+
+static Eina_List *instances = NULL;
+static E_Module *mod = NULL;
+
+/* Local config */
+static E_Config_DD *conf_edd = NULL;
+Config *ebluez5_config = NULL;
+
+E_API E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Bluez5"};
+
+static void
+_mod_icon_set(Evas_Object *base, Eina_Bool gadget)
+{
+   char edj_path[4096], *group;
+
+   // XXX: hack for now until we make the icon do things and have it
+   // in theme in efl
+   snprintf(edj_path, sizeof(edj_path), "%s/e-module-bluez5.edj", mod->dir);
+   if (1) group = "e/modules/bluez5/main";
+   else group = "e/modules/bluez5/inactive";
+
+   if (!e_theme_edje_object_set(base, "base/theme/modules/bluez5", group))
+     {
+        if (gadget)
+          elm_layout_file_set(base, edj_path, group);
+        else
+          edje_object_file_set(base, edj_path, group);
+     }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static void
+_gad_popup_dismiss(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+   Instance *inst = data;
+   E_FREE_FUNC(obj, evas_object_del);
+   inst->pop = NULL;
+}
+
+static void
+_gad_popup_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, 
void *event_info EINA_UNUSED)
+{
+   Instance *inst = data;
+   inst->pop = NULL;
+}
+
+static void
+_gad_popup_do(Instance *inst)
+{
+   Evas_Object *o;
+
+   if (inst->pop) return;
+
+   inst->pop = o = elm_ctxpopup_add(e_comp->elm);
+   elm_object_style_set(o, "noblock");
+   evas_object_smart_callback_add(o, "dismissed", _gad_popup_dismiss, inst);
+   evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _gad_popup_del, inst);
+
+   inst->popcontent = o = ebluez5_popup_content_add(e_comp->elm, inst);
+   elm_object_content_set(inst->pop, o);
+   evas_object_show(o);
+
+   e_gadget_util_ctxpopup_place(inst->o_bluez5, inst->pop, inst->o_bluez5);
+   evas_object_show(inst->pop);
+}
+
+static void
+_gad_mouse_down(void *data, Evas *evas EINA_UNUSED,
+                Evas_Object *obj EINA_UNUSED, void *event)
+{
+   Instance *inst = data;
+   Evas_Event_Mouse_Down *ev = event;
+
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+   if (ev->button != 1) return;
+   if (!inst->pop) _gad_popup_do(inst);
+   else elm_ctxpopup_dismiss(inst->pop);
+}
+
+static void
+_gad_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void 
*event_info EINA_UNUSED)
+{
+   Instance *inst = data;
+
+   instances = eina_list_remove(instances, inst);
+   E_FREE(inst);
+}
+
+/* XXX: fill in later when we have gotten this far
+static Evas_Object *
+_gad_config(Evas_Object *g EINA_UNUSED)
+{
+   if (e_configure_registry_exists("extensions/bluez5"))
+     e_configure_registry_call("extensions/bluez5", NULL, NULL);
+   return NULL;
+}
+*/
+
+static Evas_Object *
+_gad_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient)
+{
+   Evas_Object *o;
+   Instance *inst = E_NEW(Instance, 1);
+
+   if (!inst) return NULL;
+   inst->id = *id;
+   inst->orient = orient;
+   inst->o_bluez5 = o = elm_layout_add(parent);
+   _mod_icon_set(o, EINA_TRUE);
+   evas_object_size_hint_aspect_set(o, EVAS_ASPECT_CONTROL_BOTH, 1, 1);
+// XXX: fill in later when we have gotten this far   
+//   e_gadget_configure_cb_set(o, _gad_config);
+   evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, 
_gad_mouse_down, inst);
+   if (*id != -1)
+     evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _gad_del, inst);
+   instances = eina_list_append(instances, inst);
+   return o;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static void
+_popup_del(Instance *inst)
+{
+   E_FREE_FUNC(inst->popup, e_object_del);
+}
+
+static void
+_popup_del_cb(void *obj)
+{
+   _popup_del(e_object_data_get(obj));
+}
+
+static void
+_popup_comp_del_cb(void *data, Evas_Object *obj EINA_UNUSED)
+{
+   _popup_del(data);
+}
+
+static void
+_popup_new(Instance *inst)
+{
+   inst->popup = e_gadcon_popup_new(inst->gcc, 0);
+
+   e_gadcon_popup_content_set(inst->popup, 
ebluez5_popup_content_add(e_comp->elm, inst));
+   e_comp_object_util_autoclose(inst->popup->comp_object, _popup_comp_del_cb, 
NULL, inst);
+   e_gadcon_popup_show(inst->popup);
+   e_object_data_set(E_OBJECT(inst->popup), inst);
+   E_OBJECT_DEL_SET(inst->popup, _popup_del_cb);
+}
+
+static void
+_ebluez5_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, void *event)
+{
+   Instance *inst = data;
+   Evas_Event_Mouse_Down *ev = event;
+
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+   if (ev->button != 1) return;
+   if (!inst->popup) _popup_new(inst);
+   else _popup_del(inst);
+}
+
+static E_Gadcon_Client *
+_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
+{
+   Evas_Object *o;
+   Instance *inst = E_NEW(Instance, 1);
+
+   if (!inst) return NULL;
+   inst->o_bluez5 = o = edje_object_add(gc->evas);
+   _mod_icon_set(o, EINA_FALSE);
+   inst->gcc = e_gadcon_client_new(gc, name, id, style, o);
+   inst->gcc->data = inst;
+   e_gadcon_client_util_menu_attach(inst->gcc);
+   evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, 
_ebluez5_cb_mouse_down, inst);
+   instances = eina_list_append(instances, inst);
+   return inst->gcc;
+}
+
+static void
+_gc_shutdown(E_Gadcon_Client *gcc)
+{
+   Instance *inst = gcc->data;;
+
+   if (!inst) return;
+   instances = eina_list_remove(instances, inst);
+   _popup_del(inst);
+   E_FREE_FUNC(inst->o_bluez5, evas_object_del);
+   E_FREE(inst);
+}
+
+static const char *
+_gc_id_new(const E_Gadcon_Client_Class *client_class EINA_UNUSED)
+{
+   static char tmpbuf[128];
+   snprintf(tmpbuf, sizeof(tmpbuf), "bluez5.%d", eina_list_count(instances));
+   return tmpbuf;
+}
+
+static void
+_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient EINA_UNUSED)
+{
+   e_gadcon_client_aspect_set(gcc, 16, 16);
+   e_gadcon_client_min_size_set(gcc, 16, 16);
+}
+
+static const char *
+_gc_label(const E_Gadcon_Client_Class *client_class EINA_UNUSED)
+{
+   return _("Bluez5");
+}
+
+static Evas_Object *
+_gc_icon(const E_Gadcon_Client_Class *client_class EINA_UNUSED, Evas *evas)
+{
+   Evas_Object *o = NULL;
+   char buf[4096];
+
+   snprintf(buf, sizeof(buf), "%s/e-module-bluez5.edj", mod->dir);
+   o = edje_object_add(evas);
+   edje_object_file_set(o, buf, "icon");
+   return o;
+}
+
+static const E_Gadcon_Client_Class _gc_class = {
+   GADCON_CLIENT_CLASS_VERSION, "bluez5",
+     {_gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, 
NULL, NULL},
+   E_GADCON_CLIENT_STYLE_PLAIN
+};
+
+/////////////////////////////////////////////////////////////////////////////
+void
+ebluez5_popups_show(void)
+{
+   Eina_List *l;
+   Instance *inst;
+
+   EINA_LIST_FOREACH(instances, l, inst)
+     {
+        if (inst->gcc)
+          {
+             if (!inst->popup) _popup_new(inst);
+          }
+        else
+          {
+             if (!inst->pop) _gad_popup_do(inst);
+          }
+     }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+/* Module Functions */
+E_API void *
+e_modapi_init(E_Module *m)
+{
+   mod = m;
+
+   conf_edd = E_CONFIG_DD_NEW("Config", Config);
+#undef T
+#undef D
+#define T Config
+#define D conf_edd
+   E_CONFIG_VAL(D, T, lock_dev_addr, STR);
+   E_CONFIG_VAL(D, T, unlock_dev_addr, STR);
+
+   ebluez5_config = e_config_domain_load("module.ebluez5", conf_edd);
+   if (!ebluez5_config) ebluez5_config = E_NEW(Config, 1);
+
+   ebluze5_popup_init();
+   bz_init();
+
+   e_gadcon_provider_register(&_gc_class);
+   e_gadget_type_add("Bluetooth", _gad_create, NULL);
+
+   return m;
+}
+
+E_API int
+e_modapi_shutdown(E_Module *m EINA_UNUSED)
+{
+   E_CONFIG_DD_FREE(conf_edd);
+
+   eina_stringshare_del(ebluez5_config->lock_dev_addr);
+   eina_stringshare_del(ebluez5_config->unlock_dev_addr);
+   free(ebluez5_config);
+   ebluez5_config = NULL;
+
+   bz_shutdown();
+   ebluze5_popup_shutdown();
+
+   e_gadget_type_del("Bluetooth");
+   e_gadcon_provider_unregister(&_gc_class);
+   return 1;
+}
+
+E_API int
+e_modapi_save(E_Module *m EINA_UNUSED)
+{
+   e_config_domain_save("module.ebluez5", conf_edd, ebluez5_config);
+   return 1;
+}
diff --git a/src/modules/bluez5/e_mod_main.h b/src/modules/bluez5/e_mod_main.h
new file mode 100644
index 000000000..269726638
--- /dev/null
+++ b/src/modules/bluez5/e_mod_main.h
@@ -0,0 +1,68 @@
+#ifndef E_MOD_MAIN_H
+#define E_MOD_MAIN_H
+
+#include <e.h>
+#include "bz.h"
+
+typedef struct _Instance Instance;
+struct _Instance
+{
+   // common info
+   Evas_Object *o_bluez5;
+   // e_gadcon info
+   E_Gadcon_Client *gcc;
+   E_Gadcon_Popup *popup;
+   // e_gadget info
+   Evas_Object *pop;
+   Evas_Object *popcontent;
+   int id;
+   E_Gadget_Site_Orient orient;
+};
+
+typedef struct _Config Config;
+struct _Config
+{
+   const char *lock_dev_addr;
+   const char *unlock_dev_addr;
+};
+
+extern Config *ebluez5_config;
+
+E_API extern E_Module_Api e_modapi;
+
+E_API void *e_modapi_init(E_Module *m);
+E_API int e_modapi_shutdown(E_Module *m);
+E_API int e_modapi_save(E_Module *m);
+
+void ebluez5_popups_show(void);
+
+void ebluez5_popup_hide(Instance *inst);
+
+Evas_Object *ebluez5_popup_content_add(Evas_Object *base, Instance *inst);
+void ebluze5_popup_init(void);
+void ebluze5_popup_shutdown(void);
+void ebluze5_popup_clear(void);
+void ebluez5_popup_adapter_add(Obj *o);
+void ebluez5_popup_adapter_del(Obj *o);
+void ebluez5_popup_adapter_change(Obj *o);
+void ebluez5_popup_device_add(Obj *o);
+void ebluez5_popup_device_del(Obj *o);
+void ebluez5_popup_device_change(Obj *o);
+
+void ebluez5_agent_agent_release(void);
+void ebluez5_agent_agent_cancel(void);
+void ebluez5_agent_agent_req_pin(Eldbus_Message *msg);
+void ebluez5_agent_agent_disp_pin(Eldbus_Message *msg);
+void ebluez5_agent_req_pass(Eldbus_Message *msg);
+void ebluez5_agent_disp_pass(Eldbus_Message *msg);
+void ebluez5_agent_req_confirm(Eldbus_Message *msg);
+void ebluez5_agent_req_auth(Eldbus_Message *msg);
+void ebluez5_agent_auth_service(Eldbus_Message *msg);
+
+Evas_Object *util_obj_icon_add(Evas_Object *base, Obj *o, int size);
+Evas_Object *util_obj_icon_rssi_add(Evas_Object *base, Obj *o, int size);
+Evas_Object *util_check_add(Evas_Object *base, const char *text, const char 
*tip, Eina_Bool state);
+Evas_Object *util_button_icon_add(Evas_Object *base, const char *icon, const 
char *tip);
+const char  *util_obj_name_get(Obj *o);
+
+#endif
diff --git a/src/modules/bluez5/e_mod_popup.c b/src/modules/bluez5/e_mod_popup.c
new file mode 100644
index 000000000..8152802f0
--- /dev/null
+++ b/src/modules/bluez5/e_mod_popup.c
@@ -0,0 +1,714 @@
+#include "e_mod_main.h"
+
+static Elm_Genlist_Item_Class *adapt_itc = NULL;
+static Elm_Genlist_Item_Class *dev_itc = NULL;
+static Elm_Genlist_Item_Class *group_itc = NULL;
+static Eina_List *lists = NULL;
+static Eina_List *adapters = NULL;
+static Eina_List *devices = NULL;
+
+static void
+_adapter_add(Evas_Object *gl, Obj *o)
+{
+   Elm_Object_Item *it = evas_object_data_get(gl, "adapters_item");;
+   elm_genlist_item_append(gl, adapt_itc, o, it, ELM_GENLIST_ITEM_NONE,
+                            NULL, NULL);
+}
+
+static int
+_cb_insert_cmp(const void *ai, const void *bi)
+{
+   Obj *a = elm_object_item_data_get(ai);
+   Obj *b = elm_object_item_data_get(bi);
+   Eina_Bool apub = EINA_FALSE, bpub = EINA_FALSE;
+
+   if ((!a) || (!a->address)) return -1;
+   if ((!b) || (!b->address)) return 1;
+
+   // prefer paired at top
+   if ((a->paired) && (!b->paired)) return -1;
+   if ((!a->paired) && (b->paired)) return 1;
+   // prefer public addresses next after being paired
+   if ((a->address_type) && (!strcmp(a->address_type, "public")))
+     apub = EINA_TRUE;
+   if ((b->address_type) && (!strcmp(b->address_type, "public")))
+     bpub = EINA_TRUE;
+   if ((apub) && (!bpub)) return -1;
+   if ((!apub) && (bpub)) return 1;
+   // and sort by address
+   return strcmp(a->address, b->address);
+}
+
+static void
+_device_add(Evas_Object *gl, Obj *o)
+{
+   Elm_Object_Item *it = evas_object_data_get(gl, "devices_item");;
+
+   elm_genlist_item_sorted_insert(gl, dev_itc, o, it, ELM_GENLIST_ITEM_NONE,
+                                  _cb_insert_cmp, NULL, NULL);
+}
+
+static void
+_cb_power(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   if (elm_check_state_get(obj)) bz_obj_power_on(o);
+   else bz_obj_power_off(o);
+}
+
+static void
+_cb_scan(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   if (elm_check_state_get(obj)) bz_obj_discover_start(o);
+   else bz_obj_discover_stop(o);
+}
+
+static void
+_cb_visible(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   if (elm_check_state_get(obj)) bz_obj_discoverable(o);
+   else bz_obj_undiscoverable(o);
+}
+
+static void
+_cb_pairable(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   if (elm_check_state_get(obj)) bz_obj_pairable(o);
+   else bz_obj_unpairable(o);
+}
+
+static void
+_cb_connect(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   bz_obj_connect(o);
+}
+
+static void
+_cb_disconnect(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   bz_obj_disconnect(o);
+}
+
+static void
+_cb_trust(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   bz_obj_trust(o);
+}
+
+static void
+_cb_distrust(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   bz_obj_distrust(o);
+}
+
+static void
+_cb_pair(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   bz_obj_pair(o);
+}
+
+static void
+_cb_unpair(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   bz_obj_remove(o);
+}
+
+static void
+_agent_done(Obj *o)
+{
+   Eina_List *l;
+   Evas_Object *gl;
+   Elm_Object_Item *it;
+
+   if (o->agent_request)
+     {
+        eina_stringshare_del(o->agent_request);
+        o->agent_request = NULL;
+     }
+   EINA_LIST_FOREACH(lists, l, gl)
+     {
+        for (it = elm_genlist_first_item_get(gl); it;
+             it = elm_genlist_item_next_get(it))
+          {
+             if (o == elm_object_item_data_get(it))
+               {
+                  elm_genlist_item_update(it);
+                  break;
+               }
+          }
+     }
+}
+
+static void
+_cb_agent_ok(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+   Obj *o = data;
+
+   if ((o->agent_entry_fn) && (o->agent_msg_ok))
+     {
+        Evas_Object *en = evas_object_data_get(obj, "entry");
+
+        if (en)
+          {
+             const char *s = elm_object_text_get(en);
+
+             if (s) o->agent_entry_fn(o->agent_msg_ok, s);
+          }
+     }
+   if (o->agent_msg_err)
+     {
+        bz_agent_msg_drop(o->agent_msg_err);
+        o->agent_msg_err = NULL;
+     }
+   if (o->agent_msg_ok)
+     {
+        bz_agent_msg_reply(o->agent_msg_ok);
+        o->agent_msg_ok = NULL;
+     }
+   _agent_done(o);
+}
+
+static void
+_cb_agent_cancel(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Obj *o = data;
+   if (o->agent_msg_ok)
+     {
+        bz_agent_msg_drop(o->agent_msg_ok);
+        o->agent_msg_ok = NULL;
+     }
+   if (o->agent_msg_err)
+     {
+        bz_agent_msg_reply(o->agent_msg_err);
+        o->agent_msg_err = NULL;
+     }
+   _agent_done(o);
+}
+
+static char *
+_cb_group_text_get(void *data, Evas_Object *obj EINA_UNUSED,
+                   const char *part EINA_UNUSED)
+{
+   if (!data) return strdup(_("Adapters"));
+   return strdup(_("Devices"));
+}
+
+static Evas_Object *
+_cb_group_content_get(void *data EINA_UNUSED, Evas_Object *obj,
+                      const char *part EINA_UNUSED)
+{
+   if (!strcmp(part, "elm.swallow.icon"))
+     {
+        Evas_Object *ic = elm_icon_add(obj);
+        if (!data)
+          elm_icon_standard_set(ic, "computer");
+        else
+          elm_icon_standard_set(ic, "system-run");
+        evas_object_size_hint_min_set(ic,
+                                      ELM_SCALE_SIZE(16),
+                                      ELM_SCALE_SIZE(16));
+        return ic;
+     }
+   return NULL;
+}
+
+static char *
+_cb_adapt_text_get(void *data, Evas_Object *obj EINA_UNUSED,
+                   const char *part EINA_UNUSED)
+{
+   Obj *o = data;
+
+   if (!strcmp(part, "elm.text"))
+     {
+        return strdup(util_obj_name_get(o));
+     }
+   else if (!strcmp(part, "elm.text.sub"))
+     {
+        if (o->address) return strdup(o->address);
+        return strdup(_("Unknown Address"));
+     }
+   return NULL;
+}
+
+static Evas_Object *
+_cb_adapt_content_get(void *data EINA_UNUSED, Evas_Object *obj,
+                      const char *part EINA_UNUSED)
+{
+   Obj *o = data;
+
+   if (!strcmp(part, "elm.swallow.icon"))
+     {
+        return util_obj_icon_add(obj, o, 48);
+     }
+   else if (!strcmp(part, "elm.swallow.end"))
+     {
+        Evas_Object *tab, *ck;
+
+        tab = elm_table_add(obj);
+        evas_object_size_hint_weight_set(tab, EVAS_HINT_EXPAND, 0);
+        evas_object_size_hint_align_set(tab, EVAS_HINT_FILL, 0.0);
+
+        ck = util_check_add(obj, _("Power"), _("Enable power for this 
adapter"),
+                            o->powered);
+        evas_object_smart_callback_add(ck, "changed", _cb_power, o);
+        elm_table_pack(tab, ck, 0, 0, 1, 1);
+        evas_object_show(ck);
+
+        ck = util_check_add(obj, _("Visible"), _("Make this adapter visible to 
other devices"),
+                            o->discoverable);
+        evas_object_smart_callback_add(ck, "changed", _cb_visible, o);
+        elm_table_pack(tab, ck, 1, 0, 1, 1);
+        evas_object_show(ck);
+
+        ck = util_check_add(obj, _("Scan"), _("Scan for other devices"),
+                            o->discovering);
+        evas_object_smart_callback_add(ck, "changed", _cb_scan, o);
+        elm_table_pack(tab, ck, 0, 1, 1, 1);
+        evas_object_show(ck);
+
+        ck = util_check_add(obj, _("Pairable"), _("Allow this adapter to have 
other devices request to pair with it"),
+                            o->pairable);
+        evas_object_smart_callback_add(ck, "changed", _cb_pairable, o);
+        elm_table_pack(tab, ck, 1, 1, 1, 1);
+        evas_object_show(ck);
+
+        return tab;
+     }
+   return NULL;
+}
+
+static char *
+_cb_dev_text_get(void *data, Evas_Object *obj EINA_UNUSED,
+                 const char *part EINA_UNUSED)
+{
+   Obj *o = data;
+   return strdup(util_obj_name_get(o));
+}
+
+static Evas_Object *
+_cb_dev_content_get(void *data EINA_UNUSED, Evas_Object *obj,
+                    const char *part EINA_UNUSED)
+{
+   Obj *o = data;
+   char buf[512];
+
+   if (!strcmp(part, "elm.swallow.icon"))
+     {
+        Evas_Object *ic, *bx;
+
+        bx = elm_box_add(obj);
+        ic = util_obj_icon_add(obj, o, 24);
+        snprintf(buf, sizeof(buf),
+                 _("Address: %s (%s)<br>"
+                   "Services: %s%s%s%s%s%s%s%s%s<br>"
+                   "Trusted: %s<br>"
+                   "Blocked: %s<br>"
+                     )
+                 ,
+                 (o->address) ? o->address : _("Unknown"),
+                 (o->address_type) ? o->address_type : _("Unknown"),
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_LIMITED_DISCOVERABLE) ? 
_("Limited-Discoverable ") : "",
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_POSITIONING_BIT) ? 
_("Positioning ") : "",
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_NETWORKING_BIT) ? 
_("Networking ") : "",
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_RENDERING_BIT) ? 
_("Rendering ") : "",
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_CAPTURING_BIT) ? _("Capture 
") : "",
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_OBJECT_TRANSFER_BIT) ? 
_("OBEX ") : "",
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_AUDIO_BIT) ? _("Audio ") : 
"",
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_TELEPHONY_BIT) ? 
_("Telephony ") : "",
+                 (o->klass & BZ_OBJ_CLASS_SERVICE_INFORMATION_BIT) ? 
_("Information ") : "",
+                 (o->trusted) ? _("Yes") : _("No"),
+                 (o->blocked) ? _("Yes") : _("No")
+                );
+        elm_object_tooltip_text_set(ic, buf);
+        elm_box_pack_end(bx, ic);
+        evas_object_show(ic);
+        return bx;
+     }
+   else if (!strcmp(part, "elm.swallow.end"))
+     {
+        Evas_Object *bx, *ic, *bt, *lb, *tb, *en, *rec;
+
+        bx = elm_box_add(obj);
+        elm_box_horizontal_set(bx, EINA_TRUE);
+        if (o->paired)
+          {
+             if (o->connected)
+               {
+                  bt = util_button_icon_add(obj, "network-offline",
+                                            _("Disconnect this device"));
+                  evas_object_smart_callback_add(bt, "clicked", 
_cb_disconnect, o);
+               }
+             else
+               {
+                  bt = util_button_icon_add(obj, "network-transmit-receive",
+                                            _("Connect this device"));
+                  evas_object_smart_callback_add(bt, "clicked", _cb_connect, 
o);
+               }
+             elm_box_pack_end(bx, bt);
+             evas_object_show(bt);
+
+             if (o->trusted)
+               {
+                  bt = util_button_icon_add(obj, "security-low",
+                                            _("Disrust this device"));
+                  evas_object_smart_callback_add(bt, "clicked", _cb_distrust, 
o);
+               }
+             else
+               {
+                  bt = util_button_icon_add(obj, "security-high",
+                                            _("Trust this device"));
+                  evas_object_smart_callback_add(bt, "clicked", _cb_trust, o);
+               }
+             elm_box_pack_end(bx, bt);
+             evas_object_show(bt);
+          }
+        if (!o->paired)
+          {
+             if (o->agent_request)
+               {
+                  if (o->agent_entry_fn)
+                    {
+                       tb = elm_table_add(obj);
+
+                       rec = 
evas_object_rectangle_add(evas_object_evas_get(obj));
+                       evas_object_size_hint_min_set(rec, ELM_SCALE_SIZE(80), 
ELM_SCALE_SIZE(1));
+                       elm_table_pack(tb, rec, 0, 0, 1, 1);
+
+                       en = elm_entry_add(obj);
+                       elm_entry_single_line_set(en, EINA_TRUE);
+                       elm_entry_scrollable_set(en, EINA_TRUE);
+                       elm_scroller_policy_set(en, ELM_SCROLLER_POLICY_OFF, 
ELM_SCROLLER_POLICY_OFF);
+                       elm_object_part_text_set(en, "guide", o->agent_request);
+//                       elm_entry_password_set(en, EINA_TRUE);
+                       evas_object_smart_callback_add(en, "activated", 
_cb_agent_ok, o);
+                       evas_object_smart_callback_add(en, "aborted", 
_cb_agent_cancel, o);
+                       elm_table_pack(tb, en, 0, 0, 1, 1);
+                       evas_object_show(en);
+
+                       elm_box_pack_end(bx, tb);
+                       evas_object_show(tb);
+
+                       bt = util_button_icon_add(obj, "list-add",
+                                                 _("Pair with this device"));
+                       evas_object_data_set(bt, "entry", en);
+                       evas_object_smart_callback_add(bt, "clicked", 
_cb_agent_ok, o);
+                       elm_box_pack_end(bx, bt);
+                       evas_object_show(bt);
+
+                       bt = util_button_icon_add(obj, "list-remove",
+                                                 _("Reject pairing"));
+                       evas_object_smart_callback_add(bt, "clicked", 
_cb_agent_cancel, o);
+                       elm_box_pack_end(bx, bt);
+                       evas_object_show(bt);
+                    }
+                  else
+                    {
+                       lb = elm_label_add(obj);
+                       elm_layout_text_set(lb, NULL, o->agent_request);
+                       elm_box_pack_end(bx, lb);
+                       evas_object_show(lb);
+
+                       bt = util_button_icon_add(obj, "list-add",
+                                                 _("Pair with this device"));
+                       evas_object_smart_callback_add(bt, "clicked", 
_cb_agent_ok, o);
+                       elm_box_pack_end(bx, bt);
+                       evas_object_show(bt);
+
+                       bt = util_button_icon_add(obj, "list-remove",
+                                                 _("Reject pairing"));
+                       evas_object_smart_callback_add(bt, "clicked", 
_cb_agent_cancel, o);
+                       elm_box_pack_end(bx, bt);
+                       evas_object_show(bt);
+                    }
+               }
+             else
+               {
+                  bt = util_button_icon_add(obj, "list-add",
+                                            _("Pair with this device"));
+                  evas_object_smart_callback_add(bt, "clicked", _cb_pair, o);
+                  elm_box_pack_end(bx, bt);
+                  evas_object_show(bt);
+               }
+          }
+        else
+          {
+             bt = util_button_icon_add(obj, "list-remove",
+                                        _("Unpair with this device"));
+             evas_object_smart_callback_add(bt, "clicked", _cb_unpair, o);
+             elm_box_pack_end(bx, bt);
+             evas_object_show(bt);
+          }
+
+        ic = util_obj_icon_rssi_add(obj, o, 24);
+        elm_box_pack_end(bx, ic);
+        evas_object_show(ic);
+        return bx;
+     }
+   return NULL;
+}
+
+static void
+_cb_list_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, 
void *event_info EINA_UNUSED)
+{
+   lists = eina_list_remove(lists, obj);
+}
+
+/*
+static void
+_cb_settings(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Instance *inst = data;
+   ebluez5_popup_hide(inst);
+}
+*/
+
+Evas_Object *
+ebluez5_popup_content_add(Evas_Object *base, Instance *inst)
+{
+   Evas_Object *o, *box, *tab, *gl;
+   Eina_List *l;
+   Elm_Object_Item *it;
+   Obj *oo;
+
+   o = box = elm_box_add(base);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+   tab = o = elm_table_add(base);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+   o = evas_object_rectangle_add(evas_object_evas_get(base));
+   evas_object_size_hint_min_set(o, ELM_SCALE_SIZE(320), ELM_SCALE_SIZE(240));
+   evas_object_size_hint_max_set(o, ELM_SCALE_SIZE(560), ELM_SCALE_SIZE(400));
+   elm_table_pack(tab, o, 0, 0, 1, 1);
+
+   o = gl = elm_genlist_add(base);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_genlist_mode_set(o, ELM_LIST_LIMIT);
+   elm_genlist_select_mode_set(o, ELM_OBJECT_SELECT_MODE_NONE);
+
+   lists = eina_list_append(lists, gl);
+   evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _cb_list_del, inst);
+
+   it = elm_genlist_item_append(gl, group_itc, NULL, NULL,
+                                ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+   evas_object_data_set(gl, "adapters_item", it);
+   it = elm_genlist_item_append(gl, group_itc, gl, NULL,
+                                ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+   evas_object_data_set(gl, "devices_item", it);
+
+   EINA_LIST_FOREACH(adapters, l, oo)
+     {
+        _adapter_add(gl, oo);
+     }
+   EINA_LIST_FOREACH(devices, l, oo)
+     {
+        _device_add(gl, oo);
+     }
+
+   elm_table_pack(tab, o, 0, 0, 1, 1);
+   evas_object_show(o);
+
+   elm_box_pack_end(box, tab);
+   evas_object_show(tab);
+/*
+   o = elm_separator_add(base);
+   elm_separator_horizontal_set(o, EINA_TRUE);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_end(box, o);
+   evas_object_show(o);
+
+   o = elm_button_add(base);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_layout_text_set(o, NULL, _("Settings"));
+   elm_object_tooltip_text_set(o, _("Bring up more detailed Bluetooth 
settings"));
+   evas_object_smart_callback_add(o, "clicked", _cb_settings, inst);
+   elm_box_pack_end(box, o);
+   evas_object_show(o);
+*/
+   return box;
+}
+
+void
+ebluze5_popup_init(void)
+{
+   adapt_itc = elm_genlist_item_class_new();
+   adapt_itc->item_style = "double_label";
+   adapt_itc->func.text_get = _cb_adapt_text_get;
+   adapt_itc->func.content_get = _cb_adapt_content_get;
+   adapt_itc->func.state_get = NULL;
+   adapt_itc->func.del = NULL;
+
+   dev_itc = elm_genlist_item_class_new();
+   dev_itc->item_style = "default";
+   dev_itc->func.text_get = _cb_dev_text_get;
+   dev_itc->func.content_get = _cb_dev_content_get;
+   dev_itc->func.state_get = NULL;
+   dev_itc->func.del = NULL;
+
+   group_itc = elm_genlist_item_class_new();
+   group_itc->item_style = "group_index";
+   group_itc->func.text_get = _cb_group_text_get;
+   group_itc->func.content_get = _cb_group_content_get;
+   group_itc->func.state_get = NULL;
+   group_itc->func.del = NULL;
+}
+
+void
+ebluze5_popup_shutdown(void)
+{
+   ebluze5_popup_clear();
+   elm_genlist_item_class_free(group_itc);
+   elm_genlist_item_class_free(dev_itc);
+   elm_genlist_item_class_free(adapt_itc);
+   group_itc = NULL;
+   dev_itc = NULL;
+   adapt_itc = NULL;
+}
+
+void
+ebluze5_popup_clear(void)
+{
+   Eina_List *l;
+   Evas_Object *gl;
+
+   adapters = eina_list_free(adapters);
+   devices = eina_list_free(devices);
+   EINA_LIST_FOREACH(lists, l, gl)
+     {
+        elm_genlist_clear(gl);
+     }
+}
+
+void
+ebluez5_popup_adapter_add(Obj *o)
+{
+   Eina_List *l;
+   Evas_Object *gl;
+
+   adapters = eina_list_append(adapters, o);
+   EINA_LIST_FOREACH(lists, l, gl)
+     {
+        _adapter_add(gl, o);
+     }
+}
+
+void
+ebluez5_popup_adapter_del(Obj *o)
+{
+   Eina_List *l;
+   Evas_Object *gl;
+   Elm_Object_Item *it;
+
+   EINA_LIST_FOREACH(lists, l, gl)
+     {
+        for (it = elm_genlist_first_item_get(gl); it;
+             it = elm_genlist_item_next_get(it))
+          {
+             if (o == elm_object_item_data_get(it))
+               {
+                  elm_object_item_del(it);
+                  break;
+               }
+          }
+     }
+   adapters = eina_list_remove(adapters, o);
+}
+
+void
+ebluez5_popup_adapter_change(Obj *o)
+{
+   Eina_List *l;
+   Evas_Object *gl;
+   Elm_Object_Item *it;
+
+   EINA_LIST_FOREACH(lists, l, gl)
+     {
+        for (it = elm_genlist_first_item_get(gl); it;
+             it = elm_genlist_item_next_get(it))
+          {
+             if (o == elm_object_item_data_get(it))
+               {
+                  elm_genlist_item_update(it);
+                  break;
+               }
+          }
+     }
+}
+
+void
+ebluez5_popup_device_add(Obj *o)
+{
+   Eina_List *l;
+   Evas_Object *gl;
+
+   devices = eina_list_append(devices, o);
+   EINA_LIST_FOREACH(lists, l, gl)
+     {
+        _device_add(gl, o);
+     }
+}
+
+void
+ebluez5_popup_device_del(Obj *o)
+{
+   Eina_List *l;
+   Evas_Object *gl;
+   Elm_Object_Item *it;
+
+   EINA_LIST_FOREACH(lists, l, gl)
+     {
+        for (it = elm_genlist_first_item_get(gl); it;
+             it = elm_genlist_item_next_get(it))
+          {
+             if (o == elm_object_item_data_get(it))
+               {
+                  elm_object_item_del(it);
+                  break;
+               }
+          }
+     }
+   devices = eina_list_remove(devices, o);
+}
+
+void
+ebluez5_popup_device_change(Obj *o)
+{
+   Eina_List *l;
+   Evas_Object *gl;
+   Elm_Object_Item *it;
+   Eina_Bool alert = EINA_FALSE;
+
+   if (o->agent_alert)
+     {
+        alert = EINA_TRUE;
+        o->agent_alert = EINA_FALSE;
+        if (!lists) ebluez5_popups_show();
+     }
+   EINA_LIST_FOREACH(lists, l, gl)
+     {
+        for (it = elm_genlist_first_item_get(gl); it;
+             it = elm_genlist_item_next_get(it))
+          {
+             if (o == elm_object_item_data_get(it))
+               {
+                  elm_genlist_item_update(it);
+                  if (alert)
+                    elm_genlist_item_show(it, 
ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
+                  break;
+               }
+          }
+     }
+}
diff --git a/src/modules/bluez5/e_mod_util.c b/src/modules/bluez5/e_mod_util.c
new file mode 100644
index 000000000..aedd37d6a
--- /dev/null
+++ b/src/modules/bluez5/e_mod_util.c
@@ -0,0 +1,262 @@
+#include "e_mod_main.h"
+
+Evas_Object *
+util_obj_icon_add(Evas_Object *base, Obj *o, int size)
+{
+   Evas_Object *ic = elm_icon_add(base);
+   unsigned int maj, min;
+   const char *s ="bluetooth-active";
+
+   // XXX: replace this with a much better database...
+   maj = o->klass & BZ_OBJ_CLASS_MAJ_MASK;
+   if (maj == BZ_OBJ_CLASS_MAJ_MISC)
+     {
+        s ="bluetooth-active";
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_COMPUTER)
+     {
+        min = o->klass & BZ_OBJ_CLASS_MIN_COMPUTER_MASK;
+        if (min == BZ_OBJ_CLASS_MIN_COMPUTER_DESKTOP)
+          s = "computer";
+        else if (min == BZ_OBJ_CLASS_MIN_COMPUTER_SERVER)
+          s = "computer";
+        else if (min == BZ_OBJ_CLASS_MIN_COMPUTER_LAPTOP)
+          s = "computer-laptop";
+        else if (min == BZ_OBJ_CLASS_MIN_COMPUTER_CLAMSHELL)
+          s = "computer-laptop";
+        else if (min == BZ_OBJ_CLASS_MIN_COMPUTER_PDA)
+          s = "pda";
+        else if (min == BZ_OBJ_CLASS_MIN_COMPUTER_WEARABLE)
+          s = "pda";
+        else if (min == BZ_OBJ_CLASS_MIN_COMPUTER_TABLET)
+          s = "pda";
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_PHONE)
+     {
+        min = o->klass & BZ_OBJ_CLASS_MIN_PHONE_MASK;
+        if (min == BZ_OBJ_CLASS_MIN_PHONE_CELL)
+          s = "phone";
+        else if (min == BZ_OBJ_CLASS_MIN_PHONE_CORDLESS)
+          s = "phone";
+        else if (min == BZ_OBJ_CLASS_MIN_PHONE_SMARTPHONE)
+          s = "phone";
+        else if (min == BZ_OBJ_CLASS_MIN_PHONE_WIRED)
+          s = "modem";
+        else if (min == BZ_OBJ_CLASS_MIN_PHONE_ISDN)
+          s = "modem";
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_LAN)
+     {
+        s = "network-wired";
+        // XXX: handle (top is max availability)
+        // BZ_OBJ_CLASS_MIN_LAN_AVAIL_7
+        // BZ_OBJ_CLASS_MIN_LAN_AVAIL_6
+        // BZ_OBJ_CLASS_MIN_LAN_AVAIL_5
+        // BZ_OBJ_CLASS_MIN_LAN_AVAIL_4
+        // BZ_OBJ_CLASS_MIN_LAN_AVAIL_3
+        // BZ_OBJ_CLASS_MIN_LAN_AVAIL_2
+        // BZ_OBJ_CLASS_MIN_LAN_AVAIL_1
+        // BZ_OBJ_CLASS_MIN_LAN_AVAIL_0
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_AV)
+     {
+        min = o->klass & BZ_OBJ_CLASS_MIN_AV_MASK;
+        if (min == BZ_OBJ_CLASS_MIN_AV_WEARABLE_HEADSET)
+          s = "audio-input-microphone";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_HANDS_FREE)
+          s = "audio-input-microphone";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_MIC)
+          s = "audio-input-microphone";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_SPEAKER)
+          s = "audio-volume-high";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_HEADPHONES)
+          s = "audio-volume-high";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_PORTABLE_AUDIO)
+          s = "audio-volume-high";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_CAR_AUDIO)
+          s = "audio-volume-high";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_SET_TOP_BOX)
+          s = "modem";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_HIFI_AUDIO)
+          s = "audio-volume-high";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_VCR)
+          s = "media-tape";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_VIDEO_CAMERA)
+          s = "camera-photo";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_CAMCORDER)
+          s = "camera-photo";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_VIDEO_MONITOR)
+          s = "video-display";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_VIDEO_DISPLAY_SPEAKER)
+          s = "video-display";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_VIDEO_CONFERENCE)
+          s = "video-display";
+        else if (min == BZ_OBJ_CLASS_MIN_AV_GAMING)
+          s = "input-gaming";
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_PERIPHERAL)
+     {
+        s = "input-keyboard";
+
+        // XXX: handle bits + ide below
+        if (o->klass & BZ_OBJ_CLASS_MIN_PERIPHERAL_KEYBOARD_BIT)
+          s = "input-keyboard";
+        else if (o->klass & BZ_OBJ_CLASS_MIN_PERIPHERAL_MOUSE_BIT)
+          s = "input-mouse";
+
+        min = o->klass & BZ_OBJ_CLASS_MIN_PERIPHERAL_MASK2;
+        if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_JOYSTICK)
+          s = "input-gaming";
+        else if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_GAMEPAD)
+          s = "input-gaming";
+        else if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_REMOTE)
+          s = "input-gaming";
+        else if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_SENSING)
+          s = "input-gaming";
+        else if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_DIGITIZER_TAB)
+          s = "input-tablet";
+        else if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_CARD_READER)
+          s = "media-flash";
+        else if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_PEN)
+          s = "input-mouse";
+        else if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_SCANNER)
+          s = "scanner";
+        else if (min == BZ_OBJ_CLASS_MIN_PERIPHERAL_WAND)
+          s = "input-mouse";
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_IMAGING)
+     {
+        // XXX: handle permutations of bits
+        if (o->klass & BZ_OBJ_CLASS_MIN_IMAGING_CAMERA_BIT)
+          s = "camera-photo";
+        else if (o->klass & BZ_OBJ_CLASS_MIN_IMAGING_SCANNER_BIT)
+          s = "scanner";
+        else if (o->klass & BZ_OBJ_CLASS_MIN_IMAGING_PRINTER_BIT)
+          s = "printer";
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_WEARABLE)
+     {
+        min = o->klass & BZ_OBJ_CLASS_MIN_WEARABLE_MASK;
+        if (min == BZ_OBJ_CLASS_MIN_WEARABLE_WATCH)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_WEARABLE_PAGER)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_WEARABLE_JACKET)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_WEARABLE_HELMET)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_WEARABLE_GLASSES)
+          s = "cpu";
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_TOY)
+     {
+        min = o->klass & BZ_OBJ_CLASS_MIN_TOY_MASK;
+        if (min == BZ_OBJ_CLASS_MIN_TOY_ROBOT)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_TOY_VEHICLE)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_TOY_DOLL)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_TOY_CONTROLLER)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_TOY_GAME)
+          s = "cpu";
+     }
+   else if (maj == BZ_OBJ_CLASS_MAJ_HEALTH)
+     {
+        min = o->klass & BZ_OBJ_CLASS_MIN_HEALTH_MASK;
+        if (min == BZ_OBJ_CLASS_MIN_HEALTH_BLOOD_PRESSURE)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_THERMOMETER)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_SCALES)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_GLUCOSE)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_PULSE_OXIMITER)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_HEART_RATE)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_HEALTH_DATA_DISP)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_STEP)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_BODY_COMPOSITION)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_PEAK_FLOW)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_MEDICATION)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_KNEE_PROSTHESIS)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_ANKLE_PROSTHESIS)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_GENERIC_HEALTH)
+          s = "cpu";
+        else if (min == BZ_OBJ_CLASS_MIN_HEALTH_PRESONAL_MOBILITY)
+          s = "cpu";
+     }
+   elm_icon_standard_set(ic, s);
+   evas_object_size_hint_min_set(ic,
+                                 ELM_SCALE_SIZE(size),
+                                 ELM_SCALE_SIZE(size));
+   return ic;
+}
+
+Evas_Object *
+util_obj_icon_rssi_add(Evas_Object *base, Obj *o, int size)
+{
+   Evas_Object *ic = elm_icon_add(base);
+   char buf[64];
+   if (o->rssi <= -80)
+     elm_icon_standard_set(ic, "network-cellular-signal-excellent");
+   else if (o->rssi <= -72)
+     elm_icon_standard_set(ic, "network-cellular-signal-good");
+   else if (o->rssi <= -64)
+     elm_icon_standard_set(ic, "network-cellular-signal-ok");
+   else if (o->rssi <= -56)
+     elm_icon_standard_set(ic, "network-cellular-signal-weak");
+   else if (o->rssi <= -48)
+     elm_icon_standard_set(ic, "network-cellular-signal-none");
+   else
+     elm_icon_standard_set(ic, "network-cellular-signal-acquiring");
+   snprintf(buf, sizeof(buf), "RSSI: %i", (int)o->rssi);
+   elm_object_tooltip_text_set(ic, buf);
+   evas_object_size_hint_min_set(ic,
+                                 ELM_SCALE_SIZE(size),
+                                 ELM_SCALE_SIZE(size));
+   return ic;
+}
+
+Evas_Object *
+util_check_add(Evas_Object *base, const char *text, const char *tip, Eina_Bool 
state)
+{
+   Evas_Object *ck = elm_check_add(base);
+   evas_object_size_hint_align_set(ck, 0.0, EVAS_HINT_FILL);
+   elm_layout_text_set(ck, NULL, text);
+   elm_object_tooltip_text_set(ck, tip);
+   elm_check_state_set(ck, state);
+   return ck;
+}
+
+Evas_Object *
+util_button_icon_add(Evas_Object *base, const char *icon, const char *tip)
+{
+   Evas_Object *ic, *bt = elm_button_add(base);
+   ic = elm_icon_add(base);
+   evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_icon_standard_set(ic, icon);
+   elm_object_tooltip_text_set(bt, tip);
+   elm_object_part_content_set(bt, NULL, ic);
+   evas_object_show(ic);
+   return bt;
+}
+
+const char *
+util_obj_name_get(Obj *o)
+{
+   if (o->name) return o->name;
+   if (o->alias) return o->alias;
+   if (o->address) return o->address;
+   return _("Uknown");
+}
diff --git a/src/modules/bluez5/meson.build b/src/modules/bluez5/meson.build
new file mode 100644
index 000000000..f6cffcc37
--- /dev/null
+++ b/src/modules/bluez5/meson.build
@@ -0,0 +1,9 @@
+src = files(
+  'e_mod_main.c',
+  'e_mod_popup.c',
+  'e_mod_agent.c',
+  'e_mod_util.c',
+  'bz.c',
+  'bz_obj.c',
+  'bz_agent.c'
+)
diff --git a/src/modules/bluez5/module.desktop 
b/src/modules/bluez5/module.desktop
new file mode 100644
index 000000000..fd102a832
--- /dev/null
+++ b/src/modules/bluez5/module.desktop
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Type=Link
+Name=Bluez5
+Name[ca]=Bluez5
+Name[de]=Bluez5
+Name[fi]=Bluez5
+Name[gl]=Bluez5
+Name[ja]=Bluez5
+Name[ms]=Bluez5
+Name[sr]=Блуез5
+Name[tr]=Bluetooth
+Icon=e-module-bluez5
+X-Enlightenment-ModuleType=utils
diff --git a/src/modules/meson.build b/src/modules/meson.build
index 11b93df3f..4150367e7 100644
--- a/src/modules/meson.build
+++ b/src/modules/meson.build
@@ -34,6 +34,7 @@ mods = [
   'geolocation',
   'connman',
   'bluez4',
+  'bluez5',
   'syscon',
   'systray',
   'appmenu',

-- 


Reply via email to