xlsclients.c revision 8e46b049
1a850946eSmrg/* 2a850946eSmrgCopyright 1989, 1998 The Open Group 37dff02feSmrgCopyright 2009 Open Text Corporation 4a850946eSmrg 5a850946eSmrgPermission to use, copy, modify, distribute, and sell this software and its 6a850946eSmrgdocumentation for any purpose is hereby granted without fee, provided that 7a850946eSmrgthe above copyright notice appear in all copies and that both that 8a850946eSmrgcopyright notice and this permission notice appear in supporting 9a850946eSmrgdocumentation. 10a850946eSmrg 11a850946eSmrgThe above copyright notice and this permission notice shall be included in 12a850946eSmrgall copies or substantial portions of the Software. 13a850946eSmrg 14a850946eSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15a850946eSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16a850946eSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17a850946eSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18a850946eSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19a850946eSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20a850946eSmrg 21a850946eSmrgExcept as contained in this notice, the name of The Open Group shall not be 22a850946eSmrgused in advertising or otherwise to promote the sale, use or other dealings 23a850946eSmrgin this Software without prior written authorization from The Open Group. 24a850946eSmrg * * 25a850946eSmrg * Author: Jim Fulton, MIT X Consortium 267dff02feSmrg * Author: Peter Harris, Open Text Corporation 27a850946eSmrg */ 287dff02feSmrg 297dff02feSmrg#ifdef HAVE_CONFIG_H 307dff02feSmrg#include "config.h" 317dff02feSmrg#endif 32a850946eSmrg 33a850946eSmrg#include <stdio.h> 34a850946eSmrg#include <stdlib.h> 357dff02feSmrg#include <string.h> 36a850946eSmrg#include <ctype.h> 377dff02feSmrg#include <inttypes.h> 387dff02feSmrg#include <xcb/xcb.h> 397dff02feSmrg#include <xcb/xproto.h> 407dff02feSmrg#ifndef HAVE_STRNLEN 417dff02feSmrg#include "strnlen.h" 427dff02feSmrg#endif 437dff02feSmrg 447dff02feSmrg#ifndef PRIx32 457dff02feSmrg#define PRIx32 "x" 467dff02feSmrg#endif 477dff02feSmrg#ifndef PRIu32 487dff02feSmrg#define PRIu32 "u" 497dff02feSmrg#endif 50a850946eSmrg 5170f7c90cSmrgstatic char *ProgramName; 52a850946eSmrg 537dff02feSmrgstatic xcb_atom_t WM_STATE; 547dff02feSmrg 557dff02feSmrgstatic void lookat (xcb_connection_t *dpy, xcb_window_t root, int verbose, int maxcmdlen); 567dff02feSmrgstatic void print_client_properties (xcb_connection_t *dpy, xcb_window_t w, 577dff02feSmrg int verbose, int maxcmdlen ); 587dff02feSmrgstatic void print_text_field (xcb_connection_t *dpy, char *s, xcb_get_property_reply_t *tp ); 597dff02feSmrgstatic int print_quoted_word (char *s, int maxlen); 607dff02feSmrgstatic void unknown (xcb_connection_t *dpy, xcb_atom_t actual_type, int actual_format ); 617dff02feSmrg 627dff02feSmrg/* For convenience: */ 637dff02feSmrgtypedef int Bool; 647dff02feSmrg#define False (0) 657dff02feSmrg#define True (!False) 66a850946eSmrg 67a850946eSmrgstatic void 68a850946eSmrgusage(void) 69a850946eSmrg{ 70a850946eSmrg fprintf (stderr, 71a850946eSmrg "usage: %s [-display dpy] [-m len] [-[a][l]]\n", ProgramName); 72a850946eSmrg exit (1); 73a850946eSmrg} 74a850946eSmrg 757dff02feSmrgtypedef void (*queue_func)(void *closure); 767dff02feSmrgtypedef struct queue_blob { 777dff02feSmrg queue_func func; 787dff02feSmrg void *closure; 797dff02feSmrg struct queue_blob *next; 807dff02feSmrg} queue_blob; 817dff02feSmrg 827dff02feSmrgstatic queue_blob *head = NULL; 837dff02feSmrgstatic queue_blob **tail = &head; 847dff02feSmrg 857dff02feSmrgstatic void enqueue(queue_func func, void *closure) 867dff02feSmrg{ 877dff02feSmrg queue_blob *blob = malloc(sizeof(*blob)); 887dff02feSmrg if (!blob) 897dff02feSmrg return; /* TODO: print OOM error */ 907dff02feSmrg 917dff02feSmrg blob->func = func; 927dff02feSmrg blob->closure = closure; 937dff02feSmrg blob->next = NULL; 947dff02feSmrg *tail = blob; 957dff02feSmrg tail = &blob->next; 967dff02feSmrg} 977dff02feSmrg 987dff02feSmrgstatic void run_queue(void) 997dff02feSmrg{ 1007dff02feSmrg while (head) { 1017dff02feSmrg queue_blob *blob = head; 1027dff02feSmrg blob->func(blob->closure); 1037dff02feSmrg head = blob->next; 1047dff02feSmrg free(blob); 1057dff02feSmrg } 1067dff02feSmrg tail = &head; 1077dff02feSmrg} 1087dff02feSmrg 1097dff02feSmrgtypedef struct { 1107dff02feSmrg xcb_connection_t *c; 1117dff02feSmrg xcb_intern_atom_cookie_t cookie; 1127dff02feSmrg xcb_atom_t *atom; 1137dff02feSmrg} atom_state; 1147dff02feSmrg 1157dff02feSmrgstatic void atom_done(void *closure) 1167dff02feSmrg{ 1177dff02feSmrg xcb_intern_atom_reply_t *reply; 1187dff02feSmrg atom_state *as = closure; 1197dff02feSmrg 1207dff02feSmrg reply = xcb_intern_atom_reply(as->c, as->cookie, NULL); 1217dff02feSmrg if (!reply) 1227dff02feSmrg goto done; /* TODO: print Error message */ 1237dff02feSmrg 1247dff02feSmrg *(as->atom) = reply->atom; 1257dff02feSmrg free(reply); 1267dff02feSmrg 1277dff02feSmrgdone: 1287dff02feSmrg free(as); 1297dff02feSmrg} 1307dff02feSmrg 1317dff02feSmrgstatic void init_atoms(xcb_connection_t *c) 1327dff02feSmrg{ 1337dff02feSmrg atom_state *as; 1347dff02feSmrg 1357dff02feSmrg as = malloc(sizeof(*as)); 1367dff02feSmrg as->c = c; 1377dff02feSmrg as->atom = &WM_STATE; 1387dff02feSmrg as->cookie = xcb_intern_atom(c, 0, strlen("WM_STATE"), "WM_STATE"); 1397dff02feSmrg enqueue(atom_done, as); 1407dff02feSmrg} 1417dff02feSmrg 142a850946eSmrgint 143a850946eSmrgmain(int argc, char *argv[]) 144a850946eSmrg{ 145a850946eSmrg int i; 146a850946eSmrg char *displayname = NULL; 147a850946eSmrg Bool all_screens = False; 148a850946eSmrg Bool verbose = False; 1497dff02feSmrg xcb_connection_t *dpy; 1507dff02feSmrg const xcb_setup_t *setup; 1517dff02feSmrg int screen_number = 0; 152a850946eSmrg int maxcmdlen = 10000; 153a850946eSmrg 154a850946eSmrg ProgramName = argv[0]; 155a850946eSmrg 156a850946eSmrg for (i = 1; i < argc; i++) { 157a850946eSmrg char *arg = argv[i]; 158a850946eSmrg 159a850946eSmrg if (arg[0] == '-') { 160a850946eSmrg char *cp; 161a850946eSmrg 162a850946eSmrg switch (arg[1]) { 163a850946eSmrg case 'd': /* -display dpyname */ 164a850946eSmrg if (++i >= argc) usage (); 165a850946eSmrg displayname = argv[i]; 166a850946eSmrg continue; 167a850946eSmrg case 'm': /* -max maxcmdlen */ 168a850946eSmrg if (++i >= argc) usage (); 169a850946eSmrg maxcmdlen = atoi (argv[i]); 170a850946eSmrg continue; 171a850946eSmrg } 172a850946eSmrg 173a850946eSmrg for (cp = &arg[1]; *cp; cp++) { 174a850946eSmrg switch (*cp) { 175a850946eSmrg case 'a': /* -all */ 176a850946eSmrg all_screens = True; 177a850946eSmrg continue; 178a850946eSmrg case 'l': /* -long */ 179a850946eSmrg verbose = True; 180a850946eSmrg continue; 181a850946eSmrg default: 182a850946eSmrg usage (); 183a850946eSmrg } 184a850946eSmrg } 185a850946eSmrg } else { 186a850946eSmrg usage (); 187a850946eSmrg } 188a850946eSmrg } 189a850946eSmrg 1907dff02feSmrg dpy = xcb_connect(displayname, &screen_number); 1917dff02feSmrg if (xcb_connection_has_error(dpy)) { 1927dff02feSmrg char *name = displayname; 1937dff02feSmrg if (!name) 1947dff02feSmrg name = getenv("DISPLAY"); 1957dff02feSmrg if (!name) 1967dff02feSmrg name = ""; 197a850946eSmrg fprintf (stderr, "%s: unable to open display \"%s\"\r\n", 1987dff02feSmrg ProgramName, name); 199a850946eSmrg exit (1); 200a850946eSmrg } 201a850946eSmrg 2027dff02feSmrg init_atoms(dpy); 2037dff02feSmrg 2047dff02feSmrg setup = xcb_get_setup(dpy); 205a850946eSmrg if (all_screens) { 2067dff02feSmrg xcb_screen_iterator_t screen; 2077dff02feSmrg 2087dff02feSmrg screen = xcb_setup_roots_iterator(setup); 2097dff02feSmrg do { 2107dff02feSmrg lookat(dpy, screen.data->root, verbose, maxcmdlen); 2117dff02feSmrg xcb_screen_next(&screen); 2127dff02feSmrg } while (screen.rem); 213a850946eSmrg } else { 2147dff02feSmrg xcb_screen_iterator_t screen; 2157dff02feSmrg 2167dff02feSmrg screen = xcb_setup_roots_iterator(setup); 2177dff02feSmrg for (i = 0; i < screen_number; i++) 2187dff02feSmrg xcb_screen_next(&screen); 2197dff02feSmrg 2207dff02feSmrg lookat (dpy, screen.data->root, verbose, maxcmdlen); 221a850946eSmrg } 222a850946eSmrg 2237dff02feSmrg run_queue(); 2247dff02feSmrg 2257dff02feSmrg xcb_disconnect(dpy); 226a850946eSmrg exit (0); 227a850946eSmrg} 228a850946eSmrg 2297dff02feSmrgtypedef struct { 2307dff02feSmrg xcb_connection_t *c; 2317dff02feSmrg xcb_get_property_cookie_t *prop_cookie; 2327dff02feSmrg xcb_query_tree_cookie_t *tree_cookie; 2337dff02feSmrg xcb_window_t *win; 2347dff02feSmrg xcb_window_t orig_win; 2357dff02feSmrg int list_length; 2367dff02feSmrg int verbose; 2377dff02feSmrg int maxcmdlen; 2387dff02feSmrg} child_wm_state; 2397dff02feSmrg 2407dff02feSmrgstatic void child_info(void *closure) 2417dff02feSmrg{ 2427dff02feSmrg child_wm_state *cs = closure; 2437dff02feSmrg xcb_window_t orig = cs->orig_win; 2447dff02feSmrg xcb_connection_t *c = cs->c; 2457dff02feSmrg int verbose = cs->verbose; 2467dff02feSmrg int maxcmdlen = cs->maxcmdlen; 2477dff02feSmrg int i, j; 2487dff02feSmrg 2497dff02feSmrg int child_count, num_rep; 2507dff02feSmrg xcb_query_tree_reply_t **reply; 2517dff02feSmrg 2527dff02feSmrg for (i = 0; i < cs->list_length; i++) { 2537dff02feSmrg xcb_get_property_reply_t *reply; 2547dff02feSmrg reply = xcb_get_property_reply(c, cs->prop_cookie[i], NULL); 2557dff02feSmrg if (reply) { 2567dff02feSmrg if (reply->type) { 2577dff02feSmrg /* Show information for this window */ 2587dff02feSmrg print_client_properties(c, cs->win[i], cs->verbose, cs->maxcmdlen); 2597dff02feSmrg 2607dff02feSmrg free(reply); 2617dff02feSmrg 2627dff02feSmrg /* drain stale replies */ 2637dff02feSmrg for (j = i+1; j < cs->list_length; j++) { 2647dff02feSmrg reply = xcb_get_property_reply(c, cs->prop_cookie[j], NULL); 2657dff02feSmrg if (reply) 2667dff02feSmrg free(reply); 2677dff02feSmrg } 2687dff02feSmrg for (j = 0; j < cs->list_length; j++) { 2697dff02feSmrg xcb_query_tree_reply_t *rep; 2707dff02feSmrg rep = xcb_query_tree_reply(c, cs->tree_cookie[j], NULL); 2717dff02feSmrg if (rep) 2727dff02feSmrg free(rep); 2737dff02feSmrg } 2747dff02feSmrg goto done; 2757dff02feSmrg } 2767dff02feSmrg free(reply); 2777dff02feSmrg } 2787dff02feSmrg } 2797dff02feSmrg 2807dff02feSmrg /* WM_STATE not found. Recurse into children: */ 2817dff02feSmrg num_rep = 0; 2827dff02feSmrg reply = malloc(sizeof(*reply) * cs->list_length); 2837dff02feSmrg if (!reply) 2847dff02feSmrg goto done; /* TODO: print OOM message, drain reply queue */ 2857dff02feSmrg 2867dff02feSmrg for (i = 0; i < cs->list_length; i++) { 2877dff02feSmrg reply[num_rep] = xcb_query_tree_reply(c, cs->tree_cookie[i], NULL); 2887dff02feSmrg if (reply[num_rep]) 2897dff02feSmrg num_rep++; 2907dff02feSmrg } 2917dff02feSmrg 2927dff02feSmrg child_count = 0; 2937dff02feSmrg for (i = 0; i < num_rep; i++) 2947dff02feSmrg child_count += reply[i]->children_len; 2957dff02feSmrg 2967dff02feSmrg if (!child_count) { 2977dff02feSmrg /* No children have CS_STATE; try the parent window */ 2987dff02feSmrg print_client_properties(c, cs->orig_win, cs->verbose, cs->maxcmdlen); 2997dff02feSmrg goto reply_done; 3007dff02feSmrg } 3017dff02feSmrg 3027dff02feSmrg cs = malloc(sizeof(*cs) + child_count * (sizeof(*cs->prop_cookie) + sizeof(*cs->tree_cookie) + sizeof(*cs->win))); 3037dff02feSmrg if (!cs) 3047dff02feSmrg goto reply_done; /* TODO: print OOM message */ 3057dff02feSmrg 3067dff02feSmrg cs->c = c; 3077dff02feSmrg cs->verbose = verbose; 3087dff02feSmrg cs->maxcmdlen = maxcmdlen; 3097dff02feSmrg cs->orig_win = orig; 3107dff02feSmrg cs->prop_cookie = (void *)&cs[1]; 3117dff02feSmrg cs->tree_cookie = (void *)&cs->prop_cookie[child_count]; 3127dff02feSmrg cs->win = (void *)&cs->tree_cookie[child_count]; 3137dff02feSmrg cs->list_length = child_count; 3147dff02feSmrg 3157dff02feSmrg child_count = 0; 3167dff02feSmrg for (i = 0; i < num_rep; i++) { 3177dff02feSmrg xcb_window_t *child = xcb_query_tree_children(reply[i]); 3187dff02feSmrg for (j = 0; j < reply[i]->children_len; j++) { 3197dff02feSmrg cs->win[child_count] = child[j]; 3207dff02feSmrg cs->prop_cookie[child_count] = xcb_get_property(c, 0, child[j], 3217dff02feSmrg WM_STATE, XCB_GET_PROPERTY_TYPE_ANY, 3227dff02feSmrg 0, 0); 3237dff02feSmrg /* Just in case the property isn't there, get the tree too */ 3247dff02feSmrg cs->tree_cookie[child_count++] = xcb_query_tree(c, child[j]); 3257dff02feSmrg } 3267dff02feSmrg } 3277dff02feSmrg 3287dff02feSmrg enqueue(child_info, cs); 3297dff02feSmrg 3307dff02feSmrgreply_done: 3317dff02feSmrg for (i = 0; i < num_rep; i++) 3327dff02feSmrg free(reply[i]); 3337dff02feSmrg free(reply); 3347dff02feSmrg 3357dff02feSmrgdone: 3367dff02feSmrg free(closure); 3377dff02feSmrg} 3387dff02feSmrg 3397dff02feSmrgtypedef struct { 3407dff02feSmrg xcb_connection_t *c; 3417dff02feSmrg xcb_query_tree_cookie_t cookie; 3427dff02feSmrg int verbose; 3437dff02feSmrg int maxcmdlen; 3447dff02feSmrg} root_list_state; 3457dff02feSmrg 3467dff02feSmrgstatic void root_list(void *closure) 3477dff02feSmrg{ 3487dff02feSmrg int i; 3497dff02feSmrg xcb_window_t *child; 3507dff02feSmrg xcb_query_tree_reply_t *reply; 3517dff02feSmrg root_list_state *rl = closure; 3527dff02feSmrg 3537dff02feSmrg reply = xcb_query_tree_reply(rl->c, rl->cookie, NULL); 3547dff02feSmrg if (!reply) 3557dff02feSmrg goto done; 3567dff02feSmrg 3577dff02feSmrg child = xcb_query_tree_children(reply); 3587dff02feSmrg for (i = 0; i < reply->children_len; i++) { 3597dff02feSmrg /* Get information about each child */ 3607dff02feSmrg child_wm_state *cs = malloc(sizeof(*cs) + sizeof(*cs->prop_cookie) + sizeof(*cs->tree_cookie) + sizeof(*cs->win)); 3617dff02feSmrg if (!cs) 3627dff02feSmrg goto done; /* TODO: print OOM message */ 3637dff02feSmrg cs->c = rl->c; 3647dff02feSmrg cs->verbose = rl->verbose; 3657dff02feSmrg cs->maxcmdlen = rl->maxcmdlen; 3667dff02feSmrg cs->prop_cookie = (void *)&cs[1]; 3677dff02feSmrg cs->tree_cookie = (void *)&cs->prop_cookie[1]; 3687dff02feSmrg cs->win = (void *)&cs->tree_cookie[1]; 3697dff02feSmrg 3707dff02feSmrg cs->orig_win = child[i]; 3717dff02feSmrg cs->win[0] = child[i]; 3727dff02feSmrg 3737dff02feSmrg cs->prop_cookie[0] = xcb_get_property(rl->c, 0, child[i], 3747dff02feSmrg WM_STATE, XCB_GET_PROPERTY_TYPE_ANY, 3757dff02feSmrg 0, 0); 3767dff02feSmrg /* Just in case the property isn't there, get the tree too */ 3777dff02feSmrg cs->tree_cookie[0] = xcb_query_tree(rl->c, child[i]); 3787dff02feSmrg 3797dff02feSmrg cs->list_length = 1; 3807dff02feSmrg enqueue(child_info, cs); 3817dff02feSmrg } 3827dff02feSmrg free(reply); 3837dff02feSmrg 3847dff02feSmrgdone: 3857dff02feSmrg free(rl); 3867dff02feSmrg} 3877dff02feSmrg 388a850946eSmrgstatic void 3897dff02feSmrglookat(xcb_connection_t *dpy, xcb_window_t root, int verbose, int maxcmdlen) 390a850946eSmrg{ 3917dff02feSmrg root_list_state *rl = malloc(sizeof(*rl)); 392a850946eSmrg 3937dff02feSmrg if (!rl) 3947dff02feSmrg return; /* TODO: OOM message */ 395a850946eSmrg 396a850946eSmrg /* 3977dff02feSmrg * get the list of windows 398a850946eSmrg */ 399a850946eSmrg 4007dff02feSmrg rl->c = dpy; 4017dff02feSmrg rl->cookie = xcb_query_tree(dpy, root); 4027dff02feSmrg rl->verbose = verbose; 4037dff02feSmrg rl->maxcmdlen = maxcmdlen; 4047dff02feSmrg enqueue(root_list, rl); 405a850946eSmrg} 406a850946eSmrg 407a850946eSmrgstatic char *Nil = "(nil)"; 408a850946eSmrg 4097dff02feSmrgtypedef struct { 4107dff02feSmrg xcb_connection_t *c; 4117dff02feSmrg xcb_get_property_cookie_t client_machine; 4127dff02feSmrg xcb_get_property_cookie_t command; 4137dff02feSmrg xcb_get_property_cookie_t name; 4147dff02feSmrg xcb_get_property_cookie_t icon_name; 4157dff02feSmrg xcb_get_property_cookie_t wm_class; 4167dff02feSmrg xcb_window_t w; 4177dff02feSmrg int verbose; 4187dff02feSmrg int maxcmdlen; 4197dff02feSmrg} client_state; 4207dff02feSmrg 421a850946eSmrgstatic void 4227dff02feSmrgshow_client_properties(void *closure) 423a850946eSmrg{ 4247dff02feSmrg client_state *cs = closure; 4257dff02feSmrg xcb_get_property_reply_t *client_machine; 4267dff02feSmrg xcb_get_property_reply_t *command; 4277dff02feSmrg xcb_get_property_reply_t *name; 4287dff02feSmrg xcb_get_property_reply_t *icon_name; 4297dff02feSmrg xcb_get_property_reply_t *wm_class; 4307dff02feSmrg char *argv; 4317dff02feSmrg int charsleft = cs->maxcmdlen; 4327dff02feSmrg int i; 433a850946eSmrg 434a850946eSmrg /* 435a850946eSmrg * get the WM_MACHINE and WM_COMMAND list of strings 436a850946eSmrg */ 4377dff02feSmrg client_machine = xcb_get_property_reply(cs->c, cs->client_machine, NULL); 4387dff02feSmrg command = xcb_get_property_reply(cs->c, cs->command, NULL); 4397dff02feSmrg if (cs->verbose) { 4407dff02feSmrg name = xcb_get_property_reply(cs->c, cs->name, NULL); 4417dff02feSmrg icon_name = xcb_get_property_reply(cs->c, cs->icon_name, NULL); 4427dff02feSmrg wm_class = xcb_get_property_reply(cs->c, cs->wm_class, NULL); 443a850946eSmrg } 444a850946eSmrg 4457dff02feSmrg if (!command || !command->type) 4467dff02feSmrg goto done; 447a850946eSmrg 448a850946eSmrg /* 449a850946eSmrg * do header information 450a850946eSmrg */ 4517dff02feSmrg if (cs->verbose) { 4527dff02feSmrg printf ("Window 0x%" PRIx32 ":\n", cs->w); 4537dff02feSmrg print_text_field (cs->c, " Machine: ", client_machine); 4547dff02feSmrg if (name && name->type) 4557dff02feSmrg print_text_field (cs->c, " Name: ", name); 456a850946eSmrg } else { 4577dff02feSmrg print_text_field (cs->c, NULL, client_machine); 458a850946eSmrg putchar (' '); 459a850946eSmrg putchar (' '); 460a850946eSmrg } 461a850946eSmrg 4627dff02feSmrg 4637dff02feSmrg if (cs->verbose) 4647dff02feSmrg if (icon_name && icon_name->type) 4657dff02feSmrg print_text_field (cs->c, " Icon Name: ", icon_name); 466a850946eSmrg 467a850946eSmrg 468a850946eSmrg /* 469a850946eSmrg * do the command 470a850946eSmrg */ 4717dff02feSmrg if (cs->verbose) 472a850946eSmrg printf (" Command: "); 4737dff02feSmrg argv = xcb_get_property_value(command); 4747dff02feSmrg for (i = 0; i < command->value_len && charsleft > 0; ) { 4757dff02feSmrg charsleft -= print_quoted_word (argv + i, charsleft); 4767dff02feSmrg i += strnlen(argv + i, command->value_len - i) + 1; 4777dff02feSmrg if (i < command->value_len && charsleft > 0) { 4787dff02feSmrg putchar (' '); 4797dff02feSmrg charsleft--; 480a850946eSmrg } 481a850946eSmrg } 482a850946eSmrg putchar ('\n'); 483a850946eSmrg 484a850946eSmrg 485a850946eSmrg /* 486a850946eSmrg * do trailer information 487a850946eSmrg */ 4887dff02feSmrg if (cs->verbose) { 4897dff02feSmrg if (wm_class && wm_class->type) { 4907dff02feSmrg char *res_name, *res_class; 4917dff02feSmrg int name_len, class_len; 4927dff02feSmrg res_name = xcb_get_property_value(wm_class); 4937dff02feSmrg name_len = strnlen(res_name, wm_class->value_len) + 1; 4947dff02feSmrg class_len = wm_class->value_len - name_len; 4957dff02feSmrg if (class_len > 0) { 4967dff02feSmrg res_class = res_name + name_len; 4977dff02feSmrg } else { 4987dff02feSmrg res_class = Nil; 4997dff02feSmrg class_len = strlen(res_class); 5007dff02feSmrg } 5017dff02feSmrg 5027dff02feSmrg printf (" Instance/Class: %.*s/%.*s", 5037dff02feSmrg name_len, res_name, 5047dff02feSmrg class_len, res_class); 505a850946eSmrg putchar ('\n'); 506a850946eSmrg } 507a850946eSmrg } 5087dff02feSmrg 5097dff02feSmrgdone: 5107dff02feSmrg if (client_machine) 5117dff02feSmrg free(client_machine); 5127dff02feSmrg if (command) 5137dff02feSmrg free(command); 5147dff02feSmrg if (cs->verbose) { 5157dff02feSmrg if (name) 5167dff02feSmrg free(name); 5177dff02feSmrg if (icon_name) 5187dff02feSmrg free(icon_name); 5197dff02feSmrg if (wm_class) 5207dff02feSmrg free(wm_class); 5217dff02feSmrg } 5227dff02feSmrg free(cs); 523a850946eSmrg} 524a850946eSmrg 525a850946eSmrgstatic void 5267dff02feSmrgprint_client_properties(xcb_connection_t *dpy, xcb_window_t w, int verbose, int maxcmdlen) 527a850946eSmrg{ 5287dff02feSmrg client_state *cs = malloc(sizeof(*cs)); 5297dff02feSmrg if (!cs) 5307dff02feSmrg return; /* TODO: print OOM message */ 5317dff02feSmrg 5327dff02feSmrg cs->c = dpy; 5337dff02feSmrg cs->w = w; 5347dff02feSmrg cs->verbose = verbose; 5357dff02feSmrg cs->maxcmdlen = maxcmdlen; 5367dff02feSmrg 5377dff02feSmrg /* 5387dff02feSmrg * get the WM_CLIENT_MACHINE and WM_COMMAND list of strings 5397dff02feSmrg */ 5407dff02feSmrg cs->client_machine = xcb_get_property(dpy, 0, w, 5418e46b049Smrg XCB_ATOM_WM_CLIENT_MACHINE, XCB_GET_PROPERTY_TYPE_ANY, 5427dff02feSmrg 0, 1000000L); 5437dff02feSmrg cs->command = xcb_get_property(dpy, 0, w, 5448e46b049Smrg XCB_ATOM_WM_COMMAND, XCB_GET_PROPERTY_TYPE_ANY, 5457dff02feSmrg 0, 1000000L); 5467dff02feSmrg 5477dff02feSmrg if (verbose) { 5487dff02feSmrg cs->name = xcb_get_property(dpy, 0, w, 5498e46b049Smrg XCB_ATOM_WM_NAME, XCB_GET_PROPERTY_TYPE_ANY, 5507dff02feSmrg 0, 1000000L); 5517dff02feSmrg cs->icon_name = xcb_get_property(dpy, 0, w, 5528e46b049Smrg XCB_ATOM_WM_ICON_NAME, XCB_GET_PROPERTY_TYPE_ANY, 5537dff02feSmrg 0, 1000000L); 5547dff02feSmrg cs->wm_class = xcb_get_property(dpy, 0, w, 5558e46b049Smrg XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 5567dff02feSmrg 0, 1000000L); 5577dff02feSmrg } 5587dff02feSmrg 5597dff02feSmrg enqueue(show_client_properties, cs); 5607dff02feSmrg} 5617dff02feSmrg 5627dff02feSmrgstatic void 5637dff02feSmrgprint_text_field(xcb_connection_t *dpy, char *s, xcb_get_property_reply_t *tp) 5647dff02feSmrg{ 5657dff02feSmrg if (tp->type == XCB_NONE || tp->format == 0) { /* Or XCB_ATOM_NONE after libxcb 1.5 */ 566a850946eSmrg printf ("''"); 567a850946eSmrg return; 568a850946eSmrg } 569a850946eSmrg 570a850946eSmrg if (s) printf ("%s", s); 5718e46b049Smrg if (tp->type == XCB_ATOM_STRING && tp->format == 8) { 5727dff02feSmrg printf ("%.*s", (int)tp->value_len, (char *)xcb_get_property_value(tp)); 573a850946eSmrg } else { 5747dff02feSmrg unknown (dpy, tp->type, tp->format); 575a850946eSmrg } 576a850946eSmrg if (s) putchar ('\n'); 577a850946eSmrg} 578a850946eSmrg 579a850946eSmrg/* returns the number of characters printed */ 580a850946eSmrgstatic int 581a850946eSmrgprint_quoted_word(char *s, 582a850946eSmrg int maxlen) /* max number of chars we can print */ 583a850946eSmrg{ 584a850946eSmrg register char *cp; 585a850946eSmrg Bool need_quote = False, in_quote = False; 586a850946eSmrg char quote_char = '\'', other_quote = '"'; 587a850946eSmrg int charsprinted = 0; 588a850946eSmrg 589a850946eSmrg /* 590a850946eSmrg * walk down seeing whether or not we need to quote 591a850946eSmrg */ 592a850946eSmrg for (cp = s; *cp; cp++) { 593a850946eSmrg 594a850946eSmrg if (! ((isascii(*cp) && isalnum(*cp)) || 595a850946eSmrg (*cp == '-' || *cp == '_' || *cp == '.' || *cp == '+' || 596a850946eSmrg *cp == '/' || *cp == '=' || *cp == ':' || *cp == ','))) { 597a850946eSmrg need_quote = True; 598a850946eSmrg break; 599a850946eSmrg } 600a850946eSmrg } 601a850946eSmrg 602a850946eSmrg /* 603a850946eSmrg * write out the string: if we hit a quote, then close any previous quote, 604a850946eSmrg * emit the other quote, swap quotes and continue on. 605a850946eSmrg */ 606a850946eSmrg in_quote = need_quote; 607a850946eSmrg if (need_quote) { 608a850946eSmrg putchar (quote_char); 609a850946eSmrg charsprinted++; maxlen--; 610a850946eSmrg } 611a850946eSmrg for (cp = s; *cp && maxlen>0; cp++) { 612a850946eSmrg if (*cp == quote_char) { 613a850946eSmrg if (in_quote) { 614a850946eSmrg putchar (quote_char); 615a850946eSmrg charsprinted++; maxlen--; 616a850946eSmrg } 617a850946eSmrg putchar (other_quote); 618a850946eSmrg charsprinted++; maxlen--; 619a850946eSmrg { 620a850946eSmrg char tmp = other_quote; 621a850946eSmrg other_quote = quote_char; quote_char = tmp; 622a850946eSmrg } 623a850946eSmrg in_quote = True; 624a850946eSmrg } 625a850946eSmrg putchar (*cp); 626a850946eSmrg charsprinted++; maxlen--; 627a850946eSmrg } 628a850946eSmrg /* close the quote if we opened one and if we printed the whole string */ 629a850946eSmrg if (in_quote && maxlen>0) { 630a850946eSmrg putchar (quote_char); 631a850946eSmrg charsprinted++; maxlen--; 632a850946eSmrg } 633a850946eSmrg 634a850946eSmrg return charsprinted; 635a850946eSmrg} 636a850946eSmrg 637a850946eSmrgstatic void 6387dff02feSmrgunknown(xcb_connection_t *dpy, xcb_atom_t actual_type, int actual_format) 639a850946eSmrg{ 640a850946eSmrg printf ("<unknown type "); 6417dff02feSmrg if (actual_type == XCB_NONE) 6427dff02feSmrg printf ("None"); 6437dff02feSmrg else { 6447dff02feSmrg /* This should happen so rarely as to make no odds. Eat a round-trip: */ 6457dff02feSmrg xcb_get_atom_name_reply_t *atom = 6467dff02feSmrg xcb_get_atom_name_reply(dpy, 6477dff02feSmrg xcb_get_atom_name(dpy, actual_type), NULL); 6487dff02feSmrg if (atom) { 6497dff02feSmrg printf("%.*s", xcb_get_atom_name_name_length(atom), 6507dff02feSmrg xcb_get_atom_name_name(atom)); 6517dff02feSmrg free(atom); 6527dff02feSmrg } else 6537dff02feSmrg fputs (Nil, stdout); 654a850946eSmrg } 6557dff02feSmrg printf (" (%" PRIu32 ") or format %d>", actual_type, actual_format); 656a850946eSmrg} 657