1 /*
2 * Copyright (C) 1995, 1996 Karl-Johan Johnsson.
3 */
4
5 /*
6
7 Copyright (c) 1989 X Consortium
8
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
27
28 Except as contained in this notice, the name of the X Consortium shall
29 not be used in advertising or otherwise to promote the sale, use or
30 other dealings in this Software without prior written authorization
31 from the X Consortium.
32
33 */
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <X11/IntrinsicP.h>
40 #include <X11/StringDefs.h>
41 #include <X11/ShellP.h>
42 #include <X11/Xatom.h>
43 #include <X11/Xutil.h>
44
45 #include "Compat.h"
46 #include "Util.h"
47 #include "UtilI.h"
48
49 /*
50 * This function is modified from the source to XTextWidth,
51 * which is why I included the X Consortium copyright notice.
52 */
MyXWidthToChars(XFontStruct * font,const char * str,int len,int width)53 int MyXWidthToChars(XFontStruct *font, const char *str, int len, int width)
54 {
55 XCharStruct *def;
56 int singlerow = (font->max_byte1 == 0);
57 int n;
58
59 if (!str || width <= 0)
60 return 0;
61
62 if (singlerow)
63 CI_GET_DEFAULT_INFO_1D(font, def);
64 else
65 CI_GET_DEFAULT_INFO_2D(font, def);
66
67 for (n = 0 ; n < len ; n++) {
68 XCharStruct *cs;
69 int ch = (unsigned char)str[n];
70
71 if (singlerow)
72 CI_GET_CHAR_INFO_1D(font, ch, def, cs);
73 else
74 /*
75 * essentially the macro CI_GET_ROWZERO_CHAR_INFO_2D
76 */
77 if (font->min_byte1 == 0 &&
78 ch >= font->min_char_or_byte2 && ch <= font->max_char_or_byte2)
79 if (!font->per_char)
80 cs = &font->min_bounds;
81 else {
82 cs = font->per_char + ch - font->min_char_or_byte2;
83 if (CI_NONEXISTCHAR(cs))
84 cs = def;
85 }
86 else
87 cs = def;
88
89 if (cs)
90 width -= cs->width;
91 if (width < 0)
92 break;
93 }
94
95 return n;
96 }
97
MyXWidthToWChars(XFontStruct * font,const XChar2b * str,int len,int width)98 int MyXWidthToWChars(XFontStruct *font, const XChar2b *str, int len, int width)
99 {
100 XCharStruct *def;
101 int singlerow = (font->max_byte1 == 0);
102 int n;
103
104 if (!font || width < 0)
105 return 0;
106
107 if (singlerow)
108 CI_GET_DEFAULT_INFO_1D(font, def);
109 else
110 CI_GET_DEFAULT_INFO_2D(font, def);
111
112 for (n = 0 ; n < len ; n++) {
113 XCharStruct *cs;
114
115 if (singlerow) {
116 int ch = (str[n].byte1 << 8) | str[n].byte2;
117
118 CI_GET_CHAR_INFO_1D(font, ch, def, cs);
119 } else {
120 int row = str[n].byte1;
121 int col = str[n].byte2;
122
123 CI_GET_CHAR_INFO_2D(font, row, col, def, cs);
124 }
125
126 if (cs)
127 width -= cs->width;
128 if (width < 0)
129 break;
130 }
131
132 return n;
133 }
134
135 /*************************************************************************/
136
137 typedef struct {
138 XtCallbackProc proc;
139 XtPointer client_data;
140 } CALLBACK_ENTRY;
141
WM_DELETE_WINDOW_handler(Widget w,XtPointer client_data,XEvent * event,Boolean * cont)142 static void WM_DELETE_WINDOW_handler(Widget w,
143 XtPointer client_data,
144 XEvent *event,
145 Boolean *cont)
146 {
147 Display *disp = XtDisplay(w);
148 CALLBACK_ENTRY *entry = (CALLBACK_ENTRY *)client_data;
149
150 if (event->type != ClientMessage || !entry->proc ||
151 event->xclient.message_type != intern_atom(disp, "WM_PROTOCOLS") ||
152 event->xclient.data.l[0] != intern_atom(disp, "WM_DELETE_WINDOW"))
153 return;
154
155 entry->proc(w, entry->client_data, (XtPointer)event);
156 *cont = False;
157 }
158
destroy_callback(Widget w,XtPointer client_data,XtPointer call_data)159 static void destroy_callback(Widget w,
160 XtPointer client_data,
161 XtPointer call_data)
162 {
163 CALLBACK_ENTRY *entry = (CALLBACK_ENTRY *)client_data;
164
165 entry->proc = NULL;
166 entry->client_data = NULL;
167 XtFree((char *)entry);
168 }
169
add_WM_DELETE_WINDOW_callback(Widget w,XtCallbackProc proc,XtPointer client_data)170 void add_WM_DELETE_WINDOW_callback(Widget w,
171 XtCallbackProc proc,
172 XtPointer client_data)
173 {
174 Display *disp = XtDisplay(w);
175 Window win = XtWindow(w);
176 Atom wm_delete_window;
177 CALLBACK_ENTRY *entry;
178
179 wm_delete_window = intern_atom(disp, "WM_DELETE_WINDOW");
180 XSetWMProtocols(disp, win, &wm_delete_window, 1);
181
182 entry = (CALLBACK_ENTRY *)XtMalloc(sizeof *entry);
183 entry->proc = proc;
184 entry->client_data = client_data;
185
186 XtAddEventHandler(w, 0, True, WM_DELETE_WINDOW_handler, (XtPointer)entry);
187 XtAddCallback(w, XtNdestroyCallback, destroy_callback, (XtPointer)entry);
188 }
189
190 /*************************************************************************/
191
get_event_xy(XEvent * event,int * x,int * y)192 int get_event_xy(XEvent *event, int *x, int *y)
193 {
194 if (!event)
195 return False;
196
197 switch (event->type) {
198 case ButtonPress:
199 case ButtonRelease:
200 *x = event->xbutton.x;
201 *y = event->xbutton.y;
202 return True;
203 case KeyPress:
204 case KeyRelease:
205 *x = event->xkey.x;
206 *y = event->xkey.y;
207 return True;
208 case EnterNotify:
209 case LeaveNotify:
210 *x = event->xcrossing.x;
211 *y = event->xcrossing.y;
212 return True;
213 case MotionNotify:
214 *x = event->xmotion.x;
215 *y = event->xmotion.y;
216 return True;
217 }
218
219 return False;
220 }
221
get_event_time(XEvent * event)222 Time get_event_time(XEvent *event)
223 {
224 switch (event->type) {
225 case ButtonPress:
226 case ButtonRelease:
227 return event->xbutton.time;
228 case KeyPress:
229 case KeyRelease:
230 return event->xkey.time;
231 case EnterNotify:
232 case LeaveNotify:
233 return event->xcrossing.time;
234 case MotionNotify:
235 return event->xmotion.time;
236 case PropertyNotify:
237 return event->xproperty.time;
238 case SelectionClear:
239 return event->xselectionclear.time;
240 case SelectionNotify:
241 return event->xselection.time;
242 case SelectionRequest:
243 return event->xselectionrequest.time;
244 }
245
246 return CurrentTime;
247 }
248
249 /*************************************************************************/
250
my_random(int n)251 static int my_random(int n)
252 {
253 static int i = 1999;
254
255 i *= 13;
256 i = i % 2371;
257
258 return (n * i) / 2371;
259 }
260
261 /*************************************************************************/
262
is_popped_up(Widget w)263 int is_popped_up(Widget w)
264 {
265 return (XtIsSubclass(w, shellWidgetClass) &&
266 ((ShellWidget)w)->shell.popped_up);
267 }
268
popup_under_pointer(Widget w,XtGrabKind grab)269 void popup_under_pointer(Widget w, XtGrabKind grab)
270 {
271 Widget parent = XtParent(w);
272 Arg pos_args[2];
273 int x, y, x1, y1;
274 Window w1, w2;
275 unsigned int m;
276
277 if (!XQueryPointer(XtDisplay(parent), XtWindow(parent),
278 &w1, &w2, &x, &y, &x1, &y1, &m))
279 x = y = 0;
280 x -= my_random(w->core.width);
281 y -= my_random(w->core.height);
282 if (x < 0)
283 x = 0;
284 else {
285 int temp = WidthOfScreen(XtScreen(parent)) - w->core.width;
286
287 if (temp < 0)
288 x = 0;
289 else if (x > temp)
290 x = temp;
291 }
292 if (y < 0)
293 y = 0;
294 else {
295 int temp = HeightOfScreen(XtScreen(parent)) - w->core.height;
296
297 if (temp < 0)
298 y = 0;
299 else if (y > temp)
300 y = temp;
301 }
302
303 XtSetArg(pos_args[0], XtNx, x);
304 XtSetArg(pos_args[1], XtNy, y);
305 XtSetValues(w, pos_args, XtNumber(pos_args));
306
307 XtPopup(w, grab);
308 }
309
310 /*********************************************************************/
311
ascii_lower(char * c)312 static void ascii_lower(char *c)
313 {
314 while (*c != '\0') {
315 if ((unsigned int)(*c - 'A') <= 'Z' - 'A')
316 *c += 'a' - 'A';
317 c++;
318 }
319 }
320
cvt_string_to_long(Display * disp,XrmValue * args,Cardinal * no_args,XrmValue * from,XrmValue * to,XtPointer * client_data)321 Boolean cvt_string_to_long(Display *disp,
322 XrmValue *args, Cardinal *no_args,
323 XrmValue *from, XrmValue *to,
324 XtPointer *client_data)
325 {
326 static long l;
327
328 if (sscanf((char *)from->addr, "%ld", &l) != 1) {
329 XtStringConversionWarning((char *)from->addr, XtRLong);
330 return False;
331 }
332
333 if (!to->addr)
334 to->addr = (XPointer)&l;
335 else {
336 if (to->size < sizeof l) {
337 to->size = sizeof l;
338 return False;
339 }
340 *(long *)to->addr = l;
341 }
342 to->size = sizeof l;
343
344 return True;
345 }
346
cvt_string_to_justify(Display * disp,XrmValue * args,Cardinal * no_args,XrmValue * from,XrmValue * to,XtPointer * client_data)347 Boolean cvt_string_to_justify(Display *disp,
348 XrmValue *args, Cardinal *no_args,
349 XrmValue *from, XrmValue *to,
350 XtPointer *client_data)
351 {
352 static JustifyType just;
353 static XrmQuark left = 0, center, right;
354 XrmQuark q;
355 char *s = (char *)from->addr;
356 char buffer[32];
357
358 if (!s || strlen(s) > 30)
359 return False;
360
361 if (!left) {
362 left = XrmPermStringToQuark("left");
363 center = XrmPermStringToQuark("center");
364 right = XrmPermStringToQuark("right");
365 }
366
367 if (to->addr && to->size < sizeof just) {
368 to->size = sizeof just;
369 return False;
370 }
371
372 strcpy(buffer, s);
373 ascii_lower(buffer);
374 q = XrmStringToQuark(buffer);
375
376 if (q == left)
377 just = JustifyTypeLeft;
378 else if (q == center)
379 just = JustifyTypeCenter;
380 else if (q == right)
381 just = JustifyTypeRight;
382 else {
383 XtStringConversionWarning((char *)from->addr, XtRJustify);
384 return False;
385 }
386
387 to->size = sizeof just;
388 if (to->addr)
389 *(JustifyType *)to->addr = just;
390 else
391 to->addr = (XPointer)&just;
392
393 return True;
394 }
395
396 /*********************************************************************/
397
cvt_std_sel(Widget w,Time t,Atom * sel,Atom * target,Atom * type_ret,XPointer * val_ret,unsigned long * len_ret,int * format_ret)398 Boolean cvt_std_sel(Widget w,
399 Time t,
400 Atom *sel,
401 Atom *target,
402 Atom *type_ret,
403 XPointer *val_ret,
404 unsigned long *len_ret,
405 int *format_ret)
406 {
407 Display *disp = XtDisplay(w);
408
409 #if 1
410 if (*target == intern_atom(disp, "TIMESTAMP")) {
411 long l = t;
412 int i = t;
413
414 if (sizeof l != 4 && sizeof i != 4)
415 return False;
416 *val_ret = (XPointer)XtMalloc(4);
417 if (sizeof l == 4)
418 memcpy(*val_ret, &l, 4);
419 else
420 memcpy(*val_ret, &i, 4);
421 *type_ret = XA_INTEGER;
422 *len_ret = 1;
423 *format_ret = 32;
424 return True;
425 }
426 #endif
427
428 if (*target == intern_atom(disp, "USER")) {
429 char *name = getenv("USER");
430
431 if (!name)
432 return False;
433 *val_ret = (XtPointer)XtNewString(name);
434 *type_ret = XA_STRING;
435 *len_ret = strlen(name);
436 *format_ret = 8;
437 return True;
438 }
439
440 if (*target == intern_atom(disp, "CLASS")) {
441 char *class;
442 int len;
443
444 while (w && !XtIsApplicationShell(w))
445 w = XtParent(w);
446
447 if (!w)
448 return False;
449
450 class = ((ApplicationShellWidget)w)->application.class;
451 len = strlen(w->core.name);
452 *len_ret = len + strlen(class) + 2;
453 *val_ret = (XPointer)XtMalloc(*len_ret);
454 strcpy((char *)*val_ret, w->core.name);
455 strcpy((char *)*val_ret + len + 1, class);
456 *type_ret = XA_STRING;
457 *format_ret = 8;
458 return True;
459 }
460
461 if (*target == intern_atom(disp, "NAME")) {
462 while (w && !XtIsWMShell(w))
463 w = XtParent(w);
464
465 while (w && !XtIsWMShell(w))
466 w = XtParent(w);
467
468 if (!w)
469 return False;
470
471 *val_ret = (XPointer)XtNewString(((WMShellWidget)w)->wm.title);
472 *len_ret = strlen((char *)*val_ret);
473 *type_ret = XA_STRING;
474 *format_ret = 8;
475 return True;
476 }
477
478 if (*target == intern_atom(disp, "CLIENT_WINDOW")) {
479 Widget p;
480
481 while ((p = XtParent(w)))
482 w = p;
483
484 *val_ret = (XPointer)XtMalloc(sizeof(Window));
485 *(Window *)*val_ret = w->core.window;
486 *type_ret = XA_WINDOW;
487 *len_ret = 1;
488 *format_ret = 32;
489 return True;
490 }
491
492 if (*target == intern_atom(disp, "TARGETS")) {
493 Atom *std_targets;
494 int n = 0;
495
496 std_targets = (Atom *)XtMalloc(16 * sizeof *std_targets);
497
498 #if 1
499 std_targets[n++] = intern_atom(disp, "TIMESTAMP");
500 #endif
501 std_targets[n++] = intern_atom(disp, "USER");
502 std_targets[n++] = intern_atom(disp, "CLASS");
503 std_targets[n++] = intern_atom(disp, "NAME");
504 std_targets[n++] = intern_atom(disp, "CLIENT_WINDOW");
505
506 *val_ret = (XPointer)std_targets;
507 *type_ret = XA_ATOM;
508 *len_ret = n;
509 *format_ret = 32;
510 return True;
511 }
512
513 return False;
514 }
515
516 /*********************************************************************/
517
518 typedef struct StippleCache StippleCache;
519
520 struct StippleCache {
521 StippleCache *next;
522 Screen *screen;
523 Pixmap pixmap;
524 unsigned int ref_cnt;
525 };
526
527 static StippleCache *stipple_cache = NULL;
528
create_stipple(Screen * screen)529 Pixmap create_stipple(Screen *screen)
530 {
531 static char bits[] = {0x01, 0x02};
532 StippleCache *loop;
533
534 for (loop = stipple_cache ; loop ; loop = loop->next)
535 if (loop->screen == screen) {
536 loop->ref_cnt++;
537 return loop->pixmap;
538 }
539
540 loop = (StippleCache *)XtMalloc(sizeof *loop);
541 loop->next = stipple_cache;
542 stipple_cache = loop;
543 loop->screen = screen;
544 loop->ref_cnt = 1;
545 loop->pixmap =
546 XCreatePixmapFromBitmapData(DisplayOfScreen(screen),
547 RootWindowOfScreen(screen),
548 bits, 2, 2, 0, 1, 1);
549
550 return loop->pixmap;
551 }
552
release_stipple(Screen * screen,Pixmap pixmap)553 void release_stipple(Screen *screen, Pixmap pixmap)
554 {
555 StippleCache **loop, *tmp;
556
557 if (!stipple_cache)
558 return;
559
560 for (loop = &stipple_cache ; *loop ; loop = &(*loop)->next)
561 if ((*loop)->screen == screen)
562 break;
563
564 tmp = *loop;
565
566 if (!tmp || --tmp->ref_cnt != 0)
567 return;
568
569 *loop = tmp->next;
570 XtFree((char *)tmp);
571 }
572
573 /*********************************************************************/
574
get_visual(Widget w)575 Visual *get_visual(Widget w)
576 {
577 while (w && !XtIsShell(w))
578 w = XtParent(w);
579
580 if (!w)
581 return NULL;
582
583 return ((ShellWidget)w)->shell.visual;
584 }
585
black_and_white(Screen * screen,Visual * visual,Pixel * black,Pixel * white)586 void black_and_white(Screen *screen, Visual *visual,
587 Pixel *black, Pixel *white)
588 {
589 Display *disp = DisplayOfScreen(screen);
590 XVisualInfo tmp, *info;
591 int n;
592
593 *black = BlackPixelOfScreen(screen);
594 *white = WhitePixelOfScreen(screen);
595 if (!visual)
596 return;
597
598 tmp.visualid = XVisualIDFromVisual(visual);
599 info = XGetVisualInfo(disp, VisualIDMask, &tmp, &n);
600 if (!info)
601 return;
602
603 switch (info->class) {
604 case StaticGray:
605 *black = 0;
606 *white = info->colormap_size - 1; /* Is this right? */
607 break;
608 case GrayScale:
609 /* ?? */
610 break;
611 case StaticColor:
612 *black = 0;
613 *white = info->red_mask | info->green_mask | info->blue_mask;
614 break;
615 case PseudoColor:
616 /* ?? */
617 break;
618 case TrueColor:
619 *black = 0;
620 *white = info->red_mask | info->green_mask | info->blue_mask;
621 case DirectColor:
622 /* ?? */
623 break;
624 }
625
626 XFree((char *)info);
627 }
628
get_black(Widget w)629 Pixel get_black(Widget w)
630 {
631 Screen *screen = XtScreen(w);
632 Visual *visual = get_visual(w);
633 Pixel black, white;
634
635 black_and_white(screen, visual, &black, &white);
636 return black;
637 }
638
639 /*********************************************************************/
640
641 typedef struct AtomCache {
642 struct AtomCache *next;
643 Display *disp;
644 XrmQuark name;
645 Atom atom;
646 } AtomCache;
647
648 /*
649 * This shouldn't grow to deep...
650 */
651 static AtomCache *atom_cache = NULL;
652
intern_atom(Display * disp,char * name_str)653 Atom intern_atom(Display *disp, char *name_str)
654 {
655 XrmQuark name = XrmStringToQuark(name_str);
656 AtomCache *loop = atom_cache;
657
658 for (loop = atom_cache ; loop ; loop = loop->next)
659 if (loop->name == name && loop->disp == disp)
660 return loop->atom;
661
662 loop = (AtomCache *)XtMalloc(sizeof *loop);
663 loop->next = atom_cache;
664 loop->disp = disp;
665 loop->name = name;
666 loop->atom = XInternAtom(disp, name_str, False);
667
668 atom_cache = loop;
669
670 return loop->atom;
671 }
672