From ef8cc77790101edaf2d3fc40ebe5521ab7d08372 Mon Sep 17 00:00:00 2001 From: Dave Andreoli Date: Sat, 12 Aug 2017 19:28:16 +0200 Subject: [PATCH] pkit gadget: add ability to install updated directly from the gadget ! You can install all updates or select the packages you like. The update work without asking any password, if it doesn't works check the org.freedesktop.packagekit.system-update Polkit permission (work out-of-the-box on Arch Linux, just install packagekit) --- src/modules/packagekit/e_mod_packagekit.c | 192 +++++++++++++++++++++- src/modules/packagekit/e_mod_packagekit.h | 14 +- 2 files changed, 198 insertions(+), 8 deletions(-) diff --git a/src/modules/packagekit/e_mod_packagekit.c b/src/modules/packagekit/e_mod_packagekit.c index 39e21aa96..96925677d 100644 --- a/src/modules/packagekit/e_mod_packagekit.c +++ b/src/modules/packagekit/e_mod_packagekit.c @@ -63,6 +63,39 @@ _update_button_cb(void *data, Evas_Object *obj EINA_UNUSED, packagekit_create_transaction_and_exec(inst->ctxt, packagekit_refresh_cache); } +static void +_install_button_cb(void *data, Evas_Object *obj EINA_UNUSED, + void *event EINA_UNUSED) +{ + E_PackageKit_Instance *inst = data; + E_PackageKit_Package *pkg; + const Eina_List *selected; + Elm_Genlist_Item *item; + Eina_List *l; + + selected = elm_genlist_selected_items_get(inst->popup_genlist); + if (!selected) + { + // nothing selected, update all packages + EINA_LIST_FOREACH(inst->ctxt->packages, l, pkg) + pkg->to_be_installed = EINA_TRUE; + } + else + { + // only updated selected packages + EINA_LIST_FOREACH(inst->ctxt->packages, l, pkg) + pkg->to_be_installed = EINA_FALSE; + EINA_LIST_FOREACH((Eina_List*)selected, l, item) + { + pkg = elm_object_item_data_get(item); + pkg->to_be_installed = EINA_TRUE; + } + } + + packagekit_create_transaction_and_exec(inst->ctxt, packagekit_update_packages); + packagekit_popup_del(inst); +} + static void _run_button_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) @@ -81,14 +114,18 @@ _run_button_cb(void *data, Evas_Object *obj EINA_UNUSED, } void -packagekit_popup_update(E_PackageKit_Instance *inst) +packagekit_popup_update(E_PackageKit_Instance *inst, Eina_Bool rebuild_list) { E_PackageKit_Module_Context *ctxt = inst->ctxt; E_PackageKit_Package *pkg; + const Eina_List *selected; unsigned num_updates = 0; char buf[1024]; Eina_List *l; + if (rebuild_list) + elm_genlist_clear(inst->popup_genlist); + if (ctxt->error) { elm_object_text_set(inst->popup_label, _("No information available")); @@ -104,16 +141,52 @@ packagekit_popup_update(E_PackageKit_Instance *inst) EINA_LIST_FOREACH(ctxt->packages, l, pkg) { - elm_genlist_item_append(inst->popup_genlist, inst->popup_genlist_itc, - pkg, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + if (rebuild_list) + elm_genlist_item_append(inst->popup_genlist, inst->popup_genlist_itc, + pkg, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); num_updates++; } + // update title and error lables if (num_updates >= 1) snprintf(buf, sizeof(buf), P_("One update available", "%d updates available", num_updates), num_updates); else snprintf(buf, sizeof(buf), _("Your system is updated")); elm_object_text_set(inst->popup_label, buf); + elm_object_text_set(inst->popup_error_label, ""); + + // update the status of the install button + selected = elm_genlist_selected_items_get(inst->popup_genlist); + if (num_updates < 1) + { + elm_object_text_set(inst->popup_install_button, _("Nothing to do")); + elm_object_disabled_set(inst->popup_install_button, EINA_TRUE); + } + else if ((selected == NULL) || (eina_list_count(selected) == 0)) + { + elm_object_text_set(inst->popup_install_button, + _("Install all available updates")); + elm_object_disabled_set(inst->popup_install_button, EINA_FALSE); + } + else if (eina_list_count(selected) > 0) + { + snprintf(buf, sizeof(buf), P_("Install the selected update", + "Install %d selected updates", + eina_list_count(selected)), + eina_list_count(selected)); + elm_object_text_set(inst->popup_install_button, buf); + elm_object_disabled_set(inst->popup_install_button, EINA_FALSE); + } +} + +void +packagekit_all_popups_update(E_PackageKit_Module_Context *ctxt) +{ + E_PackageKit_Instance *inst; + Eina_List *l; + + EINA_LIST_FOREACH(ctxt->instances, l, inst) + packagekit_popup_update(inst, EINA_TRUE); } static void @@ -217,6 +290,13 @@ _gl_item_content_get(void *data, Evas_Object *obj, const char *part) return NULL; } +static void +_genlist_selunsel_cb(void *data, Evas_Object *obj EINA_UNUSED, + void *event EINA_UNUSED) +{ + packagekit_popup_update(data, EINA_FALSE); +} + void packagekit_popup_new(E_PackageKit_Instance *inst) { @@ -275,17 +355,25 @@ packagekit_popup_new(E_PackageKit_Instance *inst) elm_genlist_multi_select_set(li, EINA_TRUE); E_EXPAND(li); E_FILL(li); + evas_object_smart_callback_add(li, "selected", _genlist_selunsel_cb, inst); + evas_object_smart_callback_add(li, "unselected", _genlist_selunsel_cb, inst); elm_table_pack(table, li, 0, 1, 2, 1); evas_object_show(li); + bt = inst->popup_install_button = elm_button_add(table); + evas_object_size_hint_fill_set(bt, EVAS_HINT_FILL, 0.0); + evas_object_smart_callback_add(bt, "clicked", _install_button_cb, inst); + elm_table_pack(table, bt, 0, 2, 2, 1); + evas_object_show(bt); + bt = elm_button_add(table); evas_object_size_hint_fill_set(bt, EVAS_HINT_FILL, 0.0); elm_object_text_set(bt, _("Run the package manager")); evas_object_smart_callback_add(bt, "clicked", _run_button_cb, inst); - elm_table_pack(table, bt, 0, 2, 2, 1); + elm_table_pack(table, bt, 0, 3, 2, 1); evas_object_show(bt); - packagekit_popup_update(inst); + packagekit_popup_update(inst, EINA_TRUE); e_gadcon_popup_content_set(inst->popup, table); e_comp_object_util_autoclose(inst->popup->comp_object, @@ -309,6 +397,7 @@ packagekit_popup_del(E_PackageKit_Instance *inst) } +/* DBus PackageKit */ static void _store_error(E_PackageKit_Module_Context *ctxt, const char *err) { @@ -318,10 +407,9 @@ _store_error(E_PackageKit_Module_Context *ctxt, const char *err) else ctxt->error = eina_stringshare_add(err); packagekit_icon_update(ctxt, EINA_FALSE); + packagekit_all_popups_update(ctxt); } - -/* RefreshCache() */ static void null_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { @@ -332,6 +420,7 @@ null_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUS _store_error(ctxt, error_msg); } +/* RefreshCache() */ static void signal_repo_detail_cb(void *data, const Eldbus_Message *msg) { /* RepoDetail ('s'repo_id, 's'description, 'b'enabled) */ @@ -430,6 +519,7 @@ _signal_package_cb(void *data, const Eldbus_Message *msg) if (num_elements >= 2) { E_PackageKit_Package *pkg = E_NEW(E_PackageKit_Package, 1); + pkg->pkg_id = eina_stringshare_add(pkg_id); pkg->name = eina_stringshare_add(splitted[0]); pkg->version = eina_stringshare_add(splitted[1]); pkg->summary = eina_stringshare_add(summary); @@ -475,6 +565,7 @@ _signal_finished_cb(void *data, const Eldbus_Message *msg) //DBG("PKGKIT: PackageFinished"); packagekit_icon_update(ctxt, EINA_FALSE); + packagekit_all_popups_update(ctxt); } void @@ -503,6 +594,7 @@ packagekit_get_updates(E_PackageKit_Module_Context *ctxt, const char *transactio EINA_LIST_FREE(ctxt->packages, pkg) { + E_FREE_FUNC(pkg->pkg_id, eina_stringshare_del); E_FREE_FUNC(pkg->name, eina_stringshare_del); E_FREE_FUNC(pkg->version, eina_stringshare_del); E_FREE_FUNC(pkg->summary, eina_stringshare_del); @@ -510,6 +602,92 @@ packagekit_get_updates(E_PackageKit_Module_Context *ctxt, const char *transactio } +/* UpdatePackages */ +static void +_signal_update_error_code_cb(void *data, const Eldbus_Message *msg) +{ /* ErrorCode ('u'code, 's'details) */ + const char *error, *error_msg, *details; + E_PackageKit_Module_Context *ctxt = data; + Eina_Bool ret; + int err_code; + + if (eldbus_message_error_get(msg, &error, &error_msg)) + { + _store_error(ctxt, error_msg); + return; + } + + ret = eldbus_message_arguments_get(msg, "us", &err_code, &details); + if (!ret) + { + _store_error(ctxt, "could not get error code arguments"); + return; + } + + if (details) + _store_error(ctxt, details); +} + +static void +_signal_update_finished_cb(void *data, const Eldbus_Message *msg) +{ /* Finished ('u'exit, 'u'runtime) */ + const char *error, *error_msg; + E_PackageKit_Module_Context *ctxt = data; + + if (eldbus_message_error_get(msg, &error, &error_msg)) + _store_error(ctxt, error_msg); + else + E_FREE_FUNC(ctxt->error, eina_stringshare_del); + + Eldbus_Object *obj = eldbus_proxy_object_get(ctxt->transaction); + E_FREE_FUNC(ctxt->transaction, eldbus_proxy_unref); + E_FREE_FUNC(obj, eldbus_object_unref); +} + +void +packagekit_update_packages(E_PackageKit_Module_Context *ctxt, const char *transaction) +{ + Eldbus_Object *obj; + Eldbus_Proxy *proxy; + Eldbus_Message *msg; + Eldbus_Message_Iter *iter, *array_of_string; + Eldbus_Pending *pending; + E_PackageKit_Package *pkg; + Eina_List *l; + + fprintf(stderr, "PKIT: UpdatePackages (t:%s)\n", transaction); + + obj = eldbus_object_get(ctxt->conn, "org.freedesktop.PackageKit", transaction); + proxy = eldbus_proxy_get(obj, "org.freedesktop.PackageKit.Transaction"); + msg = eldbus_proxy_method_call_new(proxy, "UpdatePackages"); + iter = eldbus_message_iter_get(msg); + eldbus_message_iter_arguments_append(iter, "tas", + PK_TRANSACTION_FLAG_ENUM_ONLY_TRUSTED, + &array_of_string); + EINA_LIST_FOREACH(ctxt->packages, l, pkg) + { + if (pkg->to_be_installed) + { + DBG("Install: %s %s", pkg->pkg_id, pkg->version); + eldbus_message_iter_arguments_append(array_of_string, "s", pkg->pkg_id); + } + } + eldbus_message_iter_container_close(iter, array_of_string); + + pending = eldbus_proxy_send(proxy, msg, null_cb, ctxt, -1); + if (!pending) + { + _store_error(ctxt, "could not call UpdatePackages()"); + return; + } + + // TODO: monitor the PropertiesChanged for "Percentage" on the Transaction + // object and show a progress bar! + eldbus_proxy_signal_handler_add(proxy, "ErrorCode", _signal_update_error_code_cb, ctxt); + eldbus_proxy_signal_handler_add(proxy, "Finished", _signal_update_finished_cb, ctxt); + ctxt->transaction = proxy; +} + /* CreateTransaction() */ static void _transaction_created_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) diff --git a/src/modules/packagekit/e_mod_packagekit.h b/src/modules/packagekit/e_mod_packagekit.h index 08a8e6d71..5d9d596be 100644 --- a/src/modules/packagekit/e_mod_packagekit.h +++ b/src/modules/packagekit/e_mod_packagekit.h @@ -7,6 +7,14 @@ #define PKITV07 (ctxt->v_maj == 0) && (ctxt->v_min == 7) #define PKITV08 (ctxt->v_maj == 0) && (ctxt->v_min == 8) +// PackageKit dbus interface contains bitfield constants which +// aren't introspectable. we define here. still cannot find the proper doc! +#define PK_PROVIDES_ANY 1 +#define PK_FILTER_ENUM_NOT_INSTALLED 1 << 3 +#define PK_FILTER_ENUM_NEWEST 1 << 16 +#define PK_FILTER_ENUM_ARCH 1 << 18 +#define PK_TRANSACTION_FLAG_ENUM_ONLY_TRUSTED 1 << 1 + typedef enum { PK_INFO_ENUM_UNKNOWN, PK_INFO_ENUM_INSTALLED, @@ -72,16 +80,19 @@ typedef struct _E_PackageKit_Instance E_Gadcon_Popup *popup; Evas_Object *popup_label; Evas_Object *popup_error_label; + Evas_Object *popup_install_button; Evas_Object *popup_genlist; Elm_Genlist_Item_Class *popup_genlist_itc; } E_PackageKit_Instance; typedef struct _E_PackageKit_Package { + const char *pkg_id; const char *name; const char *summary; const char *version; PackageKit_Package_Info info; + Eina_Bool to_be_installed; } E_PackageKit_Package; @@ -95,10 +106,11 @@ void packagekit_create_transaction_and_exec(E_PackageKit_Module_Context *ct E_PackageKit_Transaction_Func func); void packagekit_get_updates(E_PackageKit_Module_Context *ctxt, const char *transaction); void packagekit_refresh_cache(E_PackageKit_Module_Context *ctxt, const char *transaction); +void packagekit_update_packages(E_PackageKit_Module_Context *ctxt, const char *transaction); void packagekit_icon_update(E_PackageKit_Module_Context *ctxt, Eina_Bool working); void packagekit_popup_new(E_PackageKit_Instance *inst); void packagekit_popup_del(E_PackageKit_Instance *inst); -void packagekit_popup_update(E_PackageKit_Instance *inst); +void packagekit_popup_update(E_PackageKit_Instance *inst, Eina_Bool rebuild_list); #endif