xlsclients.c revision 9511053f
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 ); 589511053fSmrgstatic void print_text_field (xcb_connection_t *dpy, const 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, 719511053fSmrg "usage: %s [-display dpy] [-m len] [-[a][l]] [-version]\n", 729511053fSmrg ProgramName); 73a850946eSmrg exit (1); 74a850946eSmrg} 75a850946eSmrg 767dff02feSmrgtypedef void (*queue_func)(void *closure); 777dff02feSmrgtypedef struct queue_blob { 787dff02feSmrg queue_func func; 797dff02feSmrg void *closure; 807dff02feSmrg struct queue_blob *next; 817dff02feSmrg} queue_blob; 827dff02feSmrg 837dff02feSmrgstatic queue_blob *head = NULL; 847dff02feSmrgstatic queue_blob **tail = &head; 857dff02feSmrg 867dff02feSmrgstatic void enqueue(queue_func func, void *closure) 877dff02feSmrg{ 887dff02feSmrg queue_blob *blob = malloc(sizeof(*blob)); 897dff02feSmrg if (!blob) 907dff02feSmrg return; /* TODO: print OOM error */ 917dff02feSmrg 927dff02feSmrg blob->func = func; 937dff02feSmrg blob->closure = closure; 947dff02feSmrg blob->next = NULL; 957dff02feSmrg *tail = blob; 967dff02feSmrg tail = &blob->next; 977dff02feSmrg} 987dff02feSmrg 997dff02feSmrgstatic void run_queue(void) 1007dff02feSmrg{ 1017dff02feSmrg while (head) { 1027dff02feSmrg queue_blob *blob = head; 1037dff02feSmrg blob->func(blob->closure); 1047dff02feSmrg head = blob->next; 1057dff02feSmrg free(blob); 1067dff02feSmrg } 1077dff02feSmrg tail = &head; 1087dff02feSmrg} 1097dff02feSmrg 1107dff02feSmrgtypedef struct { 1117dff02feSmrg xcb_connection_t *c; 1127dff02feSmrg xcb_intern_atom_cookie_t cookie; 1137dff02feSmrg xcb_atom_t *atom; 1147dff02feSmrg} atom_state; 1157dff02feSmrg 1167dff02feSmrgstatic void atom_done(void *closure) 1177dff02feSmrg{ 1187dff02feSmrg xcb_intern_atom_reply_t *reply; 1197dff02feSmrg atom_state *as = closure; 1207dff02feSmrg 1217dff02feSmrg reply = xcb_intern_atom_reply(as->c, as->cookie, NULL); 1227dff02feSmrg if (!reply) 1237dff02feSmrg goto done; /* TODO: print Error message */ 1247dff02feSmrg 1257dff02feSmrg *(as->atom) = reply->atom; 1267dff02feSmrg free(reply); 1277dff02feSmrg 1287dff02feSmrgdone: 1297dff02feSmrg free(as); 1307dff02feSmrg} 1317dff02feSmrg 1327dff02feSmrgstatic void init_atoms(xcb_connection_t *c) 1337dff02feSmrg{ 1347dff02feSmrg atom_state *as; 1357dff02feSmrg 1367dff02feSmrg as = malloc(sizeof(*as)); 1377dff02feSmrg as->c = c; 1387dff02feSmrg as->atom = &WM_STATE; 1397dff02feSmrg as->cookie = xcb_intern_atom(c, 0, strlen("WM_STATE"), "WM_STATE"); 1407dff02feSmrg enqueue(atom_done, as); 1417dff02feSmrg} 1427dff02feSmrg 143a850946eSmrgint 144a850946eSmrgmain(int argc, char *argv[]) 145a850946eSmrg{ 146a850946eSmrg int i; 147a850946eSmrg char *displayname = NULL; 148a850946eSmrg Bool all_screens = False; 149a850946eSmrg Bool verbose = False; 1507dff02feSmrg xcb_connection_t *dpy; 1517dff02feSmrg const xcb_setup_t *setup; 1527dff02feSmrg int screen_number = 0; 153a850946eSmrg int maxcmdlen = 10000; 154a850946eSmrg 155a850946eSmrg ProgramName = argv[0]; 156a850946eSmrg 157a850946eSmrg for (i = 1; i < argc; i++) { 158a850946eSmrg char *arg = argv[i]; 159a850946eSmrg 160a850946eSmrg if (arg[0] == '-') { 161a850946eSmrg char *cp; 162a850946eSmrg 163a850946eSmrg switch (arg[1]) { 164a850946eSmrg case 'd': /* -display dpyname */ 165a850946eSmrg if (++i >= argc) usage (); 166a850946eSmrg displayname = argv[i]; 167a850946eSmrg continue; 168a850946eSmrg case 'm': /* -max maxcmdlen */ 169a850946eSmrg if (++i >= argc) usage (); 170a850946eSmrg maxcmdlen = atoi (argv[i]); 171a850946eSmrg continue; 1729511053fSmrg case 'v': /* -version */ 1739511053fSmrg printf("%s\n", PACKAGE_STRING); 1749511053fSmrg exit(0); 175a850946eSmrg } 176a850946eSmrg 177a850946eSmrg for (cp = &arg[1]; *cp; cp++) { 178a850946eSmrg switch (*cp) { 179a850946eSmrg case 'a': /* -all */ 180a850946eSmrg all_screens = True; 181a850946eSmrg continue; 182a850946eSmrg case 'l': /* -long */ 183a850946eSmrg verbose = True; 184a850946eSmrg continue; 185a850946eSmrg default: 186a850946eSmrg usage (); 187a850946eSmrg } 188a850946eSmrg } 189a850946eSmrg } else { 190a850946eSmrg usage (); 191a850946eSmrg } 192a850946eSmrg } 193a850946eSmrg 1947dff02feSmrg dpy = xcb_connect(displayname, &screen_number); 1957dff02feSmrg if (xcb_connection_has_error(dpy)) { 1969511053fSmrg const char *name = displayname; 1977dff02feSmrg if (!name) 1987dff02feSmrg name = getenv("DISPLAY"); 1997dff02feSmrg if (!name) 2007dff02feSmrg name = ""; 201a850946eSmrg fprintf (stderr, "%s: unable to open display \"%s\"\r\n", 2027dff02feSmrg ProgramName, name); 203a850946eSmrg exit (1); 204a850946eSmrg } 205a850946eSmrg 2067dff02feSmrg init_atoms(dpy); 2077dff02feSmrg 2087dff02feSmrg setup = xcb_get_setup(dpy); 209a850946eSmrg if (all_screens) { 2107dff02feSmrg xcb_screen_iterator_t screen; 2117dff02feSmrg 2127dff02feSmrg screen = xcb_setup_roots_iterator(setup); 2137dff02feSmrg do { 2147dff02feSmrg lookat(dpy, screen.data->root, verbose, maxcmdlen); 2157dff02feSmrg xcb_screen_next(&screen); 2167dff02feSmrg } while (screen.rem); 217a850946eSmrg } else { 2187dff02feSmrg xcb_screen_iterator_t screen; 2197dff02feSmrg 2207dff02feSmrg screen = xcb_setup_roots_iterator(setup); 2217dff02feSmrg for (i = 0; i < screen_number; i++) 2227dff02feSmrg xcb_screen_next(&screen); 2237dff02feSmrg 2247dff02feSmrg lookat (dpy, screen.data->root, verbose, maxcmdlen); 225a850946eSmrg } 226a850946eSmrg 2277dff02feSmrg run_queue(); 2287dff02feSmrg 2297dff02feSmrg xcb_disconnect(dpy); 230a850946eSmrg exit (0); 231a850946eSmrg} 232a850946eSmrg 2337dff02feSmrgtypedef struct { 2347dff02feSmrg xcb_connection_t *c; 2357dff02feSmrg xcb_get_property_cookie_t *prop_cookie; 2367dff02feSmrg xcb_query_tree_cookie_t *tree_cookie; 2377dff02feSmrg xcb_window_t *win; 2387dff02feSmrg xcb_window_t orig_win; 2397dff02feSmrg int list_length; 2407dff02feSmrg int verbose; 2417dff02feSmrg int maxcmdlen; 2427dff02feSmrg} child_wm_state; 2437dff02feSmrg 2447dff02feSmrgstatic void child_info(void *closure) 2457dff02feSmrg{ 2467dff02feSmrg child_wm_state *cs = closure; 2477dff02feSmrg xcb_window_t orig = cs->orig_win; 2487dff02feSmrg xcb_connection_t *c = cs->c; 2497dff02feSmrg int verbose = cs->verbose; 2507dff02feSmrg int maxcmdlen = cs->maxcmdlen; 2517dff02feSmrg int i, j; 2527dff02feSmrg 2537dff02feSmrg int child_count, num_rep; 2549511053fSmrg xcb_query_tree_reply_t **qt_reply; 2557dff02feSmrg 2567dff02feSmrg for (i = 0; i < cs->list_length; i++) { 2579511053fSmrg xcb_get_property_reply_t *gp_reply; 2589511053fSmrg gp_reply = xcb_get_property_reply(c, cs->prop_cookie[i], NULL); 2599511053fSmrg if (gp_reply) { 2609511053fSmrg if (gp_reply->type) { 2617dff02feSmrg /* Show information for this window */ 2627dff02feSmrg print_client_properties(c, cs->win[i], cs->verbose, cs->maxcmdlen); 2637dff02feSmrg 2649511053fSmrg free(gp_reply); 2657dff02feSmrg 2667dff02feSmrg /* drain stale replies */ 2677dff02feSmrg for (j = i+1; j < cs->list_length; j++) { 2689511053fSmrg gp_reply = xcb_get_property_reply(c, cs->prop_cookie[j], NULL); 2699511053fSmrg if (gp_reply) 2709511053fSmrg free(gp_reply); 2717dff02feSmrg } 2727dff02feSmrg for (j = 0; j < cs->list_length; j++) { 2737dff02feSmrg xcb_query_tree_reply_t *rep; 2747dff02feSmrg rep = xcb_query_tree_reply(c, cs->tree_cookie[j], NULL); 2757dff02feSmrg if (rep) 2767dff02feSmrg free(rep); 2777dff02feSmrg } 2787dff02feSmrg goto done; 2797dff02feSmrg } 2809511053fSmrg free(gp_reply); 2817dff02feSmrg } 2827dff02feSmrg } 2837dff02feSmrg 2847dff02feSmrg /* WM_STATE not found. Recurse into children: */ 2857dff02feSmrg num_rep = 0; 2869511053fSmrg qt_reply = malloc(sizeof(*qt_reply) * cs->list_length); 2879511053fSmrg if (!qt_reply) 2887dff02feSmrg goto done; /* TODO: print OOM message, drain reply queue */ 2897dff02feSmrg 2907dff02feSmrg for (i = 0; i < cs->list_length; i++) { 2919511053fSmrg qt_reply[num_rep] = xcb_query_tree_reply(c, cs->tree_cookie[i], NULL); 2929511053fSmrg if (qt_reply[num_rep]) 2937dff02feSmrg num_rep++; 2947dff02feSmrg } 2957dff02feSmrg 2967dff02feSmrg child_count = 0; 2977dff02feSmrg for (i = 0; i < num_rep; i++) 2989511053fSmrg child_count += qt_reply[i]->children_len; 2997dff02feSmrg 3007dff02feSmrg if (!child_count) { 3017dff02feSmrg /* No children have CS_STATE; try the parent window */ 3027dff02feSmrg print_client_properties(c, cs->orig_win, cs->verbose, cs->maxcmdlen); 3037dff02feSmrg goto reply_done; 3047dff02feSmrg } 3057dff02feSmrg 3067dff02feSmrg cs = malloc(sizeof(*cs) + child_count * (sizeof(*cs->prop_cookie) + sizeof(*cs->tree_cookie) + sizeof(*cs->win))); 3077dff02feSmrg if (!cs) 3087dff02feSmrg goto reply_done; /* TODO: print OOM message */ 3097dff02feSmrg 3107dff02feSmrg cs->c = c; 3117dff02feSmrg cs->verbose = verbose; 3127dff02feSmrg cs->maxcmdlen = maxcmdlen; 3137dff02feSmrg cs->orig_win = orig; 3147dff02feSmrg cs->prop_cookie = (void *)&cs[1]; 3157dff02feSmrg cs->tree_cookie = (void *)&cs->prop_cookie[child_count]; 3167dff02feSmrg cs->win = (void *)&cs->tree_cookie[child_count]; 3177dff02feSmrg cs->list_length = child_count; 3187dff02feSmrg 3197dff02feSmrg child_count = 0; 3207dff02feSmrg for (i = 0; i < num_rep; i++) { 3219511053fSmrg xcb_window_t *child = xcb_query_tree_children(qt_reply[i]); 3229511053fSmrg for (j = 0; j < qt_reply[i]->children_len; j++) { 3237dff02feSmrg cs->win[child_count] = child[j]; 3247dff02feSmrg cs->prop_cookie[child_count] = xcb_get_property(c, 0, child[j], 3257dff02feSmrg WM_STATE, XCB_GET_PROPERTY_TYPE_ANY, 3267dff02feSmrg 0, 0); 3277dff02feSmrg /* Just in case the property isn't there, get the tree too */ 3287dff02feSmrg cs->tree_cookie[child_count++] = xcb_query_tree(c, child[j]); 3297dff02feSmrg } 3307dff02feSmrg } 3317dff02feSmrg 3327dff02feSmrg enqueue(child_info, cs); 3337dff02feSmrg 3347dff02feSmrgreply_done: 3357dff02feSmrg for (i = 0; i < num_rep; i++) 3369511053fSmrg free(qt_reply[i]); 3379511053fSmrg free(qt_reply); 3387dff02feSmrg 3397dff02feSmrgdone: 3407dff02feSmrg free(closure); 3417dff02feSmrg} 3427dff02feSmrg 3437dff02feSmrgtypedef struct { 3447dff02feSmrg xcb_connection_t *c; 3457dff02feSmrg xcb_query_tree_cookie_t cookie; 3467dff02feSmrg int verbose; 3477dff02feSmrg int maxcmdlen; 3487dff02feSmrg} root_list_state; 3497dff02feSmrg 3507dff02feSmrgstatic void root_list(void *closure) 3517dff02feSmrg{ 3527dff02feSmrg int i; 3537dff02feSmrg xcb_window_t *child; 3547dff02feSmrg xcb_query_tree_reply_t *reply; 3557dff02feSmrg root_list_state *rl = closure; 3567dff02feSmrg 3577dff02feSmrg reply = xcb_query_tree_reply(rl->c, rl->cookie, NULL); 3587dff02feSmrg if (!reply) 3597dff02feSmrg goto done; 3607dff02feSmrg 3617dff02feSmrg child = xcb_query_tree_children(reply); 3627dff02feSmrg for (i = 0; i < reply->children_len; i++) { 3637dff02feSmrg /* Get information about each child */ 3647dff02feSmrg child_wm_state *cs = malloc(sizeof(*cs) + sizeof(*cs->prop_cookie) + sizeof(*cs->tree_cookie) + sizeof(*cs->win)); 3657dff02feSmrg if (!cs) 3667dff02feSmrg goto done; /* TODO: print OOM message */ 3677dff02feSmrg cs->c = rl->c; 3687dff02feSmrg cs->verbose = rl->verbose; 3697dff02feSmrg cs->maxcmdlen = rl->maxcmdlen; 3707dff02feSmrg cs->prop_cookie = (void *)&cs[1]; 3717dff02feSmrg cs->tree_cookie = (void *)&cs->prop_cookie[1]; 3727dff02feSmrg cs->win = (void *)&cs->tree_cookie[1]; 3737dff02feSmrg 3747dff02feSmrg cs->orig_win = child[i]; 3757dff02feSmrg cs->win[0] = child[i]; 3767dff02feSmrg 3777dff02feSmrg cs->prop_cookie[0] = xcb_get_property(rl->c, 0, child[i], 3787dff02feSmrg WM_STATE, XCB_GET_PROPERTY_TYPE_ANY, 3797dff02feSmrg 0, 0); 3807dff02feSmrg /* Just in case the property isn't there, get the tree too */ 3817dff02feSmrg cs->tree_cookie[0] = xcb_query_tree(rl->c, child[i]); 3827dff02feSmrg 3837dff02feSmrg cs->list_length = 1; 3847dff02feSmrg enqueue(child_info, cs); 3857dff02feSmrg } 3867dff02feSmrg free(reply); 3877dff02feSmrg 3887dff02feSmrgdone: 3897dff02feSmrg free(rl); 3907dff02feSmrg} 3917dff02feSmrg 392a850946eSmrgstatic void 3937dff02feSmrglookat(xcb_connection_t *dpy, xcb_window_t root, int verbose, int maxcmdlen) 394a850946eSmrg{ 3957dff02feSmrg root_list_state *rl = malloc(sizeof(*rl)); 396a850946eSmrg 3977dff02feSmrg if (!rl) 3987dff02feSmrg return; /* TODO: OOM message */ 399a850946eSmrg 400a850946eSmrg /* 4017dff02feSmrg * get the list of windows 402a850946eSmrg */ 403a850946eSmrg 4047dff02feSmrg rl->c = dpy; 4057dff02feSmrg rl->cookie = xcb_query_tree(dpy, root); 4067dff02feSmrg rl->verbose = verbose; 4077dff02feSmrg rl->maxcmdlen = maxcmdlen; 4087dff02feSmrg enqueue(root_list, rl); 409a850946eSmrg} 410a850946eSmrg 4119511053fSmrgstatic const char *Nil = "(nil)"; 412a850946eSmrg 4137dff02feSmrgtypedef struct { 4147dff02feSmrg xcb_connection_t *c; 4157dff02feSmrg xcb_get_property_cookie_t client_machine; 4167dff02feSmrg xcb_get_property_cookie_t command; 4177dff02feSmrg xcb_get_property_cookie_t name; 4187dff02feSmrg xcb_get_property_cookie_t icon_name; 4197dff02feSmrg xcb_get_property_cookie_t wm_class; 4207dff02feSmrg xcb_window_t w; 4217dff02feSmrg int verbose; 4227dff02feSmrg int maxcmdlen; 4237dff02feSmrg} client_state; 4247dff02feSmrg 425a850946eSmrgstatic void 4267dff02feSmrgshow_client_properties(void *closure) 427a850946eSmrg{ 4287dff02feSmrg client_state *cs = closure; 4297dff02feSmrg xcb_get_property_reply_t *client_machine; 4307dff02feSmrg xcb_get_property_reply_t *command; 4317dff02feSmrg xcb_get_property_reply_t *name; 4327dff02feSmrg xcb_get_property_reply_t *icon_name; 4337dff02feSmrg xcb_get_property_reply_t *wm_class; 4347dff02feSmrg char *argv; 4357dff02feSmrg int charsleft = cs->maxcmdlen; 4367dff02feSmrg int i; 437a850946eSmrg 438a850946eSmrg /* 439a850946eSmrg * get the WM_MACHINE and WM_COMMAND list of strings 440a850946eSmrg */ 4417dff02feSmrg client_machine = xcb_get_property_reply(cs->c, cs->client_machine, NULL); 4427dff02feSmrg command = xcb_get_property_reply(cs->c, cs->command, NULL); 4437dff02feSmrg if (cs->verbose) { 4447dff02feSmrg name = xcb_get_property_reply(cs->c, cs->name, NULL); 4457dff02feSmrg icon_name = xcb_get_property_reply(cs->c, cs->icon_name, NULL); 4467dff02feSmrg wm_class = xcb_get_property_reply(cs->c, cs->wm_class, NULL); 447a850946eSmrg } 448a850946eSmrg 4497dff02feSmrg if (!command || !command->type) 4507dff02feSmrg goto done; 451a850946eSmrg 452a850946eSmrg /* 453a850946eSmrg * do header information 454a850946eSmrg */ 4557dff02feSmrg if (cs->verbose) { 4567dff02feSmrg printf ("Window 0x%" PRIx32 ":\n", cs->w); 4577dff02feSmrg print_text_field (cs->c, " Machine: ", client_machine); 4587dff02feSmrg if (name && name->type) 4597dff02feSmrg print_text_field (cs->c, " Name: ", name); 460a850946eSmrg } else { 4617dff02feSmrg print_text_field (cs->c, NULL, client_machine); 462a850946eSmrg putchar (' '); 463a850946eSmrg putchar (' '); 464a850946eSmrg } 465a850946eSmrg 4667dff02feSmrg 4677dff02feSmrg if (cs->verbose) 4687dff02feSmrg if (icon_name && icon_name->type) 4697dff02feSmrg print_text_field (cs->c, " Icon Name: ", icon_name); 470a850946eSmrg 471a850946eSmrg 472a850946eSmrg /* 473a850946eSmrg * do the command 474a850946eSmrg */ 4757dff02feSmrg if (cs->verbose) 476a850946eSmrg printf (" Command: "); 4777dff02feSmrg argv = xcb_get_property_value(command); 4787dff02feSmrg for (i = 0; i < command->value_len && charsleft > 0; ) { 4797dff02feSmrg charsleft -= print_quoted_word (argv + i, charsleft); 4807dff02feSmrg i += strnlen(argv + i, command->value_len - i) + 1; 4817dff02feSmrg if (i < command->value_len && charsleft > 0) { 4827dff02feSmrg putchar (' '); 4837dff02feSmrg charsleft--; 484a850946eSmrg } 485a850946eSmrg } 486a850946eSmrg putchar ('\n'); 487a850946eSmrg 488a850946eSmrg 489a850946eSmrg /* 490a850946eSmrg * do trailer information 491a850946eSmrg */ 4927dff02feSmrg if (cs->verbose) { 4937dff02feSmrg if (wm_class && wm_class->type) { 4949511053fSmrg const char *res_name, *res_class; 4957dff02feSmrg int name_len, class_len; 4967dff02feSmrg res_name = xcb_get_property_value(wm_class); 4977dff02feSmrg name_len = strnlen(res_name, wm_class->value_len) + 1; 4987dff02feSmrg class_len = wm_class->value_len - name_len; 4997dff02feSmrg if (class_len > 0) { 5007dff02feSmrg res_class = res_name + name_len; 5017dff02feSmrg } else { 5027dff02feSmrg res_class = Nil; 5037dff02feSmrg class_len = strlen(res_class); 5047dff02feSmrg } 5057dff02feSmrg 5067dff02feSmrg printf (" Instance/Class: %.*s/%.*s", 5077dff02feSmrg name_len, res_name, 5087dff02feSmrg class_len, res_class); 509a850946eSmrg putchar ('\n'); 510a850946eSmrg } 511a850946eSmrg } 5127dff02feSmrg 5137dff02feSmrgdone: 5147dff02feSmrg if (client_machine) 5157dff02feSmrg free(client_machine); 5167dff02feSmrg if (command) 5177dff02feSmrg free(command); 5187dff02feSmrg if (cs->verbose) { 5197dff02feSmrg if (name) 5207dff02feSmrg free(name); 5217dff02feSmrg if (icon_name) 5227dff02feSmrg free(icon_name); 5237dff02feSmrg if (wm_class) 5247dff02feSmrg free(wm_class); 5257dff02feSmrg } 5267dff02feSmrg free(cs); 527a850946eSmrg} 528a850946eSmrg 529a850946eSmrgstatic void 5307dff02feSmrgprint_client_properties(xcb_connection_t *dpy, xcb_window_t w, int verbose, int maxcmdlen) 531a850946eSmrg{ 5327dff02feSmrg client_state *cs = malloc(sizeof(*cs)); 5337dff02feSmrg if (!cs) 5347dff02feSmrg return; /* TODO: print OOM message */ 5357dff02feSmrg 5367dff02feSmrg cs->c = dpy; 5377dff02feSmrg cs->w = w; 5387dff02feSmrg cs->verbose = verbose; 5397dff02feSmrg cs->maxcmdlen = maxcmdlen; 5407dff02feSmrg 5417dff02feSmrg /* 5427dff02feSmrg * get the WM_CLIENT_MACHINE and WM_COMMAND list of strings 5437dff02feSmrg */ 5447dff02feSmrg cs->client_machine = xcb_get_property(dpy, 0, w, 5458e46b049Smrg XCB_ATOM_WM_CLIENT_MACHINE, XCB_GET_PROPERTY_TYPE_ANY, 5467dff02feSmrg 0, 1000000L); 5477dff02feSmrg cs->command = xcb_get_property(dpy, 0, w, 5488e46b049Smrg XCB_ATOM_WM_COMMAND, XCB_GET_PROPERTY_TYPE_ANY, 5497dff02feSmrg 0, 1000000L); 5507dff02feSmrg 5517dff02feSmrg if (verbose) { 5527dff02feSmrg cs->name = xcb_get_property(dpy, 0, w, 5538e46b049Smrg XCB_ATOM_WM_NAME, XCB_GET_PROPERTY_TYPE_ANY, 5547dff02feSmrg 0, 1000000L); 5557dff02feSmrg cs->icon_name = xcb_get_property(dpy, 0, w, 5568e46b049Smrg XCB_ATOM_WM_ICON_NAME, XCB_GET_PROPERTY_TYPE_ANY, 5577dff02feSmrg 0, 1000000L); 5587dff02feSmrg cs->wm_class = xcb_get_property(dpy, 0, w, 5598e46b049Smrg XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 5607dff02feSmrg 0, 1000000L); 5617dff02feSmrg } 5627dff02feSmrg 5637dff02feSmrg enqueue(show_client_properties, cs); 5647dff02feSmrg} 5657dff02feSmrg 5667dff02feSmrgstatic void 5679511053fSmrgprint_text_field(xcb_connection_t *dpy, const char *s, xcb_get_property_reply_t *tp) 5687dff02feSmrg{ 5697dff02feSmrg if (tp->type == XCB_NONE || tp->format == 0) { /* Or XCB_ATOM_NONE after libxcb 1.5 */ 570a850946eSmrg printf ("''"); 571a850946eSmrg return; 572a850946eSmrg } 573a850946eSmrg 574a850946eSmrg if (s) printf ("%s", s); 5758e46b049Smrg if (tp->type == XCB_ATOM_STRING && tp->format == 8) { 5767dff02feSmrg printf ("%.*s", (int)tp->value_len, (char *)xcb_get_property_value(tp)); 577a850946eSmrg } else { 5787dff02feSmrg unknown (dpy, tp->type, tp->format); 579a850946eSmrg } 580a850946eSmrg if (s) putchar ('\n'); 581a850946eSmrg} 582a850946eSmrg 583a850946eSmrg/* returns the number of characters printed */ 584a850946eSmrgstatic int 585a850946eSmrgprint_quoted_word(char *s, 586a850946eSmrg int maxlen) /* max number of chars we can print */ 587a850946eSmrg{ 588a850946eSmrg register char *cp; 589a850946eSmrg Bool need_quote = False, in_quote = False; 590a850946eSmrg char quote_char = '\'', other_quote = '"'; 591a850946eSmrg int charsprinted = 0; 592a850946eSmrg 593a850946eSmrg /* 594a850946eSmrg * walk down seeing whether or not we need to quote 595a850946eSmrg */ 596a850946eSmrg for (cp = s; *cp; cp++) { 597a850946eSmrg 598a850946eSmrg if (! ((isascii(*cp) && isalnum(*cp)) || 599a850946eSmrg (*cp == '-' || *cp == '_' || *cp == '.' || *cp == '+' || 600a850946eSmrg *cp == '/' || *cp == '=' || *cp == ':' || *cp == ','))) { 601a850946eSmrg need_quote = True; 602a850946eSmrg break; 603a850946eSmrg } 604a850946eSmrg } 605a850946eSmrg 606a850946eSmrg /* 607a850946eSmrg * write out the string: if we hit a quote, then close any previous quote, 608a850946eSmrg * emit the other quote, swap quotes and continue on. 609a850946eSmrg */ 610a850946eSmrg in_quote = need_quote; 611a850946eSmrg if (need_quote) { 612a850946eSmrg putchar (quote_char); 613a850946eSmrg charsprinted++; maxlen--; 614a850946eSmrg } 615a850946eSmrg for (cp = s; *cp && maxlen>0; cp++) { 616a850946eSmrg if (*cp == quote_char) { 617a850946eSmrg if (in_quote) { 618a850946eSmrg putchar (quote_char); 619a850946eSmrg charsprinted++; maxlen--; 620a850946eSmrg } 621a850946eSmrg putchar (other_quote); 622a850946eSmrg charsprinted++; maxlen--; 623a850946eSmrg { 624a850946eSmrg char tmp = other_quote; 625a850946eSmrg other_quote = quote_char; quote_char = tmp; 626a850946eSmrg } 627a850946eSmrg in_quote = True; 628a850946eSmrg } 629a850946eSmrg putchar (*cp); 630a850946eSmrg charsprinted++; maxlen--; 631a850946eSmrg } 632a850946eSmrg /* close the quote if we opened one and if we printed the whole string */ 633a850946eSmrg if (in_quote && maxlen>0) { 634a850946eSmrg putchar (quote_char); 635a850946eSmrg charsprinted++; maxlen--; 636a850946eSmrg } 637a850946eSmrg 638a850946eSmrg return charsprinted; 639a850946eSmrg} 640a850946eSmrg 641a850946eSmrgstatic void 6427dff02feSmrgunknown(xcb_connection_t *dpy, xcb_atom_t actual_type, int actual_format) 643a850946eSmrg{ 644a850946eSmrg printf ("<unknown type "); 6457dff02feSmrg if (actual_type == XCB_NONE) 6467dff02feSmrg printf ("None"); 6477dff02feSmrg else { 6487dff02feSmrg /* This should happen so rarely as to make no odds. Eat a round-trip: */ 6497dff02feSmrg xcb_get_atom_name_reply_t *atom = 6507dff02feSmrg xcb_get_atom_name_reply(dpy, 6517dff02feSmrg xcb_get_atom_name(dpy, actual_type), NULL); 6527dff02feSmrg if (atom) { 6537dff02feSmrg printf("%.*s", xcb_get_atom_name_name_length(atom), 6547dff02feSmrg xcb_get_atom_name_name(atom)); 6557dff02feSmrg free(atom); 6567dff02feSmrg } else 6577dff02feSmrg fputs (Nil, stdout); 658a850946eSmrg } 6597dff02feSmrg printf (" (%" PRIu32 ") or format %d>", actual_type, actual_format); 660a850946eSmrg} 661