/** * asb_plugin_process_app: */ gboolean asb_plugin_process_app (AsbPlugin *plugin, AsbPackage *pkg, AsbApp *app, const gchar *tmpdir, GError **error) { gchar **filelist; guint i; filelist = asb_package_get_filelist (pkg); for (i = 0; filelist[i] != NULL; i++) { GError *error_local = NULL; _cleanup_free_ gchar *filename = NULL; if (!g_str_has_prefix (filelist[i], "/usr/bin/")) continue; if (as_app_get_metadata_item (AS_APP (app), "X-Kudo-UsesAppMenu") != NULL) break; filename = g_build_filename (tmpdir, filelist[i], NULL); if (!asb_plugin_nm_app (app, filename, &error_local)) { asb_package_log (pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to run nm on %s: %s", filename, error_local->message); g_clear_error (&error_local); } } return TRUE; }
/** * asb_plugin_process_app: */ gboolean asb_plugin_process_app (AsbPlugin *plugin, AsbPackage *pkg, AsbApp *app, const gchar *tmpdir, GError **error) { gchar **filelist; guint i; filelist = asb_package_get_filelist (pkg); for (i = 0; filelist[i] != NULL; i++) { GError *error_local = NULL; g_autofree gchar *filename = NULL; if (!asb_plugin_match_glob ("/usr/bin/*", filelist[i])) continue; if (as_app_has_kudo_kind (AS_APP (app), AS_KUDO_KIND_APP_MENU)) break; filename = g_build_filename (tmpdir, filelist[i], NULL); if (!asb_plugin_gresource_app (app, filename, &error_local)) { asb_package_log (pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to get resources from %s: %s", filename, error_local->message); g_clear_error (&error_local); } } return TRUE; }
/** * asb_plugin_merge: */ void asb_plugin_merge (AsbPlugin *plugin, GList *list) { AsApp *app; AsApp *found; GList *l; const gchar *tmp; _cleanup_hashtable_unref_ GHashTable *hash = NULL; /* add all packages to the hash */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_vetos (app)->len > 0) continue; tmp = as_app_get_pkgname_default (app); if (tmp == NULL) continue; found = g_hash_table_lookup (hash, tmp); if (found != NULL) { /* ignore duplicates */ if (g_strcmp0 (as_app_get_id (app), as_app_get_id (found)) == 0) { continue; } asb_plugin_composite_app (app, found); continue; } g_hash_table_insert (hash, g_strdup (as_app_get_pkgname_default (app)), g_object_ref (app)); } }
gboolean asb_plugin_process_app (AsbPlugin *plugin, AsbPackage *pkg, AsbApp *app, const gchar *tmpdir, GError **error) { guint i; const gchar *app_dirs[] = { "/usr/share/applications", "/usr/share/applications/kde4", NULL }; /* use the .desktop file to refine the application */ for (i = 0; app_dirs[i] != NULL; i++) { g_autofree gchar *fn = NULL; fn = g_build_filename (tmpdir, app_dirs[i], as_app_get_id (AS_APP (app)), NULL); if (g_file_test (fn, G_FILE_TEST_EXISTS)) { if (!asb_plugin_desktop_refine (plugin, pkg, fn, app, tmpdir, error)) return FALSE; } } return TRUE; }
/** * asb_plugin_process_gir: */ static gboolean asb_plugin_process_gir (AsbApp *app, const gchar *tmpdir, const gchar *filename, GError **error) { GNode *l; GNode *node = NULL; const gchar *name; const gchar *version; gboolean ret = TRUE; g_autofree gchar *filename_full = NULL; g_autoptr(GFile) file = NULL; /* load file */ filename_full = g_build_filename (tmpdir, filename, NULL); file = g_file_new_for_path (filename_full); node = as_node_from_file (file, AS_NODE_FROM_XML_FLAG_NONE, NULL, error); if (node == NULL) { ret = FALSE; goto out; } /* look for includes */ l = as_node_find (node, "repository"); if (l == NULL) goto out; for (l = l->children; l != NULL; l = l->next) { if (g_strcmp0 (as_node_get_name (l), "include") != 0) continue; name = as_node_get_attribute (l, "name"); version = as_node_get_attribute (l, "version"); if (g_strcmp0 (name, "Gtk") == 0 && g_strcmp0 (version, "3.0") == 0) { asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_DEBUG, "Auto-adding kudo ModernToolkit for %s", as_app_get_id (AS_APP (app))); as_app_add_kudo_kind (AS_APP (app), AS_KUDO_KIND_MODERN_TOOLKIT); } } out: if (node != NULL) as_node_unref (node); return ret; }
/** * asb_context_add_app: * @ctx: A #AsbContext * @app: A #AsbApp * * Adds an application to the context. * * Since: 0.1.0 **/ void asb_context_add_app (AsbContext *ctx, AsbApp *app) { AsbContextPrivate *priv = GET_PRIVATE (ctx); g_mutex_lock (&priv->apps_mutex); asb_plugin_add_app (&priv->apps, AS_APP (app)); g_mutex_unlock (&priv->apps_mutex); }
/** * asb_plugin_merge: */ void asb_plugin_merge (AsbPlugin *plugin, GList *list) { AsApp *app; AsApp *found; GList *l; const gchar *tmp; _cleanup_hashtable_unref_ GHashTable *hash = NULL; /* add X-Merge-With-Parent on any metainfo files that are in a package * required by a desktop package */ asb_plugin_merge_prepare_deps (list); /* add all packages to the hash */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); g_hash_table_insert (hash, g_strdup (as_app_get_id (app)), g_object_ref (app)); } /* absorb some apps into their parent */ for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); /* no absorb metadata */ tmp = as_app_get_metadata_item (app, "X-Merge-With-Parent"); if (tmp == NULL) continue; /* find the parent app */ found = g_hash_table_lookup (hash, tmp); if (found == NULL) { as_app_add_veto (app, "No referenced '%s'", tmp); continue; } /* partially absorb */ as_app_add_veto (app, "partially absorbing %s into %s", as_app_get_id (app), as_app_get_id (found)); as_app_subsume_full (found, app, AS_APP_SUBSUME_FLAG_PARTIAL); } }
static gboolean asb_plugin_process_filename (AsbPlugin *plugin, AsbPackage *pkg, const gchar *filename, GList **apps, GError **error) { gsize len; g_autoptr(AsbApp) app = NULL; g_autofree gchar *data = NULL; app = asb_app_new (pkg, NULL); if (!g_file_get_contents (filename, &data, &len, error)) return FALSE; if (!as_app_parse_shell_extension_data (plugin, AS_APP (app), data, len, error)) return FALSE; asb_plugin_add_app (apps, AS_APP (app)); return TRUE; }
/** * asb_plugin_process_filename: */ static gboolean asb_plugin_process_filename (const gchar *filename, AsbApp *app, GError **error) { g_autofree gchar *app_runtime = NULL; g_autofree gchar *app_sdk = NULL; g_autoptr(GKeyFile) kf = NULL; kf = g_key_file_new (); if (!g_key_file_load_from_file (kf, filename, G_KEY_FILE_NONE, error)) return FALSE; app_runtime = g_key_file_get_string (kf, "Application", "runtime", NULL); if (app_runtime != NULL) as_app_add_metadata (AS_APP (app), "BundleRuntime", app_runtime); app_sdk = g_key_file_get_string (kf, "Application", "sdk", NULL); if (app_sdk != NULL) as_app_add_metadata (AS_APP (app), "BundleSDK", app_sdk); if (g_key_file_get_string (kf, "Environment", "network", NULL)) as_app_add_permission (AS_APP (app), "network"); return TRUE; }
/** * asb_plugin_merge: */ void asb_plugin_merge (AsbPlugin *plugin, GList *list) { AsApp *app; AsApp *found; GList *l; _cleanup_hashtable_unref_ GHashTable *hash = NULL; /* make a hash table of ID->AsApp */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_id_kind (app) != AS_ID_KIND_DESKTOP) continue; g_hash_table_insert (hash, g_strdup (as_app_get_id (app)), g_object_ref (app)); } /* add addons where the pkgname is different from the * main package */ for (l = list; l != NULL; l = l->next) { if (!ASB_IS_APP (l->data)) continue; app = AS_APP (l->data); if (as_app_get_id_kind (app) != AS_ID_KIND_ADDON) continue; found = g_hash_table_lookup (hash, as_app_get_id (app)); if (found == NULL) continue; if (g_strcmp0 (as_app_get_pkgname_default (app), as_app_get_pkgname_default (found)) != 0) continue; as_app_add_veto (app, "absorbing addon %s shipped in " "main package %s", as_app_get_id (app), as_app_get_pkgname_default (app)); as_app_subsume_full (found, app, AS_APP_SUBSUME_FLAG_PARTIAL); } }
/** * asb_plugin_process_filename: */ static gboolean asb_plugin_process_filename (const gchar *filename, AsbApp *app, const gchar *tmpdir, GError **error) { g_autofree gchar *types = NULL; g_autoptr(GKeyFile) kf = NULL; kf = g_key_file_new (); if (!g_key_file_load_from_file (kf, filename, G_KEY_FILE_NONE, error)) return FALSE; types = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, "X-KDE-ServiceTypes", NULL); if (types == NULL) return TRUE; if (g_strcmp0 (types, "Plasma/Runner") != 0) return TRUE; asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_DEBUG, "Auto-adding kudo SearchProvider for %s", as_app_get_id (AS_APP (app))); as_app_add_kudo_kind (AS_APP (app), AS_KUDO_KIND_SEARCH_PROVIDER); return TRUE; }
/** * as_app_infer_file_key: **/ static gboolean as_app_infer_file_key (AsApp *app, GKeyFile *kf, const gchar *key, GError **error) { g_autofree gchar *tmp = NULL; if (g_strcmp0 (key, "X-GNOME-UsesNotifications") == 0) { as_app_add_kudo_kind (AS_APP (app), AS_KUDO_KIND_NOTIFICATIONS); } else if (g_strcmp0 (key, "X-GNOME-Bugzilla-Bugzilla") == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (g_strcmp0 (tmp, "GNOME") == 0) as_app_set_project_group (app, "GNOME"); } else if (g_strcmp0 (key, "X-MATE-Bugzilla-Product") == 0) { as_app_set_project_group (app, "MATE"); } else if (g_strcmp0 (key, "X-KDE-StartupNotify") == 0) { as_app_set_project_group (app, "KDE"); } else if (g_strcmp0 (key, "X-DocPath") == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (g_str_has_prefix (tmp, "http://userbase.kde.org/")) as_app_set_project_group (app, "KDE"); /* Exec */ } else if (g_strcmp0 (key, G_KEY_FILE_DESKTOP_KEY_EXEC) == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (g_str_has_prefix (tmp, "xfce4-")) as_app_set_project_group (app, "XFCE"); } return TRUE; }
/** * asb_context_write_xml_fail: **/ static gboolean asb_context_write_xml_fail (AsbContext *ctx, GError **error) { AsApp *app; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; g_autofree gchar *basename_failed = NULL; g_autofree gchar *filename = NULL; g_autoptr(GFile) file = NULL; /* no need to create */ if ((priv->flags & ASB_CONTEXT_FLAG_INCLUDE_FAILED) == 0) return TRUE; for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); if (!ASB_IS_APP (app)) continue; if (as_app_get_vetos(app)->len == 0) continue; if (as_store_get_app_by_id (priv->store_failed, as_app_get_id (app)) != NULL) continue; as_store_add_app (priv->store_failed, app); } filename = g_strdup_printf ("%s/%s-failed.xml.gz", priv->output_dir, priv->basename); file = g_file_new_for_path (filename); g_print ("Writing %s...\n", filename); basename_failed = g_strdup_printf ("%s-failed", priv->origin); as_store_set_origin (priv->store_failed, basename_failed); as_store_set_api_version (priv->store_failed, priv->api_version); if (priv->flags & ASB_CONTEXT_FLAG_ADD_CACHE_ID) { g_autofree gchar *builder_id = asb_utils_get_builder_id (); as_store_set_builder_id (priv->store_failed, builder_id); } return as_store_to_file (priv->store_failed, file, AS_NODE_TO_XML_FLAG_ADD_HEADER | AS_NODE_TO_XML_FLAG_FORMAT_INDENT | AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE, NULL, error); }
/** * asb_plugin_merge_prepare_deps: */ static void asb_plugin_merge_prepare_deps (GList *list) { AsApp *app; AsbPackage *pkg; GList *l; for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_id_kind (app) != AS_ID_KIND_DESKTOP) continue; if (!ASB_IS_APP (app)) continue; if (as_app_get_vetos(app)->len > 0) continue; pkg = asb_app_get_package (ASB_APP (app)); asb_plugin_absorb_parent_for_pkgname (list, app, asb_package_get_name (pkg)); } }
/** * asb_plugin_merge_prepare_deps: */ static void asb_plugin_merge_prepare_deps (GList *list) { AsApp *app; AsbPackage *pkg; GList *l; gchar **deps; guint i; for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_id_kind (app) != AS_ID_KIND_DESKTOP) continue; pkg = asb_app_get_package (ASB_APP (app)); deps = asb_package_get_deps (pkg); for (i = 0; deps[i] != NULL; i++) asb_plugin_absorb_parent_for_pkgname (list, app, deps[i]); } }
/** * asb_context_detect_missing_data: **/ static gboolean asb_context_detect_missing_data (AsbContext *ctx, GError **error) { AsApp *app; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; /* look for the thing that an addon extends */ for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_name (AS_APP (app), "C") == NULL) as_app_add_veto (AS_APP (app), "No <name> in AppData"); if (as_app_get_comment (AS_APP (app), "C") == NULL) as_app_add_veto (AS_APP (app), "No <summary> in AppData"); if (as_app_get_id_kind (AS_APP (app)) != AS_ID_KIND_ADDON) { if (as_app_get_icon_default (AS_APP (app)) == NULL) as_app_add_veto (AS_APP (app), "Has no Icon"); } } return TRUE; }
/** * asb_context_add_app_ignore: **/ void asb_context_add_app_ignore (AsbContext *ctx, AsbPackage *pkg) { AsApp *app_tmp; AsbContextPrivate *priv = GET_PRIVATE (ctx); g_autofree gchar *name_arch = NULL; g_autoptr(AsApp) app = NULL; g_autoptr(GPtrArray) apps = NULL; /* only do this when we are using a cache-id */ if ((priv->flags & ASB_CONTEXT_FLAG_ADD_CACHE_ID) == 0) return; /* check not already added a dummy application for this package */ apps = as_store_get_apps_by_metadata (priv->store_ignore, "X-CacheID", asb_package_get_basename (pkg)); if (apps->len > 0) { g_debug ("already found CacheID of %s", asb_package_get_basename (pkg)); return; } /* package name already exists, but with a different CacheID */ name_arch = g_strdup_printf ("%s.%s", asb_package_get_name (pkg), asb_package_get_arch (pkg)); app_tmp = as_store_get_app_by_id (priv->store_ignore, name_arch); if (app_tmp != NULL) { as_app_add_metadata (AS_APP (app_tmp), "X-CacheID", asb_package_get_basename (pkg)); return; } /* never encountered before, so add */ app = as_app_new (); as_app_set_id (app, name_arch); as_app_add_pkgname (app, asb_package_get_name (pkg)); as_app_add_metadata (app, "X-CacheID", asb_package_get_basename (pkg)); as_store_add_app (priv->store_ignore, app); }
/** * asb_plugin_absorb_parent_for_pkgname: */ static void asb_plugin_absorb_parent_for_pkgname (GList *list, AsApp *parent, const gchar *pkgname) { AsApp *app; GList *l; for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_id_kind (app) != AS_ID_KIND_ADDON) continue; if (g_strcmp0 (as_app_get_pkgname_default (app), pkgname) != 0) continue; g_debug ("Adding X-Merge-With-Parent on %s as %s depends on %s", as_app_get_id_full (app), as_app_get_pkgname_default (parent), as_app_get_pkgname_default (app)); as_app_add_metadata (app, "X-Merge-With-Parent", as_app_get_id_full (parent), -1); } }
/** * asb_context_convert_icons: **/ static gboolean asb_context_convert_icons (AsbContext *ctx, GError **error) { AsApp *app; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; /* not enabled */ if ((priv->flags & ASB_CONTEXT_FLAG_EMBEDDED_ICONS) == 0) return TRUE; /* convert each one before saving resources */ for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_vetos(app)->len > 0) continue; if (!as_app_convert_icons (app, AS_ICON_KIND_EMBEDDED, error)) return FALSE; } return TRUE; }
/** * as_app_builder_search_provides: * @app: an #AsApp * @prefix: a prefix to search, e.g. "/usr" * @flags: #AsAppBuilderFlags, e.g. %AS_APP_BUILDER_FLAG_USE_FALLBACKS * @error: a #GError or %NULL * * Searches a prefix for auto-detected provides. * * Returns: %TRUE for success * * Since: 0.5.8 **/ gboolean as_app_builder_search_provides (AsApp *app, const gchar *prefix, AsAppBuilderFlags flags, GError **error) { /* skip for addons */ if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_ADDON) return TRUE; if (!as_app_builder_search_dbus (app, prefix, "share/dbus-1/system-services", AS_PROVIDE_KIND_DBUS_SYSTEM, flags, error)) return FALSE; if (!as_app_builder_search_dbus (app, prefix, "share/dbus-1/services", AS_PROVIDE_KIND_DBUS_SESSION, flags, error)) return FALSE; return TRUE; }
/** * asb_context_save_resources: **/ static gboolean asb_context_save_resources (AsbContext *ctx, GError **error) { AsApp *app; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); /* save icon */ if (as_app_get_vetos(app)->len > 0) continue; if (!ASB_IS_APP (app)) continue; if (!asb_app_save_resources (ASB_APP (app), ASB_APP_SAVE_FLAG_ICONS, error)) return FALSE; } return TRUE; }
/** * asb_plugin_process_app: */ gboolean asb_plugin_process_app (AsbPlugin *plugin, AsbPackage *pkg, AsbApp *app, const gchar *tmpdir, GError **error) { gchar **filelist; guint i; /* already set */ if (as_app_has_kudo_kind (AS_APP (app), AS_KUDO_KIND_SEARCH_PROVIDER)) return TRUE; /* look for a krunner provider */ filelist = asb_package_get_filelist (pkg); for (i = 0; filelist[i] != NULL; i++) { g_autoptr(GError) error_local = NULL; g_autofree gchar *filename = NULL; if (!asb_plugin_match_glob ("/usr/share/kde4/services/*.desktop", filelist[i])) continue; filename = g_build_filename (tmpdir, filelist[i], NULL); if (!asb_plugin_process_filename (filename, app, tmpdir, &error_local)) { asb_package_log (pkg, ASB_PACKAGE_LOG_LEVEL_INFO, "Failed to read KDE service file %s: %s", filelist[i], error_local->message); g_clear_error (&error_local); } } return TRUE; }
/** * asb_plugin_hardcoded_add_screenshots: */ static gboolean asb_plugin_hardcoded_add_screenshots (AsbApp *app, const gchar *location, GError **error) { const gchar *tmp; gboolean ret = TRUE; GList *l; GList *list = NULL; _cleanup_dir_close_ GDir *dir = NULL; /* scan for files */ dir = g_dir_open (location, 0, error); if (dir == NULL) { ret = FALSE; goto out; } while ((tmp = g_dir_read_name (dir)) != NULL) { if (!g_str_has_suffix (tmp, ".png")) continue; list = g_list_prepend (list, g_build_filename (location, tmp, NULL)); } list = g_list_sort (list, asb_plugin_hardcoded_sort_screenshots_cb); for (l = list; l != NULL; l = l->next) { tmp = l->data; asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_DEBUG, "Adding extra screenshot: %s", tmp); ret = asb_app_add_screenshot_source (app, tmp, error); if (!ret) goto out; } as_app_add_metadata (AS_APP (app), "DistroScreenshots", NULL, -1); out: g_list_free_full (list, g_free); return ret; }
/** * asb_plugin_process_app: */ gboolean asb_plugin_process_app (AsbPlugin *plugin, AsbPackage *pkg, AsbApp *app, const gchar *tmpdir, GError **error) { gchar **filelist; guint i; /* already set */ if (as_app_has_kudo_kind (AS_APP (app), AS_KUDO_KIND_MODERN_TOOLKIT)) return TRUE; /* look for any GIR files */ filelist = asb_package_get_filelist (pkg); for (i = 0; filelist[i] != NULL; i++) { if (!_asb_plugin_check_filename (filelist[i])) continue; if (!asb_plugin_process_gir (app, tmpdir, filelist[i], error)) return FALSE; } return TRUE; }
/** * cra_plugin_process_filename: */ static gboolean cra_plugin_process_filename (CraPlugin *plugin, CraPackage *pkg, const gchar *filename, GList **apps, const gchar *tmpdir, GError **error) { const gchar *key; gboolean ret; _cleanup_free_ gchar *app_id = NULL; _cleanup_free_ gchar *full_filename = NULL; _cleanup_free_ gchar *icon_filename = NULL; _cleanup_object_unref_ CraApp *app = NULL; _cleanup_object_unref_ GdkPixbuf *pixbuf = NULL; /* create app */ app_id = g_path_get_basename (filename); app = cra_app_new (pkg, app_id); full_filename = g_build_filename (tmpdir, filename, NULL); ret = as_app_parse_file (AS_APP (app), full_filename, AS_APP_PARSE_FLAG_USE_HEURISTICS, error); if (!ret) return FALSE; /* NoDisplay requires AppData */ if (as_app_get_metadata_item (AS_APP (app), "NoDisplay") != NULL) cra_app_add_requires_appdata (app, "NoDisplay=true"); /* Settings or DesktopSettings requires AppData */ if (as_app_has_category (AS_APP (app), "Settings")) cra_app_add_requires_appdata (app, "Category=Settings"); if (as_app_has_category (AS_APP (app), "DesktopSettings")) cra_app_add_requires_appdata (app, "Category=DesktopSettings"); /* is the icon a stock-icon-name? */ key = as_app_get_icon (AS_APP (app)); if (key != NULL) { if (as_app_get_icon_kind (AS_APP (app)) == AS_ICON_KIND_STOCK) { cra_package_log (pkg, CRA_PACKAGE_LOG_LEVEL_DEBUG, "using stock icon %s", key); } else { /* is icon XPM or GIF */ if (g_str_has_suffix (key, ".xpm")) cra_app_add_veto (app, "Uses XPM icon: %s", key); else if (g_str_has_suffix (key, ".gif")) cra_app_add_veto (app, "Uses GIF icon: %s", key); else if (g_str_has_suffix (key, ".ico")) cra_app_add_veto (app, "Uses ICO icon: %s", key); /* find icon */ pixbuf = cra_app_find_icon (tmpdir, key, error); if (pixbuf == NULL) return FALSE; /* save in target directory */ icon_filename = g_strdup_printf ("%s.png", as_app_get_id (AS_APP (app))); as_app_set_icon (AS_APP (app), icon_filename, -1); as_app_set_icon_kind (AS_APP (app), AS_ICON_KIND_CACHED); cra_app_set_pixbuf (app, pixbuf); } } /* add */ cra_plugin_add_app (apps, app); return TRUE; }
/** * cra_plugin_process_app: */ gboolean cra_plugin_process_app (CraPlugin *plugin, CraPackage *pkg, CraApp *app, const gchar *tmpdir, GError **error) { const gchar *tmp; AsRelease *release; gchar **deps; gchar **filelist; GPtrArray *releases; guint i; guint secs; guint days; /* add extra categories */ tmp = as_app_get_id (AS_APP (app)); if (g_strcmp0 (tmp, "0install") == 0) as_app_add_category (AS_APP (app), "System", -1); if (g_strcmp0 (tmp, "alacarte") == 0) as_app_add_category (AS_APP (app), "System", -1); if (g_strcmp0 (tmp, "deja-dup") == 0) as_app_add_category (AS_APP (app), "Utility", -1); if (g_strcmp0 (tmp, "gddccontrol") == 0) as_app_add_category (AS_APP (app), "System", -1); if (g_strcmp0 (tmp, "nautilus") == 0) as_app_add_category (AS_APP (app), "System", -1); if (g_strcmp0 (tmp, "pessulus") == 0) as_app_add_category (AS_APP (app), "System", -1); if (g_strcmp0 (tmp, "pmdefaults") == 0) as_app_add_category (AS_APP (app), "System", -1); if (g_strcmp0 (tmp, "fwfstab") == 0) as_app_add_category (AS_APP (app), "System", -1); /* add extra project groups */ if (g_strcmp0 (tmp, "nemo") == 0) as_app_set_project_group (AS_APP (app), "Cinnamon", -1); if (g_strcmp0 (tmp, "xfdashboard") == 0) as_app_set_project_group (AS_APP (app), "XFCE", -1); /* use the URL to guess the project group */ tmp = cra_package_get_url (pkg); if (as_app_get_project_group (AS_APP (app)) == NULL && tmp != NULL) { tmp = cra_glob_value_search (plugin->priv->project_groups, tmp); if (tmp != NULL) as_app_set_project_group (AS_APP (app), tmp, -1); } /* use summary to guess the project group */ tmp = as_app_get_comment (AS_APP (app), NULL); if (tmp != NULL && g_strstr_len (tmp, -1, "for KDE") != NULL) as_app_set_project_group (AS_APP (app), "KDE", -1); /* look for any installed docs */ filelist = cra_package_get_filelist (pkg); for (i = 0; filelist[i] != NULL; i++) { if (g_str_has_prefix (filelist[i], "/usr/share/help/")) { as_app_add_metadata (AS_APP (app), "X-Kudo-InstallsUserDocs", "", -1); break; } } /* look for a shell search provider */ for (i = 0; filelist[i] != NULL; i++) { if (g_str_has_prefix (filelist[i], "/usr/share/gnome-shell/search-providers/")) { as_app_add_metadata (AS_APP (app), "X-Kudo-SearchProvider", "", -1); break; } } /* look for a modern toolkit */ deps = cra_package_get_deps (pkg); for (i = 0; deps != NULL && deps[i] != NULL; i++) { if (g_strcmp0 (deps[i], "libgtk-3.so.0") == 0) { as_app_add_metadata (AS_APP (app), "X-Kudo-GTK3", "", -1); break; } if (g_strcmp0 (deps[i], "libQt5Core.so.5") == 0) { as_app_add_metadata (AS_APP (app), "X-Kudo-QT5", "", -1); break; } } /* look for ancient toolkits */ for (i = 0; deps != NULL && deps[i] != NULL; i++) { if (g_strcmp0 (deps[i], "libgtk-1.2.so.0") == 0) { cra_app_add_veto (app, "Uses obsolete GTK1 toolkit"); break; } if (g_strcmp0 (deps[i], "libqt-mt.so.3") == 0) { cra_app_add_veto (app, "Uses obsolete QT3 toolkit"); break; } if (g_strcmp0 (deps[i], "liblcms.so.1") == 0) { cra_app_add_veto (app, "Uses obsolete LCMS library"); break; } if (g_strcmp0 (deps[i], "libelektra.so.4") == 0) { cra_app_add_veto (app, "Uses obsolete Elektra library"); break; } if (g_strcmp0 (deps[i], "libXt.so.6") == 0) { cra_app_add_requires_appdata (app, "Uses obsolete X11 toolkit"); break; } if (g_strcmp0 (deps[i], "wine-core") == 0) { cra_app_add_requires_appdata (app, "Uses wine"); break; } } /* has the application been updated in the last year */ releases = as_app_get_releases (AS_APP (app)); for (i = 0; i < releases->len; i++) { release = g_ptr_array_index (releases, i); secs = (g_get_real_time () / G_USEC_PER_SEC) - as_release_get_timestamp (release); days = secs / (60 * 60 * 24); if (days < 365) { as_app_add_metadata (AS_APP (app), "X-Kudo-RecentRelease", "", -1); break; } } /* has there been no upstream version recently */ if (releases->len > 0 && as_app_get_id_kind (AS_APP (app)) == AS_ID_KIND_DESKTOP) { release = g_ptr_array_index (releases, 0); secs = (g_get_real_time () / G_USEC_PER_SEC) - as_release_get_timestamp (release); days = secs / (60 * 60 * 24); /* this is just too old for us to care about */ if (days > 365 * 10) { cra_app_add_veto (app, "Dead upstream for %i years", secs / (60 * 60 * 24 * 365)); } /* we need AppData if the app needs saving */ else if (days > 365 * 5) { cra_app_add_requires_appdata (app, "Dead upstream for > %i years", 5); } } /* do any extra screenshots exist */ tmp = cra_package_get_config (pkg, "ScreenshotsExtra"); if (tmp != NULL) { _cleanup_free_ gchar *dirname = NULL; dirname = g_build_filename (tmp, as_app_get_id (AS_APP (app)), NULL); if (g_file_test (dirname, G_FILE_TEST_EXISTS)) { if (!cra_plugin_hardcoded_add_screenshots (app, dirname, error)) return FALSE; } } /* a ConsoleOnly category means we require AppData */ if (as_app_has_category (AS_APP(app), "ConsoleOnly")) cra_app_add_requires_appdata (app, "ConsoleOnly"); /* no categories means we require AppData */ if (as_app_get_categories(AS_APP(app))->len == 0) cra_app_add_requires_appdata (app, "no Categories"); return TRUE; }
/** * asb_task_process: * @task: A #AsbTask * @error_not_used: A #GError or %NULL * * Processes the task. * * Returns: %TRUE for success, %FALSE otherwise * * Since: 0.1.0 **/ gboolean asb_task_process (AsbTask *task, GError **error_not_used) { AsRelease *release; AsbApp *app; AsbPlugin *plugin = NULL; AsbTaskPrivate *priv = GET_PRIVATE (task); GList *apps = NULL; GList *l; GPtrArray *array; gboolean ret; gchar *cache_id; guint i; guint nr_added = 0; g_autoptr(GError) error = NULL; g_autofree gchar *basename = NULL; /* reset the profile timer */ asb_package_log_start (priv->pkg); /* ensure nevra read */ if (!asb_package_ensure (priv->pkg, ASB_PACKAGE_ENSURE_NEVRA, error_not_used)) return FALSE; g_debug ("starting: %s", asb_package_get_name (priv->pkg)); /* treat archive as a special case */ if (g_str_has_suffix (priv->filename, ".cab")) { AsApp *app_tmp; GPtrArray *apps_tmp; g_autoptr(AsStore) store = as_store_new (); g_autoptr(GFile) file = g_file_new_for_path (priv->filename); if (!as_store_from_file (store, file, NULL, NULL, &error)) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to parse %s: %s", asb_package_get_filename (priv->pkg), error->message); return TRUE; } apps_tmp = as_store_get_apps (store); for (i = 0; i < apps_tmp->len; i++) { g_autoptr(AsbApp) app2 = NULL; app_tmp = AS_APP (g_ptr_array_index (apps_tmp, i)); app2 = asb_app_new (priv->pkg, as_app_get_id (app_tmp)); as_app_subsume (AS_APP (app2), app_tmp); asb_context_add_app (priv->ctx, app2); /* set cache-id in case we want to use the metadata directly */ if (asb_context_get_flag (priv->ctx, ASB_CONTEXT_FLAG_ADD_CACHE_ID)) { cache_id = asb_utils_get_cache_id_for_filename (priv->filename); as_app_add_metadata (AS_APP (app2), "X-CacheID", cache_id); g_free (cache_id); } nr_added++; } g_debug ("added %i apps from archive", apps_tmp->len); goto skip; } /* ensure file list read */ if (!asb_package_ensure (priv->pkg, ASB_PACKAGE_ENSURE_FILES, error_not_used)) return FALSE; /* did we get a file match on any plugin */ basename = g_path_get_basename (priv->filename); asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "Getting filename match for %s", basename); asb_task_add_suitable_plugins (task); if (priv->plugins_to_run->len == 0) { asb_context_add_app_ignore (priv->ctx, priv->pkg); goto out; } /* delete old tree if it exists */ ret = asb_utils_ensure_exists_and_empty (priv->tmpdir, &error); if (!ret) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to clear: %s", error->message); goto out; } /* explode tree */ g_debug ("decompressing files: %s", asb_package_get_name (priv->pkg)); asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "Exploding tree for %s", asb_package_get_name (priv->pkg)); ret = asb_package_explode (priv->pkg, priv->tmpdir, asb_context_get_file_globs (priv->ctx), &error); if (!ret) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to explode: %s", error->message); g_clear_error (&error); goto skip; } /* add extra packages */ if (!asb_package_ensure (priv->pkg, ASB_PACKAGE_ENSURE_DEPS | ASB_PACKAGE_ENSURE_SOURCE, error_not_used)) return FALSE; ret = asb_task_explode_extra_packages (task, &error); if (!ret) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to explode extra file: %s", error->message); goto skip; } /* run plugins */ g_debug ("examining: %s", asb_package_get_name (priv->pkg)); for (i = 0; i < priv->plugins_to_run->len; i++) { GList *apps_tmp = NULL; plugin = g_ptr_array_index (priv->plugins_to_run, i); asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "Processing %s with %s", basename, plugin->name); apps_tmp = asb_plugin_process (plugin, priv->pkg, priv->tmpdir, &error); if (apps_tmp == NULL) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to run process '%s': %s", plugin->name, error->message); g_clear_error (&error); } for (l = apps_tmp; l != NULL; l = l->next) { app = ASB_APP (l->data); asb_plugin_add_app (&apps, AS_APP (app)); } g_list_free_full (apps_tmp, g_object_unref); } if (apps == NULL) goto skip; /* print */ g_debug ("processing: %s", asb_package_get_name (priv->pkg)); for (l = apps; l != NULL; l = l->next) { app = l->data; /* never set */ if (as_app_get_id (AS_APP (app)) == NULL) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_INFO, "app id not set for %s", asb_package_get_name (priv->pkg)); continue; } /* copy data from pkg into app */ if (!asb_package_ensure (priv->pkg, ASB_PACKAGE_ENSURE_LICENSE | ASB_PACKAGE_ENSURE_RELEASES | ASB_PACKAGE_ENSURE_VCS | ASB_PACKAGE_ENSURE_URL, error_not_used)) return FALSE; if (asb_package_get_url (priv->pkg) != NULL && as_app_get_url_item (AS_APP (app), AS_URL_KIND_HOMEPAGE) == NULL) { as_app_add_url (AS_APP (app), AS_URL_KIND_HOMEPAGE, asb_package_get_url (priv->pkg)); } if (asb_package_get_license (priv->pkg) != NULL && as_app_get_project_license (AS_APP (app)) == NULL) { as_app_set_project_license (AS_APP (app), asb_package_get_license (priv->pkg)); } /* add the source name so we can suggest these together */ if (g_strcmp0 (asb_package_get_source_pkgname (priv->pkg), asb_package_get_name (priv->pkg)) != 0) { as_app_set_source_pkgname (AS_APP (app), asb_package_get_source_pkgname (priv->pkg)); } /* set all the releases on the app */ array = asb_package_get_releases (priv->pkg); for (i = 0; i < array->len; i++) { release = g_ptr_array_index (array, i); as_app_add_release (AS_APP (app), release); } /* run each refine plugin on each app */ ret = asb_plugin_loader_process_app (asb_context_get_plugin_loader (priv->ctx), priv->pkg, app, priv->tmpdir, &error); if (!ret) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to run process on %s: %s", as_app_get_id (AS_APP (app)), error->message); g_clear_error (&error); goto skip; } /* set cache-id in case we want to use the metadata directly */ if (asb_context_get_flag (priv->ctx, ASB_CONTEXT_FLAG_ADD_CACHE_ID)) { cache_id = asb_utils_get_cache_id_for_filename (priv->filename); as_app_add_metadata (AS_APP (app), "X-CacheID", cache_id); g_free (cache_id); } /* set the VCS information into the metadata */ if (asb_package_get_vcs (priv->pkg) != NULL) { as_app_add_metadata (AS_APP (app), "VersionControlSystem", asb_package_get_vcs (priv->pkg)); } /* save any screenshots early */ if (array->len == 0) { if (!asb_app_save_resources (ASB_APP (app), ASB_APP_SAVE_FLAG_SCREENSHOTS, error_not_used)) return FALSE; } /* all okay */ asb_context_add_app (priv->ctx, app); nr_added++; } skip: /* add a dummy element to the AppStream metadata so that we don't keep * parsing this every time */ if (asb_context_get_flag (priv->ctx, ASB_CONTEXT_FLAG_ADD_CACHE_ID) && nr_added == 0) asb_context_add_app_ignore (priv->ctx, priv->pkg); /* delete tree */ g_debug ("deleting temp files: %s", asb_package_get_name (priv->pkg)); if (!asb_utils_rmtree (priv->tmpdir, &error)) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to delete tree: %s", error->message); goto out; } /* write log */ g_debug ("writing log: %s", asb_package_get_name (priv->pkg)); if (!asb_package_log_flush (priv->pkg, &error)) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to write package log: %s", error->message); goto out; } out: /* clear loaded resources */ asb_package_close (priv->pkg, NULL); asb_package_clear (priv->pkg, ASB_PACKAGE_ENSURE_DEPS | ASB_PACKAGE_ENSURE_FILES); g_list_free_full (apps, (GDestroyNotify) g_object_unref); return TRUE; }
/** * asb_plugin_loader_merge: * @plugin_loader: A #AsbPluginLoader * @apps: (element-type AsbApp): a list of applications that need merging * * Merge the list of applications using the plugins. * * Since: 0.2.5 **/ void asb_plugin_loader_merge (AsbPluginLoader *plugin_loader, GList *apps) { AsbApp *app; AsbApp *found; AsbPluginLoaderPrivate *priv = GET_PRIVATE (plugin_loader); AsbPluginMergeFunc plugin_func = NULL; AsbPlugin *plugin; GList *l; const gchar *key; const gchar *tmp; gboolean ret; guint i; g_autoptr(GHashTable) hash = NULL; /* run each plugin */ for (i = 0; i < priv->plugins->len; i++) { plugin = g_ptr_array_index (priv->plugins, i); ret = g_module_symbol (plugin->module, "asb_plugin_merge", (gpointer *) &plugin_func); if (!ret) continue; plugin_func (plugin, apps); } /* FIXME: move to font plugin */ for (l = apps; l != NULL; l = l->next) { if (!ASB_IS_APP (l->data)) continue; app = ASB_APP (l->data); as_app_remove_metadata (AS_APP (app), "FontFamily"); as_app_remove_metadata (AS_APP (app), "FontFullName"); as_app_remove_metadata (AS_APP (app), "FontIconText"); as_app_remove_metadata (AS_APP (app), "FontParent"); as_app_remove_metadata (AS_APP (app), "FontSampleText"); as_app_remove_metadata (AS_APP (app), "FontSubFamily"); as_app_remove_metadata (AS_APP (app), "FontClassifier"); } /* deduplicate */ hash = g_hash_table_new (g_str_hash, g_str_equal); for (l = apps; l != NULL; l = l->next) { if (!ASB_IS_APP (l->data)) continue; app = ASB_APP (l->data); if (as_app_get_vetos(AS_APP(app))->len > 0) continue; key = as_app_get_id (AS_APP (app)); found = g_hash_table_lookup (hash, key); if (found == NULL) { g_hash_table_insert (hash, (gpointer) key, (gpointer) app); continue; } if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_FIRMWARE) { as_app_subsume_full (AS_APP (found), AS_APP (app), AS_APP_SUBSUME_FLAG_MERGE); } tmp = asb_package_get_nevr (asb_app_get_package (found)); as_app_add_veto (AS_APP (app), "duplicate of %s", tmp); asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_WARNING, "duplicate %s not included as added from %s", key, tmp); } }
/** * asb_plugin_process: */ GList * asb_plugin_process (AsbPlugin *plugin, AsbPackage *pkg, const gchar *tmpdir, GError **error) { const gchar *tmp; gchar **split; GList *apps = NULL; GPtrArray *keywords; guint i; guint j; _cleanup_free_ gchar *app_id = NULL; _cleanup_object_unref_ AsbApp *app = NULL; _cleanup_object_unref_ AsIcon *icon = NULL; _cleanup_string_free_ GString *str = NULL; /* use the pkgname suffix as the app-id */ tmp = asb_package_get_name (pkg); if (g_str_has_prefix (tmp, "gstreamer1-")) tmp += 11; if (g_str_has_prefix (tmp, "gstreamer-")) tmp += 10; if (g_str_has_prefix (tmp, "plugins-")) tmp += 8; app_id = g_strdup_printf ("gstreamer-%s", tmp); /* create app */ app = asb_app_new (pkg, app_id); as_app_set_id_kind (AS_APP (app), AS_ID_KIND_CODEC); as_app_set_name (AS_APP (app), "C", "GStreamer Multimedia Codecs", -1); asb_app_set_requires_appdata (app, TRUE); asb_app_set_hidpi_enabled (app, asb_context_get_hidpi_enabled (plugin->ctx)); as_app_add_category (AS_APP (app), "Addons", -1); as_app_add_category (AS_APP (app), "Codecs", -1); /* add icon */ icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, "application-x-executable", -1); as_app_add_icon (AS_APP (app), icon); for (i = 0; data[i].path != NULL; i++) { if (!asb_utils_is_file_in_tmpdir (tmpdir, data[i].path)) continue; split = g_strsplit (data[i].text, "|", -1); for (j = 0; split[j] != NULL; j++) as_app_add_keyword (AS_APP (app), NULL, split[j], -1); g_strfreev (split); } /* no codecs we care about */ keywords = as_app_get_keywords (AS_APP (app), NULL); if (keywords == NULL) { g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "nothing interesting in %s", asb_package_get_basename (pkg)); return NULL; } /* sort categories by name */ g_ptr_array_sort (keywords, asb_utils_string_sort_cb); /* create a description */ str = g_string_new ("Multimedia playback for "); if (keywords->len > 1) { for (i = 0; i < keywords->len - 1; i++) { tmp = g_ptr_array_index (keywords, i); g_string_append_printf (str, "%s, ", tmp); } g_string_truncate (str, str->len - 2); tmp = g_ptr_array_index (keywords, keywords->len - 1); g_string_append_printf (str, " and %s", tmp); } else { g_string_append (str, g_ptr_array_index (keywords, 0)); } as_app_set_comment (AS_APP (app), "C", str->str, -1); /* add */ asb_plugin_add_app (&apps, AS_APP (app)); return apps; }
/** * asb_plugin_process_filename: */ static gboolean asb_plugin_process_filename (AsbPlugin *plugin, AsbPackage *pkg, const gchar *filename, GList **apps, const gchar *tmpdir, GError **error) { gboolean ret = TRUE; gchar *error_msg = 0; gchar *filename_tmp; gint rc; guint i; sqlite3 *db = NULL; _cleanup_free_ gchar *basename = NULL; _cleanup_free_ gchar *description = NULL; _cleanup_free_ gchar *language_string = NULL; _cleanup_free_ gchar *name = NULL; _cleanup_free_ gchar *symbol = NULL; _cleanup_object_unref_ AsbApp *app = NULL; _cleanup_object_unref_ AsIcon *icon = NULL; _cleanup_strv_free_ gchar **languages = NULL; /* open IME database */ filename_tmp = g_build_filename (tmpdir, filename, NULL); rc = sqlite3_open (filename_tmp, &db); if (rc) { ret = FALSE; g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "Can't open database: %s", sqlite3_errmsg (db)); goto out; } /* get name */ rc = sqlite3_exec(db, "SELECT * FROM ime WHERE attr = 'name' LIMIT 1;", asb_plugin_sqlite_callback_cb, &name, &error_msg); if (rc != SQLITE_OK) { ret = FALSE; g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "Can't get IME name from %s: %s", filename, error_msg); sqlite3_free(error_msg); goto out; } /* get symbol */ rc = sqlite3_exec(db, "SELECT * FROM ime WHERE attr = 'symbol' LIMIT 1;", asb_plugin_sqlite_callback_cb, &symbol, &error_msg); if (rc != SQLITE_OK) { ret = FALSE; g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "Can't get IME symbol from %s: %s", filename, error_msg); sqlite3_free(error_msg); goto out; } /* get languages */ rc = sqlite3_exec(db, "SELECT * FROM ime WHERE attr = 'languages' LIMIT 1;", asb_plugin_sqlite_callback_cb, &language_string, &error_msg); if (rc != SQLITE_OK) { ret = FALSE; g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "Can't get IME languages from %s: %s", filename, error_msg); sqlite3_free(error_msg); goto out; } /* get description */ rc = sqlite3_exec(db, "SELECT * FROM ime WHERE attr = 'description' LIMIT 1;", asb_plugin_sqlite_callback_cb, &description, &error_msg); if (rc != SQLITE_OK) { ret = FALSE; g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "Can't get IME name from %s: %s", filename, error_msg); sqlite3_free(error_msg); goto out; } /* this is _required_ */ if (name == NULL || description == NULL) { ret = FALSE; g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "No 'name' and 'description' in %s", filename); goto out; } /* create new app */ basename = g_path_get_basename (filename); app = asb_app_new (pkg, basename); as_app_set_id_kind (AS_APP (app), AS_ID_KIND_INPUT_METHOD); as_app_add_category (AS_APP (app), "Addons"); as_app_add_category (AS_APP (app), "InputSources"); as_app_set_name (AS_APP (app), "C", name); as_app_set_comment (AS_APP (app), "C", description); if (symbol != NULL && symbol[0] != '\0') as_app_add_metadata (AS_APP (app), "X-IBus-Symbol", symbol); if (language_string != NULL) { languages = g_strsplit (language_string, ",", -1); for (i = 0; languages[i] != NULL; i++) { if (g_strcmp0 (languages[i], "other") == 0) continue; as_app_add_language (AS_APP (app), 100, languages[i]); } } asb_app_set_requires_appdata (app, TRUE); asb_app_set_hidpi_enabled (app, asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_HIDPI_ICONS)); /* add icon */ icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, "system-run-symbolic"); as_app_add_icon (AS_APP (app), icon); asb_plugin_add_app (apps, AS_APP (app)); out: if (db != NULL) sqlite3_close (db); return ret; }