Add an obprop tool which can print UTF-8 strings properly, for our users.

This commit is contained in:
Dana Jansens 2009-12-14 15:07:20 -05:00
parent 5fc18091be
commit f3e553446f
4 changed files with 338 additions and 1 deletions

1
.gitignore vendored
View file

@ -51,6 +51,7 @@ po/remove-potcdate.sed
render/obrender-3.0.pc
tools/gnome-panel-control/gnome-panel-control
tools/gdm-control/gdm-control
tools/obprop/obprop
version.h
.libs
.deps

View file

@ -32,7 +32,8 @@ lib_LTLIBRARIES = \
bin_PROGRAMS = \
openbox/openbox \
tools/gdm-control/gdm-control \
tools/gnome-panel-control/gnome-panel-control
tools/gnome-panel-control/gnome-panel-control \
tools/obprop/obprop
dist_secretbin_SCRIPTS = \
tools/xdg-autostart/xdg-autostart
@ -288,6 +289,17 @@ tools_gnome_panel_control_gnome_panel_control_LDADD = \
tools_gnome_panel_control_gnome_panel_control_SOURCES = \
tools/gnome-panel-control/gnome-panel-control.c
## obprop ##
tools_obprop_obprop_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(X_CFLAGS)
tools_obprop_obprop_LDADD = \
$(GLIB_LIBS) \
$(X_LIBS)
tools_obprop_obprop_SOURCES = \
tools/obprop/obprop.c
## gdm-control ##
tools_gdm_control_gdm_control_CPPFLAGS = \

4
tools/obprop/Makefile Normal file
View file

@ -0,0 +1,4 @@
all clean install:
$(MAKE) -C ../.. -$(MAKEFLAGS) $@
.PHONY: all clean install

320
tools/obprop/obprop.c Normal file
View file

