diff options
Diffstat (limited to 'modules/devices')
-rw-r--r-- | modules/devices/dmi_memory.c | 2 | ||||
-rw-r--r-- | modules/devices/monitors.c | 282 |
2 files changed, 283 insertions, 1 deletions
diff --git a/modules/devices/dmi_memory.c b/modules/devices/dmi_memory.c index 753c4c74..f266193c 100644 --- a/modules/devices/dmi_memory.c +++ b/modules/devices/dmi_memory.c @@ -618,7 +618,7 @@ gchar *make_spd_section(spd_data *spd) { return ret; } -gchar *tag_make_safe_inplace(gchar *tag) { +static gchar *tag_make_safe_inplace(gchar *tag) { if (!tag) return tag; if (!g_utf8_validate(tag, -1, NULL)) diff --git a/modules/devices/monitors.c b/modules/devices/monitors.c new file mode 100644 index 00000000..4e8ba915 --- /dev/null +++ b/modules/devices/monitors.c @@ -0,0 +1,282 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2019 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2019 Burt P. <pburt0@gmail.com> + * + * This program 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, version 2. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "devices.h" +#include "util_sysobj.h" +#include "util_edid.h" +#include "util_ids.h" + +static const char monitor_icon[] = "monitor.png"; + +#define UNKIFNULL2(f) ((f) ? f : _("(Unknown)")) +#define UNKIFEMPTY2(f) ((*f) ? f : _("(Unknown)")) + +gboolean no_monitors = FALSE; + +gchar *edid_ids_file = NULL; + +void find_edid_ids_file() { + if (edid_ids_file) return; + char *file_search_order[] = { + g_build_filename(g_get_user_config_dir(), "hardinfo", "edid.ids", NULL), + g_build_filename(params.path_data, "edid.ids", NULL), + NULL + }; + int n; + for(n = 0; file_search_order[n]; n++) { + if (!edid_ids_file && !access(file_search_order[n], R_OK)) + edid_ids_file = file_search_order[n]; + else + g_free(file_search_order[n]); + } + auto_free(edid_ids_file); +} + +typedef struct { + gchar *drm_connection; + uint8_t *edid_bin; + gsize edid_len; + struct edid id; + gchar *_vstr; /* use monitor_vendor_str() */ +} monitor; +#define monitor_new() g_new0(monitor, 1) + +monitor *monitor_new_from_sysfs(const gchar *sysfs_edid_file) { + monitor *m = monitor_new(); + g_file_get_contents(sysfs_edid_file, (gchar**)&(m->edid_bin), &m->edid_len, NULL); + if (m->edid_len) { + edid_fill(&m->id, (void*)(m->edid_bin), m->edid_len); + } + + gchar *pd = g_path_get_dirname(sysfs_edid_file); + m->drm_connection = g_path_get_basename(pd); + g_free(pd); + + return m; +} + +void monitor_free(monitor *m) { + if (m) { + g_free(m->_vstr); + g_free(m->drm_connection); + g_free(m->edid_bin); + g_free(m); + } +} + +const gchar *monitor_vendor_str(monitor *m) { + if (m->_vstr) + return m->_vstr; + + ids_query_result result = {}; + + if (!edid_ids_file) + find_edid_ids_file(); + + scan_ids_file(edid_ids_file, m->id.ven, &result, -1); + if (result.results[0]) { + m->_vstr = g_strdup(result.results[0]); + return m->_vstr; + } + return g_strdup(m->id.ven); +} + +gchar *monitor_name(monitor *m, gboolean include_vendor) { + if (!m) return NULL; + gchar *desc = NULL; + + if (include_vendor) { + if (*m->id.ven) + desc = appfsp(desc, "%s", vendor_get_shortest_name(monitor_vendor_str(m))); + else + desc = appfsp(desc, "%s", "Unknown"); + } + + if (m->id.diag_in) { + gchar *din = util_strchomp_float(g_strdup_printf("%0.1f", m->id.diag_in)); + desc = appfsp(desc, "%s\"", din); + g_free(din); + } + + if (m->id.name) + desc = appfsp(desc, "%s", m->id.name); + else + desc = appfsp(desc, "%s %s", m->id.a_or_d ? "Digital" : "Analog", "Display"); + + return desc; +} + +gchar **get_output_lines(const char *cmd_line) { + gboolean spawned; + gchar *out, *err; + gchar **ret = NULL; + + spawned = g_spawn_command_line_sync(cmd_line, + &out, &err, NULL, NULL); + if (spawned) { + ret = g_strsplit(out, "\n", -1); + g_free(out); + g_free(err); + } + return ret; +} + +static gchar *tag_make_safe_inplace(gchar *tag) { + if (!tag) + return tag; + if (!g_utf8_validate(tag, -1, NULL)) + return tag; //TODO: reconsider + gchar *p = tag, *pd = tag; + while(*p) { + gchar *np = g_utf8_next_char(p); + gunichar c = g_utf8_get_char_validated(p, -1); + int l = g_unichar_to_utf8(c, NULL); + if (l == 1 && g_unichar_isalnum(c)) { + g_unichar_to_utf8(c, pd); + } else { + *pd = '_'; + } + p = np; + pd++; + } + return tag; +} + +static gchar *make_edid_section(monitor *m) { + if (m->edid_len) { + const gchar *vstr = monitor_vendor_str(m); + + gchar *dom = NULL; + if (m->id.week && m->id.year) + dom = g_strdup_printf(_("Week %d of %d"), m->id.week, m->id.year); + else if (m->id.year) + dom = g_strdup_printf("%d", m->id.year); + + gchar *bpcc = NULL; + if (m->id.bpc) + bpcc = g_strdup_printf("%d", m->id.bpc); + + gchar *scr_size = NULL; + if (m->id.horiz_cm && m->id.vert_cm) + scr_size = g_strdup_printf("%d cm × %d cm", m->id.horiz_cm, m->id.vert_cm); + + int aok = m->id.checksum_ok; + if (m->id.ext_blocks_fail) aok = 0; + gchar *csum = aok ? _("Ok") : _("Fail"); + + gchar *ret = g_strdup_printf("[%s]\n" + "%s=%d.%d\n" /* version */ + "%s=%d %s\n" /* size */ + "%s=%d\n" /* ext block */ + "%s=%s %s\n" /* checksum */ + "[%s]\n" + "%s=%s\n" /* vendor */ + "%s=%s\n" /* name */ + "%s=%s\n" /* dom */ + "%s=%s\n" /* size */ + "%s=%s\n" /* sig type */ + "%s=%s\n" /* bpcc */ + , + _("EDID Meta"), + _("Version"), (int)m->id.ver_major, (int)m->id.ver_minor, + _("Data Size"), m->id.size, _("bytes"), + _("Extension Blocks"), m->id.ext_blocks, + _("Checksum"), csum, aok ? "" : problem_marker(), + _("EDID Device"), + _("Vendor"), vstr, + _("Name"), m->id.name, + _("Manufacture Date"), UNKIFNULL2(dom), + _("Screen Size"), UNKIFNULL2(scr_size), + _("Signal Type"), m->id.a_or_d ? _("Digital") : _("Analog"), + _("Bits per Color Channel"), UNKIFNULL2(bpcc) + ); + g_free(scr_size); + g_free(bpcc); + g_free(dom); + //printf("ret: %s\n", ret); + return ret; + } else + return g_strdup(""); +} + +gchar *monitors_get_info() { + + gchar *icons = g_strdup(""); + gchar *ret = g_strdup_printf("[%s]\n", _("Monitors")); + gchar tag_prefix[] = "DEV"; + + gchar **edid_files = get_output_lines("find /sys/devices -name edid"); + //gchar **edid_files = get_output_lines("find /home/pburt/github/verbose-spork/junk/testing/.testing/edid/ -name edid.*"); + int i, found = 0; + for(i = 0; edid_files[i]; i++) { + monitor *m = monitor_new_from_sysfs(edid_files[i]); + if (m) { + found++; + if (m->id.checksum_ok && m->drm_connection) { + gchar *tag = g_strdup_printf("%d-%s", found, m->drm_connection); + tag_make_safe_inplace(tag); + gchar *desc = monitor_name(m, TRUE); + gchar *edid_section = make_edid_section(m); + gchar *details = g_strdup_printf("[%s]\n" + "%s=%s\n" + "%s\n", + _("Connection"), + _("DRM"), m->drm_connection, + edid_section + ); + moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */ + ret = h_strdup_cprintf("$!%s$%s=%s|%s\n", + ret, + tag, m->drm_connection, desc + ); + icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, monitor_icon); + g_free(desc); + g_free(edid_section); + } + monitor_free(m); + } + } + + no_monitors = FALSE; + if(!found) { + no_monitors = TRUE; + g_free(ret); + ret = g_strdup_printf("[%s]\n%s=%s\n" "[$ShellParam$]\nViewType=0\n", + _("Monitors"), _("Result"), _("(Empty)") ); + } else { + ret = h_strdup_cprintf( + "[$ShellParam$]\nViewType=1\n" + "ColumnTitle$TextValue=%s\n" /* DRM connection */ + "ColumnTitle$Value=%s\n" /* Name */ + "ShowColumnHeaders=true\n" + "%s", + ret, + _("Connection"), + _("Name"), + icons + ); + } + + return ret; +} + +gboolean monitors_hinote(const char **msg) { + PARAM_NOT_UNUSED(msg); + return FALSE; +} |