1 /* A program to pick a color by clicking the mouse.
2 *
3 * RCS:
4 * $Revision$
5 * $Date$
6 *
7 * Description:
8 *
9 * When this program is run, the mouse pointer is grabbed and changed to
10 * a cross hair and when the mouse is clicked, the color of the clicked
11 * pixel is written to stdout in hex prefixed with #
12 *
13 * This program can be useful when you see a color and want to use the
14 * color in xterm or your window manager's border but no clue what the
15 * name of the color is. It's silly to use a image processing software
16 * to find it out.
17 *
18 * Example:
19 * cpick
20 * #ffffff
21 * xterm -bg `cpick` -fg `cpick` (silly but esoteric!)
22 *
23 * Development History:
24 * who when why
25 * ma_muquit@fccc.edu march-16-19997 first cut
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <math.h>
35 #include <signal.h>
36 #include <time.h>
37
38 #include <X11/Xos.h>
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/Xresource.h>
42 #include <X11/Xproto.h>
43 #include <X11/Xatom.h>
44 #include <X11/cursorfont.h>
45 #include <X11/keysym.h>
46
47 #ifndef True
48 #define True 1
49 #endif
50
51 #ifndef False
52 #define False 0
53 #endif
54
55 /* private function prototypes */
56 static Window selectWindow (Display *,int *x,int *y);
57
58 static Window findSubWindow(Display *display,Window top_winodw,
59 Window window_to_check,int *x,int *y);
60
61 static int getWindowColor(Display *display,XColor *color);
62 static int MXError(Display *display,XErrorEvent *error);
63
main(int argc,char ** argv)64 int main(int argc,char **argv)
65 {
66 Display
67 *display;
68
69 int
70 status;
71
72 XColor
73 color;
74
75 Colormap
76 cmap;
77
78 int
79 i,
80 r,
81 g,
82 b;
83
84 for (i=1; i < argc; i++)
85 {
86 if (strncmp(argv[i],"-h",2) == 0)
87 {
88 (void) fprintf (stderr,"grabc 1.1 by Muhammad A Muquit\n");
89 exit(1);
90 }
91 }
92 display=XOpenDisplay((char *) NULL);
93 cmap=DefaultColormap(display,DefaultScreen(display));
94
95 XSetErrorHandler(MXError);
96
97 if (display == (Display *) NULL)
98 {
99 (void) fprintf (stderr,"Failed to open local DISPLAY!'n");
100 exit(1);
101 }
102
103 status=getWindowColor(display,&color);
104 if (status == True)
105 {
106 XQueryColor(display,cmap,&color);
107 r=(color.red >> 8);
108 g=(color.green >> 8);
109 b=(color.blue >> 8);
110 (void) fprintf (stdout,"#%02x%02x%02x\n",r,g,b);
111 (void) fflush(stdout);
112 /*
113 ** write the values in decimal on stderr
114 */
115 (void) fprintf(stderr,"%d,%d,%d\n",r,g,b);
116 }
117 else
118 {
119 (void) fprintf (stderr,"Failed to grab color!\n");
120 }
121 return (0);
122 }
123
124 /*
125 ** function to select a window
126 ** output parameters: x,y (coordinate of the point of click)
127 ** reutrns Window
128 ** exits if mouse can not be grabbed
129 */
selectWindow(Display * display,int * x,int * y)130 static Window selectWindow(Display *display,int *x,int *y)
131 {
132 Cursor
133 target_cursor;
134
135 static Cursor
136 cross_cursor=(Cursor) NULL;
137 int
138 status;
139
140 Window
141 target_window,
142 root_window;
143
144 XEvent
145 event;
146
147 target_window=(Window) NULL;
148
149 if (cross_cursor == (Cursor) NULL)
150 {
151 cross_cursor=XCreateFontCursor(display,XC_tcross);
152 if (cross_cursor == (Cursor) NULL)
153 {
154 (void) fprintf (stderr,"Failed to create Cross Cursor!\n");
155 return ((Window) NULL);
156 }
157 }
158 target_cursor=cross_cursor;
159 root_window=XRootWindow(display,XDefaultScreen(display));
160
161 status=XGrabPointer(display,root_window,False,
162 (unsigned int) ButtonPressMask,GrabModeSync,
163 GrabModeAsync,root_window,target_cursor,CurrentTime);
164
165 if (status == GrabSuccess)
166 {
167 XAllowEvents(display,SyncPointer,CurrentTime);
168 XWindowEvent(display,root_window,ButtonPressMask,&event);
169
170 if (event.type == ButtonPress)
171 {
172 target_window=findSubWindow(display,root_window,
173 event.xbutton.subwindow,
174 &event.xbutton.x,
175 &event.xbutton.y );
176
177 if (target_window == (Window) NULL)
178 {
179 (void) fprintf (stderr,
180 "Failed to get target window, getting root window!\n");
181 target_window=root_window;
182 }
183 XUngrabPointer(display,CurrentTime);
184 }
185 }
186 else
187 {
188 (void) fprintf (stderr,"Failed to grab mouse!\n");
189 exit(1);
190 }
191
192 /* free things we do not need, always a good practice */
193 XFreeCursor(display,cross_cursor);
194
195 (*x)=event.xbutton.x;
196 (*y)=event.xbutton.y;
197
198 return (target_window);
199 }
200
201 /* find a window */
findSubWindow(Display * display,Window top_window,Window window_to_check,int * x,int * y)202 static Window findSubWindow(Display *display,Window top_window,
203 Window window_to_check,int *x,int *y)
204 {
205 int
206 newx,
207 newy;
208
209 Window
210 window;
211
212 if (top_window == (Window) NULL)
213 return ((Window) NULL);
214
215 if (window_to_check == (Window) NULL)
216 return ((Window) NULL);
217
218 /* initialize automatics */
219 window=window_to_check;
220
221 while ((XTranslateCoordinates(display,top_window,window_to_check,
222 *x,*y,&newx,&newy,&window) != 0) &&
223 (window != (Window) NULL))
224 {
225 if (window != (Window) NULL)
226 {
227 top_window=window_to_check;
228 window_to_check=window;
229 (*x)=newx;
230 (*y)=newy;
231 }
232 }
233
234 if (window == (Window) NULL)
235 window=window_to_check;
236
237
238 (*x)=newx;
239 (*y)=newy;
240
241 return (window);
242 }
243
244 /*
245 * get the color of the pixel of the point of mouse click
246 * output paramter: XColor *color
247 *
248 * returns True if succeeds
249 * False if fails
250 */
251
getWindowColor(Display * display,XColor * color)252 static int getWindowColor(Display *display,XColor *color)
253 {
254 Window
255 root_window,
256 target_window;
257
258 XImage
259 *ximage;
260
261 int
262 x,
263 y;
264
265 Status
266 status;
267
268 root_window=XRootWindow(display,XDefaultScreen(display));
269 target_window=selectWindow(display,&x,&y);
270
271 if (target_window == (Window) NULL)
272 return (False);
273
274 ximage=XGetImage(display,target_window,x,y,1,1,AllPlanes,ZPixmap);
275 if (ximage == (XImage *) NULL)
276 return (False);
277
278 color->pixel=XGetPixel(ximage,0,0);
279 XDestroyImage(ximage);
280
281 return (True);
282 }
283
284 /* forgiving X error handler */
285
MXError(Display * display,XErrorEvent * error)286 static int MXError (Display *display, XErrorEvent *error)
287 {
288 int
289 xerrcode;
290
291 xerrcode = error->error_code;
292
293 if (xerrcode == BadAlloc ||
294 (xerrcode == BadAccess && error->request_code==88))
295 {
296 return (False);
297 }
298 else
299 {
300 switch (error->request_code)
301 {
302 case X_GetGeometry:
303 {
304 if (error->error_code == BadDrawable)
305 return (False);
306 break;
307 }
308
309 case X_GetWindowAttributes:
310 case X_QueryTree:
311 {
312 if (error->error_code == BadWindow)
313 return (False);
314 break;
315 }
316
317 case X_QueryColors:
318 {
319 if (error->error_code == BadValue)
320 return(False);
321 break;
322 }
323 }
324 }
325 return (True);
326 }
327
328