/* * Copyright 2015 Javier S. Pedro * * 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 . */ #include #include #include #include #include #include #include "app-id.h" AppId * app_id_new() { return g_slice_new0(AppId); } AppId * app_id_create(const gchar *host, gint uid, const gchar *executable, const gchar *wm_class_class, const gchar *wm_class_name) { AppId *appid = g_slice_new(AppId); appid->host = g_strdup(host); appid->uid = uid; appid->executable = g_strdup(executable); appid->wm_class_class = g_strdup(wm_class_class); appid->wm_class_name = g_strdup(wm_class_name); } void app_id_destroy(AppId *appid) { g_free(appid->host); g_free(appid->executable); g_free(appid->wm_class_class); g_free(appid->wm_class_name); g_slice_free(AppId, appid); } static inline guint str_hash0(const gchar *s) { return s ? g_str_hash(s) : 0; } guint app_id_hash(gconstpointer appid_pointer) { const AppId *appid = appid_pointer; return str_hash0(appid->host) + appid->uid + str_hash0(appid->executable) + str_hash0(appid->wm_class_class) + str_hash0(appid->wm_class_name); } gboolean app_id_equal(gconstpointer ap, gconstpointer bp) { const AppId *a = ap, *b = bp; return g_strcmp0(a->host, b->host) == 0 && a->uid == b->uid && g_strcmp0(a->executable, b->executable) == 0 && g_strcmp0(a->wm_class_class, b->wm_class_class) == 0 && g_strcmp0(a->wm_class_name, b->wm_class_name) == 0; } static gchar *text_property_to_string(Display *dpy, XTextProperty *prop) { gchar *str = NULL; char **list; int count = 0; if (Xutf8TextPropertyToTextList(dpy, prop, &list, &count) == Success) { if (count > 0) { str = g_strdup(list[0]); } XFreeStringList(list); } return str; } static gchar *text_property_to_lower_string(Display *dpy, XTextProperty *prop) { gchar *str = NULL; char **list; int count = 0; if (Xutf8TextPropertyToTextList(dpy, prop, &list, &count) == Success) { if (count > 0) { str = g_utf8_strdown(list[0], -1); } XFreeStringList(list); } return str; } static gboolean is_local_host(const gchar *host) { if (strcmp(host, "localhost") == 0) { return TRUE; } else if (strcmp(host, g_get_host_name()) == 0) { return TRUE; } else { return FALSE; } } AppId * app_id_from_window(WnckWindow *window) { AppId *appid = g_slice_new0(AppId); Display *dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default()); Window w = wnck_window_get_xid(window); XTextProperty textprop; if (XGetWMClientMachine(dpy, w, &textprop)) { appid->host = text_property_to_lower_string(dpy, &textprop); XFree(textprop.value); } pid_t pid = wnck_window_get_pid(window); if (pid) { glibtop_proc_uid proc_uid; glibtop_get_proc_uid(&proc_uid, pid); if (proc_uid.flags & (1L << GLIBTOP_PROC_UID_UID)) { appid->uid = proc_uid.uid; } if (!appid->host || is_local_host(appid->host)) { glibtop_proc_wd proc_wd; gchar **dirs = glibtop_get_proc_wd(&proc_wd, pid); if (proc_wd.flags & (1 << GLIBTOP_PROC_WD_EXE)) { appid->executable = g_strdup(proc_wd.exe); } g_strfreev(dirs); } } else { appid->uid = getuid(); appid->executable = NULL; } XClassHint classhint; if (XGetClassHint(dpy, w, &classhint)) { if (classhint.res_class) { appid->wm_class_class = g_ascii_strdown(classhint.res_class, -1); XFree(classhint.res_class); } if (classhint.res_name) { appid->wm_class_name = g_ascii_strdown(classhint.res_name, -1); XFree(classhint.res_name); } } return appid; } gboolean app_id_is_local_user(AppId *appid) { if (appid->host && !is_local_host(appid->host)) { return FALSE; } return appid->uid == getuid(); }