1 /*
2 * Copyright (C) 1997-2009, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN 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 SOFTWARE.
22 */
23
24 static const char cvs_ident[] = "$Id: windows.c 51650 2010-08-26 01:34:13Z lucas $";
25
26 #include "config.h"
27 #include "feature.h"
28
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <X11/cursorfont.h>
34
35 #include "buttons.h"
36 #include "command.h"
37 #include "e.h"
38 #include "events.h"
39 #include "font.h"
40 #include "startup.h"
41 #include "menus.h"
42 #include "options.h"
43 #include "pixmap.h"
44 #include "screen.h"
45 #include "scrollbar.h"
46 #include "term.h"
47 #include "windows.h"
48
49 XWindowAttributes attr;
50 XSetWindowAttributes Attributes;
51 XSizeHints szHint = {
52 PMinSize | PResizeInc | PBaseSize,
53 0, 0, 80, 24, /* x, y, width, height */
54 1, 1, /* Min width, height */
55 0, 0, /* Max width, height - unused */
56 1, 1, /* increments: width, height */
57 {1, 1}, /* increments: x, y */
58 {0, 0}, /* Aspect ratio - unused */
59 0, 0, /* base size: width, height */
60 NorthWestGravity /* gravity */
61 };
62 Cursor TermWin_cursor; /* cursor for vt window */
63
64 void
set_text_property(Window win,char * propname,char * value)65 set_text_property(Window win, char *propname, char *value)
66 {
67 XTextProperty prop;
68 Atom atom;
69
70 ASSERT(propname != NULL);
71
72 if (!value) {
73 atom = XInternAtom(Xdisplay, propname, True);
74 if (atom == None) {
75 return;
76 }
77 XDeleteProperty(Xdisplay, win, atom);
78 } else {
79 atom = XInternAtom(Xdisplay, propname, False);
80 prop.value = (unsigned char *) value;
81 prop.encoding = XA_STRING;
82 prop.format = 8;
83 prop.nitems = strlen(value);
84 XSetTextProperty(Xdisplay, win, &prop, atom);
85 }
86 }
87
88 unsigned long
get_tint_by_color_name(const char * color)89 get_tint_by_color_name(const char *color)
90 {
91 XColor wcol, xcol;
92 unsigned long r, g, b, t;
93
94 wcol.pixel = WhitePixel(Xdisplay, Xscreen);
95 XQueryColor(Xdisplay, cmap, &wcol);
96
97 D_PIXMAP(("Tint string is \"%s\", white color is rgbi:%d/%d/%d\n", color, wcol.red, wcol.green, wcol.blue));
98 if (!XParseColor(Xdisplay, cmap, color, &xcol)) {
99 libast_print_error("Unable to parse tint color \"%s\". Ignoring.\n", color);
100 return 0xffffff;
101 }
102
103 D_PIXMAP(("RGB values for color are %d/%d/%d\n", xcol.red, xcol.green, xcol.blue));
104 if ((wcol.flags & DoRed) && (xcol.flags & DoRed)) {
105 r = (xcol.red << 8) / wcol.red;
106 D_PIXMAP(("Got red == %lu\n", r));
107 if (r >= 0x100)
108 r = 0xff;
109 } else {
110 r = 0xff;
111 }
112 if ((wcol.flags & DoGreen) && (xcol.flags & DoGreen)) {
113 g = (xcol.green << 8) / wcol.green;
114 D_PIXMAP(("Got green == %lu\n", g));
115 if (g >= 0x100)
116 g = 0xff;
117 } else {
118 g = 0xff;
119 }
120 if ((wcol.flags & DoBlue) && (xcol.flags & DoBlue)) {
121 b = (xcol.blue << 8) / wcol.blue;
122 D_PIXMAP(("Got blue == %lu\n", b));
123 if (b >= 0x100)
124 b = 0xff;
125 } else {
126 b = 0xff;
127 }
128 t = (r << 16) | (g << 8) | b;
129 D_PIXMAP(("Final tint is 0x%06x\n", t));
130 return t;
131 }
132
133 Pixel
get_bottom_shadow_color(Pixel norm_color,const char * type)134 get_bottom_shadow_color(Pixel norm_color, const char *type)
135 {
136
137 XColor xcol;
138
139 xcol.pixel = norm_color;
140 XQueryColor(Xdisplay, cmap, &xcol);
141
142 xcol.red /= 2;
143 xcol.green /= 2;
144 xcol.blue /= 2;
145
146 if (!XAllocColor(Xdisplay, cmap, &xcol)) {
147 libast_print_error("Unable to allocate \"%s\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map.\n", type, xcol.pixel, xcol.red,
148 xcol.green, xcol.blue);
149 xcol.pixel = PixColors[minColor];
150 }
151 return (xcol.pixel);
152 }
153
154 Pixel
get_top_shadow_color(Pixel norm_color,const char * type)155 get_top_shadow_color(Pixel norm_color, const char *type)
156 {
157
158 XColor xcol, white;
159
160 # ifdef PREFER_24BIT
161 white.red = white.green = white.blue = r = g = b = ~0;
162 XAllocColor(Xdisplay, cmap, &white);
163 # else
164 white.pixel = WhitePixel(Xdisplay, Xscreen);
165 XQueryColor(Xdisplay, cmap, &white);
166 # endif
167
168 xcol.pixel = norm_color;
169 XQueryColor(Xdisplay, cmap, &xcol);
170
171 xcol.red = MAX((white.red / 5), xcol.red);
172 xcol.green = MAX((white.green / 5), xcol.green);
173 xcol.blue = MAX((white.blue / 5), xcol.blue);
174
175 xcol.red = MIN(white.red, (xcol.red * 7) / 5);
176 xcol.green = MIN(white.green, (xcol.green * 7) / 5);
177 xcol.blue = MIN(white.blue, (xcol.blue * 7) / 5);
178
179 if (!XAllocColor(Xdisplay, cmap, &xcol)) {
180 libast_print_error("Unable to allocate \"%s\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map.\n", type, xcol.pixel, xcol.red,
181 xcol.green, xcol.blue);
182 xcol.pixel = PixColors[WhiteColor];
183 }
184 return (xcol.pixel);
185 }
186
187 Pixel
get_color_by_name(const char * name,const char * fallback)188 get_color_by_name(const char *name, const char *fallback)
189 {
190 XColor xcol;
191
192 if (!name) {
193 if (!fallback) {
194 return ((Pixel) - 1);
195 } else {
196 name = fallback;
197 }
198 } else if (isdigit(*name)) {
199 unsigned long c;
200
201 c = strtoul(name, (char **) NULL, 0);
202 if (c <= 15) {
203 name = rs_color[c + minColor];
204 }
205 }
206 if (!XParseColor(Xdisplay, cmap, name, &xcol)) {
207 libast_print_warning("Unable to resolve \"%s\" as a color name. Falling back on \"%s\".\n", name, NONULL(fallback));
208 name = fallback;
209 if (name) {
210 if (!XParseColor(Xdisplay, cmap, name, &xcol)) {
211 libast_print_warning
212 ("Unable to resolve \"%s\" as a color name. This should never fail. Please repair/restore your RGB database.\n",
213 name);
214 return ((Pixel) - 1);
215 }
216 } else {
217 return ((Pixel) - 1);
218 }
219 }
220 if (!XAllocColor(Xdisplay, cmap, &xcol)) {
221 libast_print_warning("Unable to allocate \"%s\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map. Falling back on \"%s\".\n",
222 name, xcol.pixel, xcol.red, xcol.green, xcol.blue, NONULL(fallback));
223 name = fallback;
224 if (name) {
225 if (!XAllocColor(Xdisplay, cmap, &xcol)) {
226 libast_print_warning("Unable to allocate \"%s\" (0x%08x: 0x%04x, 0x%04x, 0x%04x) in the color map.\n", name, xcol.pixel,
227 xcol.red, xcol.green, xcol.blue);
228 return ((Pixel) - 1);
229 }
230 } else {
231 return ((Pixel) - 1);
232 }
233 }
234 return (xcol.pixel);
235 }
236
237 Pixel
get_color_by_pixel(Pixel pixel,Pixel fallback)238 get_color_by_pixel(Pixel pixel, Pixel fallback)
239 {
240 XColor xcol;
241
242 xcol.pixel = pixel;
243 if (!XQueryColor(Xdisplay, cmap, &xcol)) {
244 libast_print_warning("Unable to convert pixel value 0x%08x to an XColor structure. Falling back on 0x%08x.\n", pixel, fallback);
245 xcol.pixel = fallback;
246 if (!XQueryColor(Xdisplay, cmap, &xcol)) {
247 libast_print_warning("Unable to convert pixel value 0x%08x to an XColor structure.\n", xcol.pixel);
248 return ((Pixel) 0);
249 }
250 }
251 if (!XAllocColor(Xdisplay, cmap, &xcol)) {
252 libast_print_warning("Unable to allocate 0x%08x (0x%04x, 0x%04x, 0x%04x) in the color map. Falling back on 0x%08x.\n", xcol.pixel,
253 xcol.red, xcol.green, xcol.blue, fallback);
254 xcol.pixel = fallback;
255 if (!XAllocColor(Xdisplay, cmap, &xcol)) {
256 libast_print_warning("Unable to allocate 0x%08x (0x%04x, 0x%04x, 0x%04x) in the color map.\n", xcol.pixel, xcol.red,
257 xcol.green, xcol.blue);
258 return ((Pixel) 0);
259 }
260 }
261 return (xcol.pixel);
262 }
263
264 void
process_colors(void)265 process_colors(void)
266 {
267 int i;
268 Pixel pixel;
269
270 for (i = 0; i < NRS_COLORS; i++) {
271 D_COLORS(("Adding color %d of %d (%s)\n", i, NRS_COLORS, def_colorName[i]));
272 if ((Xdepth <= 2) || ((pixel = get_color_by_name(rs_color[i], def_colorName[i])) == (Pixel) (-1))) {
273 switch (i) {
274 case fgColor:
275 pixel = WhitePixel(Xdisplay, Xscreen);
276 break;
277 case bgColor:
278 pixel = BlackPixel(Xdisplay, Xscreen);
279 break;
280 #ifndef NO_CURSORCOLOR
281 case cursorColor:
282 pixel = PixColors[bgColor];
283 break;
284 case cursorColor2:
285 pixel = PixColors[fgColor];
286 break;
287 #endif /* NO_CURSORCOLOR */
288 #ifndef NO_BOLDUNDERLINE
289 case colorBD:
290 pixel = PixColors[fgColor];
291 break;
292 case colorUL:
293 pixel = PixColors[fgColor];
294 break;
295 #endif
296 #ifdef ESCREEN
297 case ES_COLOR_CURRENT:
298 pixel = PixColors[YellowColor];
299 break;
300 case ES_COLOR_ACTIVE:
301 pixel = PixColors[BlueColor];
302 break;
303 #endif
304 case pointerColor:
305 pixel = PixColors[fgColor];
306 break;
307 case borderColor:
308 pixel = PixColors[bgColor];
309 break;
310 default:
311 pixel = PixColors[fgColor]; /* None */
312 break;
313 }
314 }
315 D_COLORS(("Pixel : %x\n", pixel));
316 PixColors[i] = pixel;
317 }
318
319 if (Xdepth <= 2) { /* Monochrome */
320 PixColors[topShadowColor] = PixColors[fgColor];
321 PixColors[bottomShadowColor] = PixColors[fgColor];
322 PixColors[unfocusedTopShadowColor] = PixColors[fgColor];
323 PixColors[unfocusedBottomShadowColor] = PixColors[fgColor];
324
325 PixColors[menuTopShadowColor] = PixColors[fgColor];
326 PixColors[menuBottomShadowColor] = PixColors[fgColor];
327 PixColors[unfocusedMenuTopShadowColor] = PixColors[fgColor];
328 PixColors[unfocusedMenuBottomShadowColor] = PixColors[fgColor];
329 } else {
330 PixColors[bottomShadowColor] = get_bottom_shadow_color(images[image_sb].norm->bg, "bottomShadowColor");
331 PixColors[unfocusedBottomShadowColor] =
332 get_bottom_shadow_color(images[image_sb].disabled->bg, "unfocusedBottomShadowColor");
333 PixColors[topShadowColor] = get_top_shadow_color(images[image_sb].norm->bg, "topShadowColor");
334 PixColors[unfocusedTopShadowColor] = get_top_shadow_color(images[image_sb].disabled->bg, "unfocusedTopShadowColor");
335
336 PixColors[menuBottomShadowColor] = get_bottom_shadow_color(images[image_menu].norm->bg, "menuBottomShadowColor");
337 PixColors[unfocusedMenuBottomShadowColor] =
338 get_bottom_shadow_color(images[image_menu].disabled->bg, "unfocusedMenuBottomShadowColor");
339 PixColors[menuTopShadowColor] = get_top_shadow_color(images[image_menu].norm->bg, "menuTopShadowColor");
340 PixColors[unfocusedMenuTopShadowColor] =
341 get_top_shadow_color(images[image_menu].disabled->bg, "unfocusedMenuTopShadowColor");
342 }
343 stored_palette(SAVE);
344 }
345
346 void
set_pointer_colors(const char * fg_name,const char * bg_name)347 set_pointer_colors(const char *fg_name, const char *bg_name)
348 {
349 XColor fg, bg;
350
351 if (fg_name) {
352 fg.pixel = get_color_by_name(fg_name, COLOR_NAME(pointerColor));
353 } else {
354 fg.pixel = PixColors[pointerColor];
355 }
356 XQueryColor(Xdisplay, cmap, &fg);
357 if (bg_name) {
358 bg.pixel = get_color_by_name(bg_name, COLOR_NAME(bgColor));
359 } else {
360 bg.pixel = PixColors[bgColor];
361 }
362 XQueryColor(Xdisplay, cmap, &bg);
363 XRecolorCursor(Xdisplay, TermWin_cursor, &fg, &bg);
364 }
365
366 /* Create_Windows() - Open and map the window */
367 void
Create_Windows(int argc,char * argv[])368 Create_Windows(int argc, char *argv[])
369 {
370
371 Cursor cursor;
372 XClassHint classHint;
373 XWMHints wmHint;
374 Atom prop = None;
375 CARD32 val;
376 int x = 0, y = 0, flags;
377 unsigned int width = 0, height = 0;
378 MWMHints mwmhints;
379
380 if (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_BORDERLESS)) {
381 mwmhints.flags = MWM_HINTS_DECORATIONS;
382 mwmhints.decorations = 0;
383 } else {
384 mwmhints.flags = 0;
385 }
386 Attributes.colormap = cmap;
387
388 szHint.base_width = (2 * TermWin.internalBorder + ((BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_SCROLLBAR))
389 ? (scrollbar_get_width() + (2 * scrollbar_get_shadow())) : 0));
390 szHint.base_height = (2 * TermWin.internalBorder) + bbar_calc_docked_height(BBAR_DOCKED);
391
392 flags = (rs_geometry ? XParseGeometry(rs_geometry, &x, &y, &width, &height) : 0);
393 D_X11(("XParseGeometry(geom, %d, %d, %d, %d)\n", x, y, width, height));
394
395 if (flags & WidthValue) {
396 szHint.width = width;
397 szHint.flags |= USSize;
398 }
399 if (flags & HeightValue) {
400 szHint.height = height;
401 szHint.flags |= USSize;
402 }
403 TERM_WINDOW_SET_COLS(szHint.width);
404 TERM_WINDOW_SET_ROWS(szHint.height);
405
406 change_font(1, NULL);
407
408 if (flags & XValue) {
409 if (flags & XNegative) {
410 x += (DisplayWidth(Xdisplay, Xscreen) - (szHint.width + TermWin.internalBorder));
411 }
412 szHint.x = x;
413 szHint.flags |= USPosition;
414 }
415 if (flags & YValue) {
416 if (flags & YNegative) {
417 y += (DisplayHeight(Xdisplay, Xscreen) - (szHint.height + TermWin.internalBorder));
418 }
419 szHint.y = y;
420 szHint.flags |= USPosition;
421 }
422 if (flags) {
423 D_X11(("Geometry values after parsing: %dx%d%+d%+d\n", width, height, x, y));
424 }
425
426 Attributes.background_pixel = PixColors[bgColor];
427 Attributes.border_pixel = PixColors[bgColor];
428 D_X11(("Size Hints: x %d, y %d. Width/Height: Base %dx%d, Minimum %dx%d, Current %dx%d, Increment %dx%d\n",
429 szHint.x, szHint.y, szHint.base_width, szHint.base_height, szHint.min_width, szHint.min_height, szHint.width,
430 szHint.height, szHint.width_inc, szHint.height_inc));
431 TermWin.parent = XCreateWindow(Xdisplay, Xroot, szHint.x, szHint.y, szHint.width, szHint.height, 0, Xdepth, InputOutput,
432 #ifdef PREFER_24BIT
433 Xvisual,
434 #else
435 CopyFromParent,
436 #endif
437 CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect, &Attributes);
438
439 xterm_seq(ESCSEQ_XTERM_TITLE, rs_title);
440 xterm_seq(ESCSEQ_XTERM_ICONNAME, rs_iconName);
441 classHint.res_name = (char *) rs_name;
442 classHint.res_class = APL_NAME;
443 wmHint.window_group = TermWin.parent;
444 wmHint.input = ((BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_NO_INPUT)) ? False : True);
445 wmHint.initial_state = (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_ICONIC) ? IconicState : NormalState);
446 wmHint.window_group = TermWin.parent;
447 wmHint.flags = (InputHint | StateHint | WindowGroupHint);
448 #ifdef PIXMAP_SUPPORT
449 set_icon_pixmap(rs_icon, &wmHint);
450 #endif
451
452 XSetWMProperties(Xdisplay, TermWin.parent, NULL, NULL, argv, argc, &szHint, &wmHint, &classHint);
453 XSelectInput(Xdisplay, Xroot, PropertyChangeMask);
454 XSelectInput(Xdisplay, TermWin.parent,
455 (KeyPressMask | FocusChangeMask | StructureNotifyMask | VisibilityChangeMask | PropertyChangeMask));
456 if (mwmhints.flags) {
457 prop = XInternAtom(Xdisplay, "_MOTIF_WM_HINTS", False);
458 XChangeProperty(Xdisplay, TermWin.parent, prop, prop, 32,
459 PropModeReplace, (unsigned char *) &mwmhints, PROP_MWM_HINTS_ELEMENTS);
460 }
461
462 /* vt cursor: Black-on-White is standard, but this is more popular */
463 TermWin_cursor = XCreateFontCursor(Xdisplay, XC_xterm);
464 set_pointer_colors(NULL, NULL);
465
466 /* cursor (menu/scrollbar): Black-on-White */
467 cursor = XCreateFontCursor(Xdisplay, XC_left_ptr);
468
469 /* the vt window */
470 TermWin.x = (((BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_SCROLLBAR))
471 && !(BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_SCROLLBAR_RIGHT)))
472 ? (scrollbar_get_width() + (2 * scrollbar_get_shadow())) : 0);
473 TermWin.y = bbar_calc_docked_height(BBAR_DOCKED_TOP);
474 TermWin.vt = XCreateWindow(Xdisplay, TermWin.parent, TermWin.x, TermWin.y, szHint.width, szHint.height,
475 0, Xdepth, InputOutput, CopyFromParent,
476 CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWColormap, &Attributes);
477 D_X11(("Created terminal window 0x%08x at %dx%d\n", TermWin.vt, TermWin.x, TermWin.y));
478 if (!(background_is_pixmap()) && !(BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_BORDERLESS))) {
479 XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[bgColor]);
480 XClearWindow(Xdisplay, TermWin.vt);
481 }
482 XDefineCursor(Xdisplay, TermWin.vt, TermWin_cursor);
483 TermWin.mask =
484 (EnterWindowMask | LeaveWindowMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | Button1MotionMask |
485 Button2MotionMask | Button3MotionMask);
486 XSelectInput(Xdisplay, TermWin.vt, TermWin.mask);
487
488 /* If the user wants a specific desktop, tell the WM that */
489 if (rs_desktop != -1) {
490 val = rs_desktop;
491 XChangeProperty(Xdisplay, TermWin.parent, props[PROP_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &val, 1);
492 }
493
494 /* Make window sticky if requested */
495 if (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_STICKY)) {
496 XChangeProperty(Xdisplay, TermWin.parent, props[PROP_EWMH_STATE], XA_ATOM, 32, PropModeReplace,
497 (unsigned char *) &props[PROP_EWMH_STATE_STICKY], 1);
498 }
499
500 /* Set startup ID property if given by the launching application. */
501 if (getenv("DESKTOP_STARTUP_ID")) {
502 Atom atom;
503 unsigned char *tmp = (spif_uchar_t *) getenv("DESKTOP_STARTUP_ID");
504
505 atom = XInternAtom(Xdisplay, "UTF8_STRING", False);
506 XChangeProperty(Xdisplay, TermWin.parent, props[PROP_EWMH_STARTUP_ID], atom, 8, PropModeReplace, tmp, strlen(tmp) + 1);
507 unsetenv("DESKTOP_STARTUP_ID");
508 }
509
510 /* Set window opacity if needed. */
511 if ((props[PROP_EWMH_OPACITY] != None) && (rs_opacity != 0xff)) {
512 XChangeProperty(Xdisplay, TermWin.parent, props[PROP_EWMH_OPACITY],
513 XA_CARDINAL, 32, PropModeReplace, (spif_uchar_t *) &rs_opacity, 1);
514 XChangeProperty(Xdisplay, TermWin.vt, props[PROP_EWMH_OPACITY],
515 XA_CARDINAL, 32, PropModeReplace, (spif_uchar_t *) &rs_opacity, 1);
516 }
517
518 /* We're done creating our windows. Now let's initialize the event subsystem to handle them. */
519 event_init_subsystem((event_dispatcher_t) process_x_event, (event_dispatcher_init_t) event_init_primary_dispatcher);
520
521 XMapWindow(Xdisplay, TermWin.vt);
522 XMapWindow(Xdisplay, TermWin.parent);
523 XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[bgColor]);
524
525 render_simage(images[image_bg].current, TermWin.vt, TermWin_TotalWidth(), TermWin_TotalHeight(), image_bg, 0);
526 if (image_mode_is(image_bg, MODE_AUTO)) {
527 enl_ipc_sync();
528 }
529
530 /* graphics context for the vt window */
531 {
532 XGCValues gcvalue;
533
534 gcvalue.font = TermWin.font->fid;
535 gcvalue.foreground = PixColors[fgColor];
536 gcvalue.background = PixColors[bgColor];
537 gcvalue.graphics_exposures = 0;
538 TermWin.gc = LIBAST_X_CREATE_GC(GCForeground | GCBackground | GCFont | GCGraphicsExposures, &gcvalue);
539 D_X11(("Created GC 0x%08x for TermWin.gc\n", TermWin.gc));
540 }
541
542 if (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_NO_CURSOR)) {
543 scr_cursor_visible(0);
544 }
545 }
546
547 /* resize window keeping one point (determined by window geometry) in place */
548 void
resize_parent(unsigned int width,unsigned int height)549 resize_parent(unsigned int width, unsigned int height)
550 {
551 XWindowAttributes attr;
552
553 if (!(BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_RESIZE_GRAVITY)) || !XGetWindowAttributes(Xdisplay, TermWin.parent, &attr)) {
554 XResizeWindow(Xdisplay, TermWin.parent, width, height);
555 } else {
556 Window junkwin;
557 int x, y, scr_w, scr_h;
558 int dx = 0, dy = 0;
559
560 scr_w = WidthOfScreen(attr.screen);
561 scr_h = HeightOfScreen(attr.screen);
562 dx = attr.width - width;
563 dy = attr.height - height;
564 XTranslateCoordinates(Xdisplay, TermWin.parent, attr.root, 0, 0, &x, &y, &junkwin);
565 /* Check position of the center of the window */
566 if (x < (scr_w - attr.width) / 2) {
567 /* left half */
568 dx = 0;
569 } else if (x == (scr_w - attr.width) / 2) {
570 /* exact center */
571 dx /= 2;
572 }
573 if (y < (scr_h - attr.height) / 2) {
574 /* top half */
575 dy = 0;
576 } else if (y == (scr_h - attr.height) / 2) {
577 /* exact center */
578 dy /= 2;
579 }
580 D_X11(("Calling XMoveResizeWindow(Xdisplay, 0x%08x, %d + %d, %d + %d, %d, %d)\n", TermWin.parent, x, dx, y, dy, width,
581 height));
582 XMoveResizeWindow(Xdisplay, TermWin.parent, x + dx, y + dy, width, height);
583 }
584 }
585
586 /* good for toggling 80/132 columns */
587 void
set_width(unsigned short width)588 set_width(unsigned short width)
589 {
590 unsigned short height = TERM_WINDOW_GET_REPORTED_ROWS();
591
592 if (width != TERM_WINDOW_GET_REPORTED_COLS()) {
593 width = szHint.base_width + width * TermWin.fwidth;
594 height = szHint.base_height + height * TermWin.fheight;
595
596 resize_parent(width, height);
597 handle_resize(width, height);
598 }
599 }
600
601 void
update_size_hints(void)602 update_size_hints(void)
603 {
604 D_X11(("Called.\n"));
605 szHint.base_width = (2 * TermWin.internalBorder) + ((scrollbar_is_visible())? (scrollbar_trough_width()) : (0));
606 szHint.base_height = (2 * TermWin.internalBorder) + bbar_calc_docked_height(BBAR_DOCKED);
607
608 szHint.width_inc = TermWin.fwidth;
609 szHint.height_inc = TermWin.fheight;
610
611 D_X11(("Size Hints: base width/height == %lux%lu, width/height increment == %lux%lu\n", szHint.base_width, szHint.base_height,
612 szHint.width_inc, szHint.height_inc));
613
614 szHint.min_width = szHint.base_width + szHint.width_inc;
615 szHint.min_height = szHint.base_height + szHint.height_inc;
616 szHint.width = szHint.base_width + TERM_WINDOW_GET_WIDTH();
617 szHint.height = szHint.base_height + TERM_WINDOW_GET_HEIGHT();
618 D_X11((" Minimum width/height == %lux%lu, width/height == %lux%lu\n", szHint.min_width, szHint.min_height,
619 szHint.width, szHint.height));
620
621 szHint.flags = PMinSize | PResizeInc | PBaseSize;
622 XSetWMNormalHints(Xdisplay, TermWin.parent, &szHint);
623 }
624
625 /* Resize terminal window and scrollbar window */
626 void
term_resize(int width,int height)627 term_resize(int width, int height)
628 {
629 static int last_width = 0, last_height = 0;
630
631 D_X11(("term_resize(%d, %d)\n", width, height));
632 TERM_WINDOW_SET_WIDTH();
633 TERM_WINDOW_SET_HEIGHT();
634 D_X11((" -> New TermWin width/height == %lux%lu\n", TERM_WINDOW_GET_WIDTH(), TERM_WINDOW_GET_HEIGHT()));
635 width = TERM_WINDOW_FULL_WIDTH();
636 height = TERM_WINDOW_FULL_HEIGHT();
637 XMoveResizeWindow(Xdisplay, TermWin.vt, ((BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_SCROLLBAR_RIGHT)) ? (0)
638 : ((scrollbar_is_visible())? (scrollbar_trough_width()) : (0))),
639 bbar_calc_docked_height(BBAR_DOCKED_TOP), width, height);
640 if (width != last_width || height != last_height) {
641 render_simage(images[image_bg].current, TermWin.vt, width, height, image_bg, 0);
642 scr_reset();
643 scr_touch();
644 if (image_mode_is(image_bg, MODE_AUTO)) {
645 enl_ipc_sync();
646 }
647 last_width = width;
648 last_height = height;
649 }
650 #ifdef USE_XIM
651 xim_set_status_position();
652 #endif
653 }
654
655 /* Resize due to font change; update size hints and child windows */
656 void
parent_resize(void)657 parent_resize(void)
658 {
659 D_X11(("Called.\n"));
660 update_size_hints();
661 resize_parent(szHint.width, szHint.height);
662 D_X11((" -> New parent width/height == %lux%lu\n", szHint.width, szHint.height));
663 term_resize(szHint.width, szHint.height);
664 scrollbar_resize(szHint.width, szHint.height - bbar_calc_docked_height(BBAR_DOCKED));
665 bbar_resize_all(szHint.width);
666 }
667
668 void
handle_resize(unsigned int width,unsigned int height)669 handle_resize(unsigned int width, unsigned int height)
670 {
671 static short first_time = 1;
672 int new_ncol = (width - szHint.base_width) / TermWin.fwidth;
673 int new_nrow = (height - szHint.base_height) / TermWin.fheight;
674
675 D_EVENTS(("handle_resize(%u, %u)\n", width, height));
676
677 if (first_time || (new_ncol != TERM_WINDOW_GET_REPORTED_ROWS()) || (new_nrow != TERM_WINDOW_GET_REPORTED_COLS())) {
678 TERM_WINDOW_SET_COLS(new_ncol);
679 TERM_WINDOW_SET_ROWS(new_nrow);
680 term_resize(width, height);
681 szHint.width = szHint.base_width + TERM_WINDOW_GET_WIDTH();
682 szHint.height = szHint.base_height + TERM_WINDOW_GET_HEIGHT();
683 D_X11((" -> New szHint.width/height == %lux%lu\n", szHint.width, szHint.height));
684 scrollbar_resize(width, szHint.height - bbar_calc_docked_height(BBAR_DOCKED));
685 bbar_resize_all(szHint.width);
686 first_time = 0;
687 }
688 }
689
690 void
handle_move(int x,int y)691 handle_move(int x, int y)
692 {
693 int dx, dy;
694
695 if ((TermWin.x != x) || (TermWin.y != y)) {
696 dx = abs(TermWin.x - x);
697 dy = abs(TermWin.y - y);
698 TermWin.x = x;
699 TermWin.y = y;
700 /* If we've moved an even multiple of the screen size, there's no
701 need to redraw trans/viewport images; the images will line up. */
702 if (image_mode_any(MODE_TRANS | MODE_VIEWPORT)) {
703 if ((dx % DisplayWidth(Xdisplay, Xscreen)) || (dy % DisplayHeight(Xdisplay, Xscreen))) {
704 redraw_images_by_mode(MODE_TRANS | MODE_VIEWPORT);
705 }
706 }
707 }
708 }
709
710 #ifdef XTERM_COLOR_CHANGE
711 void
stored_palette(char op)712 stored_palette(char op)
713 {
714 static Pixel default_colors[NRS_COLORS + EXTRA_COLORS];
715 static unsigned char stored = 0;
716 unsigned int i;
717
718 if (op == SAVE) {
719 for (i = 0; i < NRS_COLORS; i++) {
720 default_colors[i] = PixColors[i];
721 }
722 stored = 1;
723 } else if (op == RESTORE && stored) {
724 for (i = 0; i < NRS_COLORS; i++) {
725 PixColors[i] = default_colors[i];
726 }
727 }
728 }
729
730 void
set_window_color(int idx,const char * color)731 set_window_color(int idx, const char *color)
732 {
733 XColor xcol;
734 int i;
735
736 D_X11(("idx == %d, color == \"%s\"\n", idx, NONULL(color)));
737
738 if (!color || *color == '\0')
739 return;
740
741 /* handle color aliases */
742 if (isdigit(*color)) {
743 i = atoi(color);
744 if (i >= 8 && i <= 15) { /* bright colors */
745 i -= 8;
746 PixColors[idx] = PixColors[minBright + i];
747 } else if (i >= 0 && i <= 7) { /* normal colors */
748 PixColors[idx] = PixColors[minColor + i];
749 } else {
750 libast_print_warning("Color index %d is invalid.\n", i);
751 return;
752 }
753 } else if (XParseColor(Xdisplay, cmap, color, &xcol)) {
754 if (!XAllocColor(Xdisplay, cmap, &xcol)) {
755 libast_print_warning("Unable to allocate \"%s\" in the color map.\n", color);
756 return;
757 }
758 if ((idx > maxBright) && (idx < 256) && (PixColors[idx])) {
759 XFreeColors(Xdisplay, cmap, (unsigned long *) &(PixColors[idx]), 1, 0);
760 }
761 PixColors[idx] = xcol.pixel;
762 } else {
763 libast_print_warning("Unable to resolve \"%s\" as a color name.\n", color);
764 return;
765 }
766 set_colorfgbg();
767 scr_touch();
768 scr_refresh(DEFAULT_REFRESH);
769 redraw_image(image_bg);
770 }
771 #endif /* XTERM_COLOR_CHANGE */
772
773 Window
find_window_by_coords(Window win,int win_x,int win_y,int rel_x,int rel_y)774 find_window_by_coords(Window win, int win_x, int win_y, int rel_x, int rel_y)
775 {
776 Window *children = NULL;
777 XWindowAttributes attr;
778 Window child = 0, parent_win = 0, root_win = 0;
779 int i;
780 unsigned int ww, wh, num;
781 int wx, wy;
782
783 D_X11(("win 0x%08x at %d, %d. Coords are %d, %d.\n", win, win_x, win_y, rel_x, rel_y));
784
785 /* Bad or invisible window. */
786 if ((!XGetWindowAttributes(Xdisplay, win, &attr)) || (attr.map_state != IsViewable)) {
787 return None;
788 }
789 wx = attr.x + win_x;
790 wy = attr.y + win_y;
791 ww = attr.width;
792 wh = attr.height;
793
794 if (!((rel_x >= wx) && (rel_y >= wy) && (rel_x < (int) (wx + ww)) && (rel_y < (int) (wy + wh)))) {
795 return None;
796 }
797
798 if (!XQueryTree(Xdisplay, win, &root_win, &parent_win, &children, &num)) {
799 return win;
800 }
801 if (children) {
802 D_X11(("%d children.\n", num));
803 for (i = num - 1; i >= 0; i--) {
804 D_X11(("Trying children[%d] (0x%08x)\n", i, children[i]));
805 if ((child = find_window_by_coords(children[i], wx, wy, rel_x, rel_y)) != None) {
806 D_X11(("Match!\n"));
807 XFree(children);
808 return child;
809 }
810 }
811 D_X11(("XFree(children)\n"));
812 XFree(children);
813 }
814 D_X11(("Returning 0x%08x\n", win));
815 return win;
816 }
817