diff options
author | Javier <dev.git@javispedro.com> | 2015-01-19 00:07:22 +0100 |
---|---|---|
committer | Javier <dev.git@javispedro.com> | 2015-01-19 00:07:22 +0100 |
commit | cd89c60570d17cad28928f3495eded7af2b45431 (patch) | |
tree | a7d13d4f0d63e852062964fcf79ca9d5ad70ae15 /libmdock/matcher.c | |
parent | a215500011290121925cfe929d71b80696732230 (diff) | |
download | mdock-cd89c60570d17cad28928f3495eded7af2b45431.tar.gz mdock-cd89c60570d17cad28928f3495eded7af2b45431.zip |
initially app-id support
Diffstat (limited to 'libmdock/matcher.c')
-rw-r--r-- | libmdock/matcher.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/libmdock/matcher.c b/libmdock/matcher.c new file mode 100644 index 0000000..25e2b2f --- /dev/null +++ b/libmdock/matcher.c @@ -0,0 +1,238 @@ +/* + * Copyright 2015 Javier S. Pedro <dev.git@javispedro.com> + * + * This file is part of MDock. + * + * MDock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MDock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MDock. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <ftw.h> +#include <string.h> +#include <glib/gstdio.h> +#include <gio/gio.h> +#include <gio/gdesktopappinfo.h> +#include "matcher.h" + +static gboolean init_done = FALSE; +static GAppInfoMonitor *appinfo_monitor; +static guint refresh_timeout; +static GHashTable *info_by_exec; +static GHashTable *info_by_wmclass; + +typedef struct _DesktopItem +{ + gint priority; + gchar *desktop_file; +} DesktopItem; + +typedef struct _DesktopItemList +{ + GSList *list; +} DesktopItemList; + +static DesktopItem * desktop_item_create() +{ + return g_slice_new(DesktopItem); +} + +static void desktop_item_destroy(DesktopItem *item) +{ + g_free(item->desktop_file); + g_slice_free(DesktopItem, item); +} + +static gint desktop_item_compare(gconstpointer ap, gconstpointer bp) +{ + const DesktopItem *a = ap, *b = bp; + return b->priority - a->priority; +} + +static void desktop_item_list_destroy(DesktopItemList *l) +{ + g_slist_free_full(l->list, (GDestroyNotify)desktop_item_destroy); +} + +static gint compute_priority(GDesktopAppInfo *info, gint base_priority) +{ + gint prio = base_priority; + + if (g_app_info_should_show(G_APP_INFO(info))) { + prio += 32000; + } + + const gchar *cmdline = g_app_info_get_commandline(G_APP_INFO(info)); + prio -= strlen(cmdline); + + return prio; +} + +static void add_desktop_item_by_exec(const gchar *exec, GDesktopAppInfo *info, gint base_priority) +{ + DesktopItem *item = desktop_item_create(); + item->priority = compute_priority(info, base_priority); + item->desktop_file = g_strdup(g_app_info_get_id(G_APP_INFO(info))); + + DesktopItemList *elist = g_hash_table_lookup(info_by_exec, exec); + if (!elist) { + elist = g_slice_new0(DesktopItemList); + g_hash_table_insert(info_by_exec, g_strdup(exec), elist); + } + + elist->list = g_slist_append(elist->list, item); +} + +static void add_desktop_item_by_wmclass(const gchar *wmclass, GDesktopAppInfo *info, gint base_priority) +{ + DesktopItem *item = desktop_item_create(); + item->priority = compute_priority(info, base_priority); + item->desktop_file = g_strdup(g_app_info_get_id(G_APP_INFO(info))); + + DesktopItemList *elist = g_hash_table_lookup(info_by_wmclass, wmclass); + if (!elist) { + elist = g_slice_new0(DesktopItemList); + g_hash_table_insert(info_by_wmclass, g_strdup(wmclass), elist); + } + + elist->list = g_slist_append(elist->list, item); +} + +static void add_desktop_info(GDesktopAppInfo *info) +{ + const char *quoted_executable = g_app_info_get_executable(G_APP_INFO(info)); + gchar *executable = NULL; + if (quoted_executable) { + executable = g_shell_unquote(quoted_executable, NULL); + } + + if (executable && executable[0]) { + if (g_path_is_absolute(executable)) { + add_desktop_item_by_exec(executable, info, 4000); + } else { + gchar *execpath = g_find_program_in_path(executable); + if (execpath) { + add_desktop_item_by_exec(execpath, info, 0); + } else { + g_warning("Could not find executable in path: '%s'", executable); + } + g_free(execpath); + } + } + + const gchar *wmclass = g_desktop_app_info_get_startup_wm_class(info); + if (wmclass && wmclass[0]) { + add_desktop_item_by_wmclass(wmclass, info, 128000); + } + + if (executable && executable[0]) { + gchar *basename = g_path_get_basename(executable); + add_desktop_item_by_wmclass(basename, info, -32000); + g_free(basename); + } + + g_free(executable); +} + +static void refresh_appinfo() +{ + g_debug("Refreshing application info..."); + + g_hash_table_remove_all(info_by_exec); + g_hash_table_remove_all(info_by_wmclass); + + GList *list = g_app_info_get_all(); + for (GList *l = g_list_first(list); l; l = g_list_next(l)) { + add_desktop_info(G_DESKTOP_APP_INFO(l->data)); + } + + g_list_free_full(list, g_object_unref); +} + +static gboolean appinfo_timeout(gpointer user_data) +{ + refresh_appinfo(); + refresh_timeout = 0; + return G_SOURCE_REMOVE; +} + +static void appinfo_changed(GAppInfoMonitor *monitor, gpointer user_data) +{ + g_debug("Appinfo changed"); + if (refresh_timeout == 0) { + refresh_timeout = g_timeout_add_seconds(10, appinfo_timeout, 0); + } +} + +static gboolean init_matcher(void) +{ + if (!init_done) { + refresh_timeout = 0; + appinfo_monitor = g_app_info_monitor_get(); + g_signal_connect(appinfo_monitor, "changed", + G_CALLBACK(appinfo_changed), 0); + + info_by_exec = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, (GDestroyNotify)desktop_item_list_destroy); + info_by_wmclass = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, (GDestroyNotify)desktop_item_list_destroy); + + refresh_appinfo(); + } + + return TRUE; +} + +static GSList * matches_by_executable(const gchar *exec) +{ + DesktopItemList *elist = g_hash_table_lookup(info_by_exec, exec); + + if (elist) { + return g_slist_copy(elist->list); + } else { + return NULL; + } +} + +static GSList * matches_by_wmclass(const gchar *wmclass) +{ + DesktopItemList *elist = g_hash_table_lookup(info_by_wmclass, wmclass); + + if (elist) { + return g_slist_copy(elist->list); + } else { + return NULL; + } +} + +const gchar * match_application_to_desktop_file(AppId *appid) +{ + if (!init_matcher()) return NULL; + + GSList *list = NULL; + + if (appid->executable) { + list = g_slist_concat(list, matches_by_executable(appid->executable)); + } + if (appid->wm_class_name) { + list = g_slist_concat(list, matches_by_wmclass(appid->wm_class_name)); + } + + if (list) { + list = g_slist_sort(list, desktop_item_compare); + DesktopItem *best = list->data; + g_slist_free(list); + return best->desktop_file; + } else { + return NULL; + } +} |