@ -0,0 +1,320 @@
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <glib.h>
gint fail(const gchar *s) {
if (s)
fprintf(stderr, "%s\n", s);
else
fprintf
(stderr,
"Usage: obprop [OPTIONS]\n\n"
"Options:\n"
" --help Display this help and exit\n"
" --display DISPLAY Connect to this X display\n"
" --id ID Show the properties for this window\n");
return 1;
}
gint parse_hex(gchar *s) {
gint result = 0;
while (*s) {
gint add;
if (*s >= '0' && *s <='9')
add = *s-'0';
else if (*s >= 'A' && *s <='F')
add = *s-'A';
else if (*s >= 'a' && *s <='f')
add = *s-'a';
else
break;
result *= 16;
result += add;
}
return result;
}
Window find_client(Display *d, Window win)
{
Window r, *children;
guint n, i;
Atom state = XInternAtom(d, "WM_STATE", True);
Atom ret_type;
gint ret_format, res;
gulong ret_items, ret_bytesleft, *xdata;
XQueryTree(d, win, &r, &r, &children, &n);
for (i = 0; i < n; ++i) {
Window w = find_client(d, children[i]);
if (w) return w;
}
// try me
res = XGetWindowProperty(d, win, state, 0, 1,
False, state, &ret_type, &ret_format,
&ret_items, &ret_bytesleft,
(unsigned char**) &xdata);
XFree(xdata);
if (res != Success || ret_type == None || ret_items < 1)
return None;
return win; // found it!
}
static gboolean get_all(Display *d, Window win, Atom prop,
Atom *type, gint *size,
guchar **data, guint *num)
{
gboolean ret = FALSE;
gint res;
guchar *xdata = NULL;
gulong ret_items, bytes_left;
res = XGetWindowProperty(d, win, prop, 0l, G_MAXLONG,
FALSE, AnyPropertyType, type, size,
&ret_items, &bytes_left, &xdata);
if (res == Success) {
if (ret_items > 0) {
guint i;
*data = g_malloc(ret_items * (*size / 8));
for (i = 0; i < ret_items; ++i)
switch (*size) {
case 8:
(*data)[i] = xdata[i];
break;
case 16:
((guint16*)*data)[i] = ((gushort*)xdata)[i];
break;
case 32:
((guint32*)*data)[i] = ((gulong*)xdata)[i];
break;
default:
g_assert_not_reached(); /* unhandled size */
}
*num = ret_items;
ret = TRUE;
}
XFree(xdata);
}
return ret;
}
gchar *append_string(gchar *before, gchar *after, gboolean quote)
{
gchar *tmp;
const gchar *q = quote ? "\"" : "";
if (before)
tmp = g_strdup_printf("%s, %s%s%s", before, q, after, q);
else
tmp = g_strdup_printf("%s%s%s", q, after, q);
g_free(before);
return tmp;
}
gchar *append_int(gchar *before, guint after)
{
gchar *tmp;
if (before)
tmp = g_strdup_printf("%s, %u", before, after);
else
tmp = g_strdup_printf("%u", after);
g_free(before);
return tmp;
}
gchar* read_strings(gchar *val, guint n, gboolean utf8)
{
GSList *strs = NULL, *it;
gchar *ret, *p;
guint i;
p = val;
while (p < val + n) {
strs = g_slist_append(strs, g_strndup(p, n - (p - val)));
p += strlen(p) + 1; /* next string */
}
ret = NULL;
for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
char *data;
if (utf8) {
if (g_utf8_validate(it->data, -1, NULL))
data = g_strdup(it->data);
else
data = g_strdup("");
}
else
data = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL);
ret = append_string(ret, data, TRUE);
g_free(data);
}
while (strs) {
g_free(strs->data);
strs = g_slist_delete_link(strs, strs);
}
return ret;
}
gchar* read_atoms(Display *d, guchar *val, guint n)
{
gchar *ret;
guint i;
ret = NULL;
for (i = 0; i < n; ++i)
ret = append_string(ret, XGetAtomName(d, ((guint32*)val)[i]), FALSE);
return ret;
}
gchar* read_numbers(guchar *val, guint n, guint size)
{
gchar *ret;
guint i;
ret = NULL;
for (i = 0; i < n; ++i)
switch (size) {
case 8:
ret = append_int(ret, ((guint8*)val)[i]);
break;
case 16:
ret = append_int(ret, ((guint16*)val)[i]);
break;
case 32:
ret = append_int(ret, ((guint32*)val)[i]);
break;
default:
g_assert_not_reached(); /* unhandled size */
}
return ret;
}
gboolean read_prop(Display *d, Window w, Atom prop, const gchar **type, gchar **val)
{
guchar *ret;
guint nret;
gint size;
Atom ret_type;
ret = NULL;
if (get_all(d, w, prop, &ret_type, &size, &ret, &nret)) {
*type = XGetAtomName(d, ret_type);
if (strcmp(*type, "STRING") == 0)
*val = read_strings((gchar*)ret, nret, FALSE);
else if (strcmp(*type, "UTF8_STRING") == 0)
*val = read_strings((gchar*)ret, nret, TRUE);
else if (strcmp(*type, "ATOM") == 0) {
g_assert(size == 32);
*val = read_atoms(d, ret, nret);
}
else
*val = read_numbers(ret, nret, size);
g_free(ret);
return TRUE;
}
return FALSE;
}
void show_properties(Display *d, Window w)
{
Atom* props;
int i, n;
props = XListProperties(d, w, &n);
for (i = 0; i < n; ++i) {
const char *type;
char *name, *val;
name = XGetAtomName(d, props[i]);
if (read_prop(d, w, props[i], &type, &val)) {
g_print("%s(%s) = %s\n", name, type, val);
g_free(val);
}
XFree(name);
}
XFree(props);
}
int main(int argc, char **argv)
{
Display *d;
Window id, userid = None;
int i;
char *dname = NULL;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--help")) {
return fail(0);
}
else if (!strcmp(argv[i], "--id")) {
if (++i == argc)
return fail(0);
if (argv[i][0] == '0' && argv[i][1] == 'x') {
/* hex */
userid = parse_hex(argv[i]+2);
}
else {
/* decimal */
userid = atoi(argv[i]);
}
break;
}
else if (!strcmp(argv[i], "--display")) {
if (++i == argc)
return fail(0);
dname = argv[i];
}
}
d = XOpenDisplay(dname);
if (!d) {
return fail("Unable to find an X display. "
"Ensure you have permission to connect to the display.");
}
if (userid == None) {
i = XGrabPointer(d, RootWindow(d, DefaultScreen(d)),
False, ButtonPressMask,
GrabModeAsync, GrabModeAsync,
None, XCreateFontCursor(d, XC_crosshair),
CurrentTime);
if (i != GrabSuccess)
return fail("Unable to grab the pointer device");
while (1) {
XEvent ev;
XNextEvent(d, &ev);
if (ev.type == ButtonPress) {
XUngrabPointer(d, CurrentTime);
userid = ev.xbutton.subwindow;
break;
}
}
}
id = find_client(d, userid);
if (id == None)
return fail("Unable to find window with the requested ID");
show_properties(d, id);
XCloseDisplay(d);
return 0;
}