1 /**
2  * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <X11/Xutil.h>
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #ifdef ENABLE_NLS
32 # define _(string) gettext (string)
33 # include "gettext.h"
34 #else
35 # define _(string) string
36 #endif
37 #include <X11/extensions/XRes.h>
38 #include "xresview.h"
39 
40 static Atom wm_state;
41 static Atom res_pixmap;
42 static Atom res_window;
43 static Atom res_gc;
44 static Atom res_font;
45 static Atom res_glyphset;
46 static Atom res_picture;
47 static Atom res_cursor;
48 static Atom res_colormap_entry;
49 static Atom res_passive_grab;
50 static int atoms_loaded = 0;
51 
52 /**
53  * Cache every atom we need.  This minimizes round trips to the server.
54  * The number of atoms and their position is hardcoded, but it's small.
55  * Making this look pretty I think would be too annoying to be worth it.
56  */
load_atoms(Display * dpy)57 static void load_atoms( Display *dpy )
58 {
59     static char *atom_names[] = {
60         "WM_STATE",
61         "PIXMAP",
62         "WINDOW",
63         "GC",
64         "FONT",
65         "PICTURE",
66         "CURSOR",
67         "GLYPHSET",
68         "COLORMAP_ENTRY",
69         "PASSIVE_GRAB"
70     };
71     Atom atoms_return[ 10 ];
72 
73     if( atoms_loaded ) return;
74 
75     XInternAtoms( dpy, atom_names, 10, False, atoms_return );
76     wm_state = atoms_return[ 0 ];
77     res_pixmap = atoms_return[ 1 ];
78     res_window = atoms_return[ 2 ];
79     res_gc = atoms_return[ 3 ];
80     res_font = atoms_return[ 4 ];
81     res_picture = atoms_return[ 5 ];
82     res_cursor = atoms_return[ 6 ];
83     res_glyphset = atoms_return[ 7 ];
84     res_colormap_entry = atoms_return[ 8 ];
85     res_passive_grab = atoms_return[ 9 ];
86     atoms_loaded = 1;
87 }
88 
89 struct xresview_s
90 {
91     GtkWidget *scrolled;
92     GtkWidget *main;
93     GtkWidget *name;
94     GtkWidget *pixmap_bytes;
95     GtkWidget *pixmaps;
96     GtkWidget *windows;
97     GtkWidget *glyphsets;
98     GtkWidget *gcs;
99     GtkWidget *fonts;
100     GtkWidget *pictures;
101     GtkWidget *pgrabs;
102     GtkWidget *colormaps;
103     GtkWidget *cursors;
104     XResClient *clients;
105     int numclients;
106 };
107 
xresview_new(void)108 xresview_t *xresview_new( void )
109 {
110     xresview_t *rv = malloc( sizeof( xresview_t ) );
111     GtkWidget *vbox;
112     GtkWidget *table;
113     GtkWidget *label;
114     GtkWidget *align;
115     int row = 0;
116 
117     rv->clients = 0;
118 
119     vbox = gtk_vbox_new( FALSE, 2 );
120     align = gtk_alignment_new( 0.5, 0.0, 0.95, 0.0 );
121     table = gtk_table_new( 1, 2, FALSE );
122     gtk_container_add( GTK_CONTAINER( align ), table );
123     gtk_box_pack_start( GTK_BOX( vbox ), align, TRUE, TRUE, 2 );
124 
125 /*
126     label = gtk_label_new( "Name:" );
127     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
128     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
129     rv->name = gtk_entry_new();
130     gtk_entry_set_editable( GTK_ENTRY( rv->name ), FALSE );
131     gtk_table_attach_defaults( GTK_TABLE( table ), rv->name, 1, 2, row, row + 1 );
132     row++;
133 */
134 
135     label = gtk_label_new( _("Pixmaps:") );
136     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
137     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
138     rv->pixmaps = gtk_entry_new();
139     gtk_entry_set_editable( GTK_ENTRY( rv->pixmaps ), FALSE );
140     gtk_table_attach_defaults( GTK_TABLE( table ), rv->pixmaps, 1, 2, row, row + 1 );
141     row++;
142 
143     label = gtk_label_new( _("Pixmap Bytes:") );
144     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
145     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
146     rv->pixmap_bytes = gtk_entry_new();
147     gtk_entry_set_editable( GTK_ENTRY( rv->pixmap_bytes ), FALSE );
148     gtk_table_attach_defaults( GTK_TABLE( table ), rv->pixmap_bytes, 1, 2, row, row + 1 );
149     row++;
150 
151     label = gtk_label_new( _("Windows:") );
152     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
153     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
154     rv->windows = gtk_entry_new();
155     gtk_entry_set_editable( GTK_ENTRY( rv->windows ), FALSE );
156     gtk_table_attach_defaults( GTK_TABLE( table ), rv->windows, 1, 2, row, row + 1 );
157     row++;
158 
159     label = gtk_label_new( _("Cursors:") );
160     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
161     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
162     rv->cursors = gtk_entry_new();
163     gtk_entry_set_editable( GTK_ENTRY( rv->cursors ), FALSE );
164     gtk_table_attach_defaults( GTK_TABLE( table ), rv->cursors, 1, 2, row, row + 1 );
165     row++;
166 
167     label = gtk_label_new( _("Graphics Contexts:") );
168     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
169     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
170     rv->gcs = gtk_entry_new();
171     gtk_entry_set_editable( GTK_ENTRY( rv->gcs ), FALSE );
172     gtk_table_attach_defaults( GTK_TABLE( table ), rv->gcs, 1, 2, row, row + 1 );
173     row++;
174 
175     label = gtk_label_new( _("Fonts:") );
176     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
177     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
178     rv->fonts = gtk_entry_new();
179     gtk_entry_set_editable( GTK_ENTRY( rv->fonts ), FALSE );
180     gtk_table_attach_defaults( GTK_TABLE( table ), rv->fonts, 1, 2, row, row + 1 );
181     row++;
182 
183     label = gtk_label_new( _("Pictures:") );
184     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
185     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
186     rv->pictures = gtk_entry_new();
187     gtk_entry_set_editable( GTK_ENTRY( rv->pictures ), FALSE );
188     gtk_table_attach_defaults( GTK_TABLE( table ), rv->pictures, 1, 2, row, row + 1 );
189     row++;
190 
191     label = gtk_label_new( _("Glyphsets:") );
192     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
193     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
194     rv->glyphsets = gtk_entry_new();
195     gtk_entry_set_editable( GTK_ENTRY( rv->glyphsets ), FALSE );
196     gtk_table_attach_defaults( GTK_TABLE( table ), rv->glyphsets, 1, 2, row, row + 1 );
197     row++;
198 
199     label = gtk_label_new( _("Colormap Entries:") );
200     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
201     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
202     rv->colormaps = gtk_entry_new();
203     gtk_entry_set_editable( GTK_ENTRY( rv->colormaps ), FALSE );
204     gtk_table_attach_defaults( GTK_TABLE( table ), rv->colormaps, 1, 2, row, row + 1 );
205     row++;
206 
207     label = gtk_label_new( _("Passive Grabs:") );
208     gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
209     gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row + 1, GTK_SHRINK, GTK_SHRINK, 2, 2 );
210     rv->pgrabs = gtk_entry_new();
211     gtk_entry_set_editable( GTK_ENTRY( rv->pgrabs ), FALSE );
212     gtk_table_attach_defaults( GTK_TABLE( table ), rv->pgrabs, 1, 2, row, row + 1 );
213     row++;
214 
215     rv->main = vbox;
216     return rv;
217 }
218 
xresview_delete(xresview_t * rv)219 void xresview_delete( xresview_t *rv )
220 {
221     free( rv );
222 }
223 
xresview_clear(xresview_t * rv,Display * dpy,Window root)224 void xresview_clear( xresview_t *rv, Display *dpy, Window root )
225 {
226     gtk_entry_set_text( GTK_ENTRY( rv->pixmaps ), "" );
227     gtk_entry_set_text( GTK_ENTRY( rv->pixmap_bytes ), "" );
228     gtk_entry_set_text( GTK_ENTRY( rv->windows ), "" );
229     gtk_entry_set_text( GTK_ENTRY( rv->gcs ), "" );
230     gtk_entry_set_text( GTK_ENTRY( rv->fonts ), "" );
231     gtk_entry_set_text( GTK_ENTRY( rv->pictures ), "" );
232     gtk_entry_set_text( GTK_ENTRY( rv->glyphsets ), "" );
233     gtk_entry_set_text( GTK_ENTRY( rv->cursors ), "" );
234     gtk_entry_set_text( GTK_ENTRY( rv->colormaps ), "" );
235     gtk_entry_set_text( GTK_ENTRY( rv->pgrabs ), "" );
236     if( rv->clients ) {
237         XFree( rv->clients );
238     }
239     XResQueryClients( dpy, &rv->numclients, &rv->clients );
240 }
241 
is_application_window(Display * dpy,Window win)242 static int is_application_window( Display *dpy, Window win )
243 {
244     Atom type_return;
245     int format_return;
246     unsigned long bytes_after_return;
247     unsigned long nitems_return;
248     unsigned char *prop_return = 0;
249 
250     if( XGetWindowProperty( dpy, win, wm_state, 0,
251                             4, False, AnyPropertyType,
252                             &type_return, &format_return,
253                             &nitems_return, &bytes_after_return,
254                             &prop_return ) != Success ) {
255         return 0;
256     }
257     if( nitems_return ) {
258         XFree( prop_return );
259     }
260     if( !type_return ) {
261         return 0;
262     }
263 
264     return 1;
265 }
266 
xresview_load(xresview_t * rv,Display * dpy,Window win,Window root)267 void xresview_load( xresview_t *rv, Display *dpy, Window win, Window root )
268 {
269     Atom type_return;
270     int format_return;
271     unsigned long bytes_after_return;
272     unsigned long nitems_return;
273     unsigned char *prop_return = 0;
274     int i;
275 
276     load_atoms( dpy );
277 
278     if( !is_application_window( dpy, win ) ) {
279         return;
280     }
281 
282     for( i = 0; i < rv->numclients; i++ ) {
283         unsigned int match_xid;
284 
285         match_xid = (rv->clients[ i ].resource_base & ~rv->clients[ i ].resource_mask);
286         if( (win & ~rv->clients[ i ].resource_mask) == match_xid ) {
287             XResType *types;
288             char text[ 256 ];
289             unsigned long bytes;
290             int numtypes;
291             int j;
292 
293             XResQueryClientPixmapBytes( dpy, win, &bytes );
294             sprintf( text, "%ld", bytes );
295             gtk_entry_set_text( GTK_ENTRY( rv->pixmap_bytes ), text );
296 
297             XResQueryClientResources( dpy, win, &numtypes, &types );
298             for( j = 0; j < numtypes; j++ ) {
299                 if( types[ j ].resource_type == res_pixmap ) {
300                     sprintf( text, "%u", types[ j ].count );
301                     gtk_entry_set_text( GTK_ENTRY( rv->pixmaps ), text );
302                 } else if( types[ j ].resource_type == res_window ) {
303                     sprintf( text, "%u", types[ j ].count );
304                     gtk_entry_set_text( GTK_ENTRY( rv->windows ), text );
305                 } else if( types[ j ].resource_type == res_gc ) {
306                     sprintf( text, "%u", types[ j ].count );
307                     gtk_entry_set_text( GTK_ENTRY( rv->gcs ), text );
308                 } else if( types[ j ].resource_type == res_font ) {
309                     sprintf( text, "%u", types[ j ].count );
310                     gtk_entry_set_text( GTK_ENTRY( rv->fonts ), text );
311                 } else if( types[ j ].resource_type == res_picture ) {
312                     sprintf( text, "%u", types[ j ].count );
313                     gtk_entry_set_text( GTK_ENTRY( rv->pictures ), text );
314                 } else if( types[ j ].resource_type == res_glyphset ) {
315                     sprintf( text, "%u", types[ j ].count );
316                     gtk_entry_set_text( GTK_ENTRY( rv->glyphsets ), text );
317                 } else if( types[ j ].resource_type == res_colormap_entry ) {
318                     sprintf( text, "%u", types[ j ].count );
319                     gtk_entry_set_text( GTK_ENTRY( rv->colormaps ), text );
320                 } else if( types[ j ].resource_type == res_passive_grab ) {
321                     sprintf( text, "%u", types[ j ].count );
322                     gtk_entry_set_text( GTK_ENTRY( rv->pgrabs ), text );
323                 } else if( types[ j ].resource_type == res_cursor ) {
324                     sprintf( text, "%u", types[ j ].count );
325                     gtk_entry_set_text( GTK_ENTRY( rv->cursors ), text );
326                 }
327             }
328             if( numtypes ) {
329                 XFree( types );
330             }
331 
332             return;
333         }
334     }
335 }
336 
xresview_get_widget(xresview_t * rv)337 GtkWidget *xresview_get_widget( xresview_t *rv )
338 {
339     return rv->main;
340 }
341 
342