elm: Support switching between local and D-Bus main menus on the fly
authorHenrique Dante de Almeida <hdante@profusion.mobi>
Tue, 22 Jan 2013 18:51:16 +0000 (18:51 +0000)
committerBruno Dilly <bdilly@profusion.mobi>
Tue, 22 Jan 2013 18:51:16 +0000 (18:51 +0000)
With this patch, the main menu now keeps listening for the app menu
registrar all the time. Whenever it's available, it tries to register
itself. If the registrar exits, the menu switches back to local mode.

Patch by: Henrique Dante de Almeida <hdante@profusion.mobi>

SVN revision: 83098

legacy/elementary/src/lib/elm_dbus_menu.c
legacy/elementary/src/lib/elm_menu.c
legacy/elementary/src/lib/elm_priv.h
legacy/elementary/src/lib/elm_win.c

index 19b74bf..e14507a 100644 (file)
@@ -17,6 +17,8 @@
 #define DBUS_DATA_KEY       "_Elm_DBus_Menu"
 #endif
 
+typedef struct _Callback_Data Callback_Data;
+
 struct _Elm_DBus_Menu
 {
 #ifdef ELM_EDBUS2
@@ -26,7 +28,7 @@ struct _Elm_DBus_Menu
    unsigned                 timestamp;
    Eina_Hash               *elements;
    Ecore_Idler             *signal_idler;
-   Ecore_X_Window           xid;
+   Callback_Data           *app_menu_data;
 #endif
 };
 
@@ -53,7 +55,9 @@ enum
 typedef struct _Callback_Data
 {
    void (*result_cb)(Eina_Bool, void *);
-   void *data;
+   void          *data;
+   EDBus_Pending *pending_register;
+   Ecore_X_Window xid;
 } Callback_Data;
 
 static Eina_Bool
@@ -82,10 +86,49 @@ static void
 _app_register_cb(void *data, const EDBus_Message *msg,
                  EDBus_Pending *pending EINA_UNUSED)
 {
-   Callback_Data *cd = data;
+   Elm_DBus_Menu *menu = data;
+   Callback_Data *cd = menu->app_menu_data;
+   Eina_Bool result;
+   const char *error_name;
 
-   cd->result_cb(!edbus_message_error_get(msg, NULL, NULL), cd->data);
-   free(cd);
+   cd->pending_register = NULL;
+
+   result = !edbus_message_error_get(msg, &error_name, NULL);
+   if (!result && !strcmp(error_name, EDBUS_ERROR_PENDING_CANCELED))
+     {
+        DBG("Register canceled");
+        return;
+     }
+
+   if (cd->result_cb) cd->result_cb(result, cd->data);
+}
+
+static void
+_app_menu_watch_cb(void *data, const char *bus EINA_UNUSED,
+                   const char *old_id EINA_UNUSED, const char *new_id)
+{
+   Elm_DBus_Menu *menu = data;
+   Callback_Data *cd = menu->app_menu_data;
+   EDBus_Message *msg;
+   const char *obj_path;
+
+   if (!strcmp(new_id, ""))
+     {
+        if (cd->pending_register) edbus_pending_cancel(cd->pending_register);
+
+        if (cd->result_cb) cd->result_cb(EINA_FALSE, cd->data);
+     }
+   else
+     {
+        msg = edbus_message_method_call_new(REGISTRAR_NAME, REGISTRAR_PATH,
+                                            REGISTRAR_INTERFACE,
+                                            "RegisterWindow");
+        obj_path = edbus_service_object_path_get(menu->iface);
+        edbus_message_arguments_append(msg, "uo", (unsigned)cd->xid,
+                                       obj_path);
+        cd->pending_register = edbus_connection_send(menu->bus, msg,
+                                                     _app_register_cb, data, -1);
+     }
 }
 
 static Eina_Bool
@@ -878,8 +921,8 @@ _elm_dbus_menu_unregister(Eo *obj)
 
    if (!sd->dbus_menu) return;
 
-   if (sd->dbus_menu->xid)
-     _elm_dbus_menu_app_menu_unregister(sd->dbus_menu->menu);
+   if (sd->dbus_menu->app_menu_data)
+     _elm_dbus_menu_app_menu_unregister(obj);
    edbus_service_interface_unregister(sd->dbus_menu->iface);
    edbus_connection_unref(sd->dbus_menu->bus);
    if (sd->dbus_menu->signal_idler)
@@ -894,8 +937,6 @@ void
 _elm_dbus_menu_app_menu_register(Ecore_X_Window xid, Eo *obj,
                                  void (*result_cb)(Eina_Bool, void *), void *data)
 {
-   EDBus_Message *msg;
-   const char *obj_path;
    Callback_Data *cd;
 
    ELM_MENU_CHECK(obj);
@@ -907,23 +948,31 @@ _elm_dbus_menu_app_menu_register(Ecore_X_Window xid, Eo *obj,
         return;
      }
 
-   msg = edbus_message_method_call_new(REGISTRAR_NAME, REGISTRAR_PATH,
-                                       REGISTRAR_INTERFACE, "RegisterWindow");
-   cd = malloc(sizeof(Callback_Data));
+   if (sd->dbus_menu->app_menu_data)
+     {
+        if (sd->dbus_menu->app_menu_data->xid != xid)
+          ERR("There's another XID registered: %x",
+              sd->dbus_menu->app_menu_data->xid);
+
+        return;
+     }
+
+   sd->dbus_menu->app_menu_data = malloc(sizeof(Callback_Data));
+   cd = sd->dbus_menu->app_menu_data;
    cd->result_cb = result_cb;
    cd->data = data;
-   obj_path = edbus_service_object_path_get(sd->dbus_menu->iface);
-   edbus_message_arguments_append(msg, "uo", (unsigned)xid,
-                                  obj_path);
-   edbus_connection_send(sd->dbus_menu->bus, msg, _app_register_cb,
-                         cd, -1);
-   sd->dbus_menu->xid = xid;
+   cd->pending_register = NULL;
+   cd->xid = xid;
+   edbus_name_owner_changed_callback_add(sd->dbus_menu->bus, REGISTRAR_NAME,
+                                         _app_menu_watch_cb, sd->dbus_menu,
+                                         EINA_TRUE);
 }
 
 void
 _elm_dbus_menu_app_menu_unregister(Eo *obj)
 {
    EDBus_Message *msg;
+   Callback_Data *cd;
 
    ELM_MENU_CHECK(obj);
    ELM_MENU_DATA_GET(obj, sd);
@@ -934,13 +983,21 @@ _elm_dbus_menu_app_menu_unregister(Eo *obj)
         return;
      }
 
-   if (!sd->dbus_menu->xid) return;
+   cd = sd->dbus_menu->app_menu_data;
+
+   if (!cd) return;
+
+   if (cd->pending_register)
+     edbus_pending_cancel(cd->pending_register);
 
    msg = edbus_message_method_call_new(REGISTRAR_NAME, REGISTRAR_PATH,
                                        REGISTRAR_INTERFACE, "UnregisterWindow");
-   edbus_message_arguments_append(msg, "u", (unsigned)sd->dbus_menu->xid);
+   edbus_message_arguments_append(msg, "u", (unsigned)cd->xid);
    edbus_connection_send(sd->dbus_menu->bus, msg, NULL, NULL, -1);
-   sd->dbus_menu->xid = 0;
+   edbus_name_owner_changed_callback_del(sd->dbus_menu->bus, REGISTRAR_NAME,
+                                         _app_menu_watch_cb, sd->dbus_menu);
+   free(cd);
+   sd->dbus_menu->app_menu_data = NULL;
 }
 
 int
index 5ca1fc7..144314f 100644 (file)
@@ -611,6 +611,16 @@ _elm_menu_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
 }
 
 void
+_elm_menu_menu_bar_hide(Eo *obj)
+{
+  ELM_MENU_DATA_GET_OR_RETURN(obj, sd);
+
+  evas_object_hide(sd->hv);
+  evas_object_hide(obj);
+  _menu_hide(obj, NULL, NULL);
+}
+
+void
 _elm_menu_menu_bar_set(Eo *obj, Eina_Bool menu_bar)
 {
    Eina_List *l;
index 4d4780b..62899bb 100644 (file)
@@ -415,6 +415,7 @@ void                 _elm_dbus_menu_app_menu_unregister(Eo *obj);
 void                 _elm_dbus_menu_item_select_cb(Elm_Object_Item *obj_item);
 
 void                 _elm_menu_menu_bar_set(Eo *obj, Eina_Bool menu_bar);
+void                 _elm_menu_menu_bar_hide(Eo *obj);
 
 /* DEPRECATED, will be removed on next release */
 void                 _elm_icon_signal_emit(Evas_Object *obj,
index ca982c1..0c36d38 100644 (file)
@@ -3573,22 +3573,23 @@ elm_win_main_menu_get(const Evas_Object *obj)
 }
 
 static void
-_local_menu_set(Eo *obj)
+_dbus_menu_set(Eina_Bool connect, void *data)
 {
-   ELM_WIN_DATA_GET_OR_RETURN(obj, sd);
+   ELM_WIN_DATA_GET_OR_RETURN(data, sd);
 
-   edje_object_part_swallow(sd->layout, "elm.swallow.menu", sd->main_menu);
-   edje_object_signal_emit(sd->layout, "elm,action,show_menu", "elm");
-   _elm_menu_menu_bar_set(sd->main_menu, EINA_TRUE);
-}
-
-static void
-_dbus_result_cb(Eina_Bool result, void *data)
-{
-   if (!result)
+   if (connect)
      {
-        ERR("D-Bus menu error. Using local menu");
-        _local_menu_set(data);
+        DBG("Setting menu to D-Bus");
+        edje_object_part_unswallow(sd->layout, sd->main_menu);
+        edje_object_signal_emit(sd->layout, "elm,action,hide_menu", "elm");
+        _elm_menu_menu_bar_hide(sd->main_menu);
+     }
+   else
+     {
+        DBG("Setting menu to local mode");
+        edje_object_part_swallow(sd->layout, "elm.swallow.menu", sd->main_menu);
+        edje_object_signal_emit(sd->layout, "elm,action,show_menu", "elm");
+        evas_object_show(sd->main_menu);
      }
 }
 
@@ -3602,19 +3603,19 @@ _main_menu_get(Eo *obj, void *_pd, va_list *list)
    if (sd->main_menu) goto end;
 
    sd->main_menu = elm_menu_add(obj);
+   _elm_menu_menu_bar_set(sd->main_menu, EINA_TRUE);
 
 #ifdef HAVE_ELEMENTARY_X
    if (_elm_config->external_menu && sd->x.xwin) use_dbus = EINA_TRUE;
 #endif
 
-   if (use_dbus)
+   if (use_dbus && _elm_dbus_menu_register(sd->main_menu))
      {
-        _elm_dbus_menu_register(sd->main_menu);
         _elm_dbus_menu_app_menu_register(sd->x.xwin, sd->main_menu,
-                                         _dbus_result_cb, obj);
+                                         _dbus_menu_set, obj);
      }
    else
-     _local_menu_set(obj);
+     _dbus_menu_set(EINA_FALSE, obj);
 
 end:
    *ret = sd->main_menu;