428
+ − 1 /* X output and frame manipulation routines.
+ − 2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
+ − 3 Copyright (C) 1994 Lucid, Inc.
+ − 4 Copyright (C) 1995 Sun Microsystems, Inc.
1318
+ − 5 Copyright (C) 2002, 2003 Ben Wing.
428
+ − 6
+ − 7 This file is part of XEmacs.
+ − 8
+ − 9 XEmacs is free software; you can redistribute it and/or modify it
+ − 10 under the terms of the GNU General Public License as published by the
+ − 11 Free Software Foundation; either version 2, or (at your option) any
+ − 12 later version.
+ − 13
+ − 14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ − 15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ − 16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ − 17 for more details.
+ − 18
+ − 19 You should have received a copy of the GNU General Public License
+ − 20 along with XEmacs; see the file COPYING. If not, write to
+ − 21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ − 22 Boston, MA 02111-1307, USA. */
+ − 23
+ − 24 /* Synched up with: Not in FSF. */
+ − 25
+ − 26 /* Author: Chuck Thompson */
+ − 27
+ − 28 /* Lots of work done by Ben Wing for Mule */
+ − 29
+ − 30 #include <config.h>
+ − 31 #include "lisp.h"
+ − 32
+ − 33 #include "buffer.h"
+ − 34 #include "debug.h"
872
+ − 35 #include "device-impl.h"
428
+ − 36 #include "faces.h"
800
+ − 37 #include "file-coding.h"
872
+ − 38 #include "frame-impl.h"
428
+ − 39 #include "gutter.h"
+ − 40 #include "redisplay.h"
+ − 41 #include "sysdep.h"
+ − 42 #include "window.h"
800
+ − 43
+ − 44 #ifdef MULE
+ − 45 #include "mule-ccl.h"
+ − 46 #endif
+ − 47
872
+ − 48 #include "console-x-impl.h"
800
+ − 49 #include "glyphs-x.h"
872
+ − 50 #include "objects-x-impl.h"
800
+ − 51 #include "xgccache.h"
+ − 52
+ − 53 #include "EmacsFrame.h"
+ − 54 #include "EmacsFrameP.h"
428
+ − 55
+ − 56 #include "sysproc.h" /* for select() */
+ − 57
800
+ − 58 #include <X11/bitmaps/gray>
428
+ − 59
+ − 60 /* Number of pixels below each line. */
+ − 61 int x_interline_space; /* #### implement me */
+ − 62
+ − 63 #define EOL_CURSOR_WIDTH 5
+ − 64
+ − 65 static void x_output_vertical_divider (struct window *w, int clear);
+ − 66 static void x_output_blank (struct window *w, struct display_line *dl,
+ − 67 struct rune *rb, int start_pixpos,
+ − 68 int cursor_start, int cursor_width);
+ − 69 static void x_output_hline (struct window *w, struct display_line *dl,
+ − 70 struct rune *rb);
+ − 71 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
+ − 72 int xpos, face_index findex);
+ − 73 static void x_clear_frame (struct frame *f);
+ − 74 static void x_clear_frame_windows (Lisp_Object window);
+ − 75
+ − 76
+ − 77 /* Note: We do not use the Xmb*() functions and XFontSets.
+ − 78 Those functions are generally losing for a number of reasons:
+ − 79
+ − 80 1) They only support one locale (e.g. you could display
+ − 81 Japanese and ASCII text, but not mixed Japanese/Chinese
+ − 82 text). You could maybe call setlocale() frequently
+ − 83 to try to deal with this, but that would generally
+ − 84 fail because an XFontSet is tied to one locale and
+ − 85 won't have the other character sets in it.
+ − 86 2) Not all (or even very many) OS's support the useful
+ − 87 locales. For example, as far as I know SunOS and
+ − 88 Solaris only support the Japanese locale if you get the
+ − 89 special Asian-language version of the OS. Yuck yuck
+ − 90 yuck. Linux doesn't support the Japanese locale at
+ − 91 all.
+ − 92 3) The locale support in X only exists in R5, not in R4.
+ − 93 (Not sure how big of a problem this is: how many
+ − 94 people are using R4?)
+ − 95 4) Who knows if the multi-byte text format (which is locale-
+ − 96 specific) is even the same for the same locale on
+ − 97 different OS's? It's not even documented anywhere that
+ − 98 I can find what the multi-byte text format for the
+ − 99 Japanese locale under SunOS and Solaris is, but I assume
+ − 100 it's EUC.
+ − 101 */
+ − 102
+ − 103 struct textual_run
+ − 104 {
+ − 105 Lisp_Object charset;
+ − 106 unsigned char *ptr;
+ − 107 int len;
+ − 108 int dimension;
+ − 109 };
+ − 110
+ − 111 /* Separate out the text in DYN into a series of textual runs of a
+ − 112 particular charset. Also convert the characters as necessary into
+ − 113 the format needed by XDrawImageString(), XDrawImageString16(), et
+ − 114 al. (This means converting to one or two byte format, possibly
+ − 115 tweaking the high bits, and possibly running a CCL program.) You
+ − 116 must pre-allocate the space used and pass it in. (This is done so
851
+ − 117 you can ALLOCA () the space.) You need to allocate (2 * len) bytes
428
+ − 118 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
+ − 119 RUN_STORAGE, where LEN is the length of the dynarr.
+ − 120
+ − 121 Returns the number of runs actually used. */
+ − 122
+ − 123 static int
+ − 124 separate_textual_runs (unsigned char *text_storage,
+ − 125 struct textual_run *run_storage,
867
+ − 126 const Ichar *str, Charcount len)
428
+ − 127 {
+ − 128 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
+ − 129 possible valid charset when
+ − 130 MULE is not defined */
+ − 131 int runs_so_far = 0;
+ − 132 int i;
+ − 133 #ifdef MULE
+ − 134 struct ccl_program char_converter;
+ − 135 int need_ccl_conversion = 0;
+ − 136 #endif
+ − 137
+ − 138 for (i = 0; i < len; i++)
+ − 139 {
867
+ − 140 Ichar ch = str[i];
428
+ − 141 Lisp_Object charset;
+ − 142 int byte1, byte2;
+ − 143 int dimension;
+ − 144 int graphic;
+ − 145
867
+ − 146 BREAKUP_ICHAR (ch, charset, byte1, byte2);
428
+ − 147 dimension = XCHARSET_DIMENSION (charset);
+ − 148 graphic = XCHARSET_GRAPHIC (charset);
+ − 149
+ − 150 if (!EQ (charset, prev_charset))
+ − 151 {
+ − 152 run_storage[runs_so_far].ptr = text_storage;
+ − 153 run_storage[runs_so_far].charset = charset;
+ − 154 run_storage[runs_so_far].dimension = dimension;
+ − 155
+ − 156 if (runs_so_far)
+ − 157 {
+ − 158 run_storage[runs_so_far - 1].len =
+ − 159 text_storage - run_storage[runs_so_far - 1].ptr;
+ − 160 if (run_storage[runs_so_far - 1].dimension == 2)
+ − 161 run_storage[runs_so_far - 1].len >>= 1;
+ − 162 }
+ − 163 runs_so_far++;
+ − 164 prev_charset = charset;
+ − 165 #ifdef MULE
+ − 166 {
+ − 167 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
444
+ − 168 if ((!NILP (ccl_prog))
+ − 169 && (setup_ccl_program (&char_converter, ccl_prog) >= 0))
+ − 170 need_ccl_conversion = 1;
428
+ − 171 }
+ − 172 #endif
+ − 173 }
+ − 174
+ − 175 if (graphic == 0)
+ − 176 {
+ − 177 byte1 &= 0x7F;
+ − 178 byte2 &= 0x7F;
+ − 179 }
+ − 180 else if (graphic == 1)
+ − 181 {
+ − 182 byte1 |= 0x80;
+ − 183 byte2 |= 0x80;
+ − 184 }
+ − 185 #ifdef MULE
+ − 186 if (need_ccl_conversion)
+ − 187 {
+ − 188 char_converter.reg[0] = XCHARSET_ID (charset);
+ − 189 char_converter.reg[1] = byte1;
+ − 190 char_converter.reg[2] = byte2;
+ − 191 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
+ − 192 byte1 = char_converter.reg[1];
+ − 193 byte2 = char_converter.reg[2];
+ − 194 }
+ − 195 #endif
+ − 196 *text_storage++ = (unsigned char) byte1;
+ − 197 if (dimension == 2)
+ − 198 *text_storage++ = (unsigned char) byte2;
+ − 199 }
+ − 200
+ − 201 if (runs_so_far)
+ − 202 {
+ − 203 run_storage[runs_so_far - 1].len =
+ − 204 text_storage - run_storage[runs_so_far - 1].ptr;
+ − 205 if (run_storage[runs_so_far - 1].dimension == 2)
+ − 206 run_storage[runs_so_far - 1].len >>= 1;
+ − 207 }
+ − 208
+ − 209 return runs_so_far;
+ − 210 }
+ − 211
+ − 212 /****************************************************************************/
+ − 213 /* */
+ − 214 /* X output routines */
+ − 215 /* */
+ − 216 /****************************************************************************/
+ − 217
+ − 218 static int
+ − 219 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
+ − 220 {
+ − 221 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
440
+ − 222 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
428
+ − 223 if (!fi->proportional_p)
+ − 224 return fi->width * run->len;
+ − 225 else
+ − 226 {
+ − 227 if (run->dimension == 2)
+ − 228 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
+ − 229 (XChar2b *) run->ptr, run->len);
+ − 230 else
+ − 231 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
+ − 232 (char *) run->ptr, run->len);
+ − 233 }
+ − 234 }
+ − 235
+ − 236 /*
+ − 237 x_text_width
+ − 238
+ − 239 Given a string and a face, return the string's length in pixels when
+ − 240 displayed in the font associated with the face.
+ − 241 */
+ − 242
+ − 243 static int
2286
+ − 244 x_text_width (struct frame *UNUSED (f), struct face_cachel *cachel,
+ − 245 const Ichar *str, Charcount len)
428
+ − 246 {
2367
+ − 247 /* !!#### Needs review */
428
+ − 248 int width_so_far = 0;
851
+ − 249 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len);
428
+ − 250 struct textual_run *runs = alloca_array (struct textual_run, len);
+ − 251 int nruns;
+ − 252 int i;
+ − 253
+ − 254 nruns = separate_textual_runs (text_storage, runs, str, len);
+ − 255
+ − 256 for (i = 0; i < nruns; i++)
+ − 257 width_so_far += x_text_width_single_run (cachel, runs + i);
+ − 258
+ − 259 return width_so_far;
+ − 260 }
+ − 261
+ − 262 /*****************************************************************************
+ − 263 x_divider_height
+ − 264
+ − 265 Return the height of the horizontal divider. This is a function because
+ − 266 divider_height is a device method.
+ − 267
+ − 268 #### If we add etched horizontal divider lines this will have to get
+ − 269 smarter.
+ − 270 ****************************************************************************/
+ − 271 static int
+ − 272 x_divider_height (void)
+ − 273 {
+ − 274 return 1;
+ − 275 }
+ − 276
+ − 277 /*****************************************************************************
+ − 278 x_eol_cursor_width
+ − 279
+ − 280 Return the width of the end-of-line cursor. This is a function
+ − 281 because eol_cursor_width is a device method.
+ − 282 ****************************************************************************/
+ − 283 static int
+ − 284 x_eol_cursor_width (void)
+ − 285 {
+ − 286 return EOL_CURSOR_WIDTH;
+ − 287 }
+ − 288
+ − 289 /*****************************************************************************
442
+ − 290 x_window_output_begin
428
+ − 291
+ − 292 Perform any necessary initialization prior to an update.
+ − 293 ****************************************************************************/
+ − 294 static void
2286
+ − 295 x_window_output_begin (struct window *UNUSED (w))
428
+ − 296 {
+ − 297 }
+ − 298
+ − 299 /*****************************************************************************
442
+ − 300 x_window_output_end
428
+ − 301
+ − 302 Perform any necessary flushing of queues when an update has completed.
+ − 303 ****************************************************************************/
+ − 304 static void
442
+ − 305 x_window_output_end (struct window *w)
428
+ − 306 {
1204
+ − 307 if (!(check_if_pending_expose_event (WINDOW_XDEVICE (w))))
+ − 308 XFlush (DEVICE_X_DISPLAY (WINDOW_XDEVICE (w)));
428
+ − 309 }
+ − 310
+ − 311 /*****************************************************************************
+ − 312 x_output_display_block
+ − 313
+ − 314 Given a display line, a block number for that start line, output all
+ − 315 runes between start and end in the specified display block.
+ − 316 ****************************************************************************/
+ − 317 static void
+ − 318 x_output_display_block (struct window *w, struct display_line *dl, int block,
+ − 319 int start, int end, int start_pixpos, int cursor_start,
+ − 320 int cursor_width, int cursor_height)
+ − 321 {
+ − 322 struct frame *f = XFRAME (w->frame);
867
+ − 323 Ichar_dynarr *buf = Dynarr_new (Ichar);
428
+ − 324 Lisp_Object window;
+ − 325
+ − 326 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
+ − 327 rune_dynarr *rba = db->runes;
+ − 328 struct rune *rb;
+ − 329
+ − 330 int elt = start;
+ − 331 face_index findex;
+ − 332 int xpos, width = 0;
+ − 333 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
+ − 334 MULE is not defined */
+ − 335
793
+ − 336 window = wrap_window (w);
428
+ − 337 rb = Dynarr_atp (rba, start);
+ − 338
+ − 339 if (!rb)
+ − 340 /* Nothing to do so don't do anything. */
+ − 341 return;
+ − 342
+ − 343 findex = rb->findex;
+ − 344 xpos = rb->xpos;
+ − 345 if (rb->type == RUNE_CHAR)
867
+ − 346 charset = ichar_charset (rb->object.chr.ch);
428
+ − 347
+ − 348 if (end < 0)
+ − 349 end = Dynarr_length (rba);
+ − 350 Dynarr_reset (buf);
+ − 351
+ − 352 while (elt < end)
+ − 353 {
+ − 354 rb = Dynarr_atp (rba, elt);
+ − 355
+ − 356 if (rb->findex == findex && rb->type == RUNE_CHAR
+ − 357 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
867
+ − 358 && EQ (charset, ichar_charset (rb->object.chr.ch)))
428
+ − 359 {
+ − 360 Dynarr_add (buf, rb->object.chr.ch);
+ − 361 width += rb->width;
+ − 362 elt++;
+ − 363 }
+ − 364 else
+ − 365 {
+ − 366 if (Dynarr_length (buf))
+ − 367 {
+ − 368 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
+ − 369 findex, 0, cursor_start, cursor_width,
+ − 370 cursor_height);
+ − 371 xpos = rb->xpos;
+ − 372 width = 0;
+ − 373 }
+ − 374 Dynarr_reset (buf);
+ − 375 width = 0;
+ − 376
+ − 377 if (rb->type == RUNE_CHAR)
+ − 378 {
+ − 379 findex = rb->findex;
+ − 380 xpos = rb->xpos;
867
+ − 381 charset = ichar_charset (rb->object.chr.ch);
428
+ − 382
+ − 383 if (rb->cursor_type == CURSOR_ON)
+ − 384 {
+ − 385 if (rb->object.chr.ch == '\n')
+ − 386 {
+ − 387 x_output_eol_cursor (w, dl, xpos, findex);
+ − 388 }
+ − 389 else
+ − 390 {
+ − 391 Dynarr_add (buf, rb->object.chr.ch);
+ − 392 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
+ − 393 rb->width, findex, 1,
+ − 394 cursor_start, cursor_width,
+ − 395 cursor_height);
+ − 396 Dynarr_reset (buf);
+ − 397 }
+ − 398
+ − 399 xpos += rb->width;
+ − 400 elt++;
+ − 401 }
+ − 402 else if (rb->object.chr.ch == '\n')
+ − 403 {
+ − 404 /* Clear in case a cursor was formerly here. */
440
+ − 405 redisplay_clear_region (window, findex, xpos,
428
+ − 406 DISPLAY_LINE_YPOS (dl),
440
+ − 407 rb->width,
428
+ − 408 DISPLAY_LINE_HEIGHT (dl));
+ − 409 elt++;
+ − 410 }
+ − 411 }
+ − 412 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
+ − 413 {
+ − 414 if (rb->type == RUNE_BLANK)
+ − 415 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
+ − 416 cursor_width);
+ − 417 else
+ − 418 {
+ − 419 /* #### Our flagging of when we need to redraw the
+ − 420 modeline shadows sucks. Since RUNE_HLINE is only used
+ − 421 by the modeline at the moment it is a good bet
+ − 422 that if it gets redrawn then we should also
+ − 423 redraw the shadows. This won't be true forever.
+ − 424 We borrow the shadow_thickness_changed flag for
+ − 425 now. */
+ − 426 w->shadow_thickness_changed = 1;
+ − 427 x_output_hline (w, dl, rb);
+ − 428 }
+ − 429
+ − 430 elt++;
+ − 431 if (elt < end)
+ − 432 {
+ − 433 rb = Dynarr_atp (rba, elt);
+ − 434
+ − 435 findex = rb->findex;
+ − 436 xpos = rb->xpos;
+ − 437 }
+ − 438 }
+ − 439 else if (rb->type == RUNE_DGLYPH)
+ − 440 {
+ − 441 Lisp_Object instance;
+ − 442 struct display_box dbox;
+ − 443 struct display_glyph_area dga;
819
+ − 444
428
+ − 445 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
819
+ − 446 rb->object.dglyph.yoffset, start_pixpos,
+ − 447 rb->width, &dbox, &dga);
428
+ − 448
793
+ − 449 window = wrap_window (w);
428
+ − 450 instance = glyph_image_instance (rb->object.dglyph.glyph,
793
+ − 451 window, ERROR_ME_DEBUG_WARN, 1);
428
+ − 452 findex = rb->findex;
+ − 453
+ − 454 if (IMAGE_INSTANCEP (instance))
442
+ − 455 {
+ − 456 switch (XIMAGE_INSTANCE_TYPE (instance))
428
+ − 457 {
442
+ − 458 case IMAGE_MONO_PIXMAP:
+ − 459 case IMAGE_COLOR_PIXMAP:
+ − 460 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
+ − 461 cursor_start, cursor_width,
+ − 462 cursor_height, 0);
+ − 463 break;
428
+ − 464
442
+ − 465 case IMAGE_WIDGET:
+ − 466 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
+ − 467 Qlayout))
+ − 468 {
+ − 469 redisplay_output_layout (window, instance, &dbox, &dga, findex,
+ − 470 cursor_start, cursor_width,
+ − 471 cursor_height);
+ − 472 break;
+ − 473 }
+ − 474 case IMAGE_SUBWINDOW:
+ − 475 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
+ − 476 cursor_start, cursor_width,
+ − 477 cursor_height);
+ − 478 break;
428
+ − 479
442
+ − 480 case IMAGE_NOTHING:
+ − 481 /* nothing is as nothing does */
+ − 482 break;
428
+ − 483
442
+ − 484 case IMAGE_TEXT:
+ − 485 case IMAGE_POINTER:
+ − 486 default:
2500
+ − 487 ABORT ();
442
+ − 488 }
+ − 489 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
+ − 490 (XIMAGE_INSTANCE (instance)) = 0;
+ − 491 }
428
+ − 492
+ − 493 xpos += rb->width;
+ − 494 elt++;
+ − 495 }
+ − 496 else
2500
+ − 497 ABORT ();
428
+ − 498 }
+ − 499 }
+ − 500
+ − 501 if (Dynarr_length (buf))
+ − 502 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
+ − 503 0, cursor_start, cursor_width, cursor_height);
+ − 504
+ − 505 /* #### This is really conditionalized well for optimized
+ − 506 performance. */
+ − 507 if (dl->modeline
+ − 508 && !EQ (Qzero, w->modeline_shadow_thickness)
+ − 509 && (f->clear
+ − 510 || f->windows_structure_changed
+ − 511 || w->shadow_thickness_changed))
+ − 512 bevel_modeline (w, dl);
+ − 513
+ − 514 Dynarr_free (buf);
+ − 515 }
+ − 516
+ − 517 /*****************************************************************************
+ − 518 x_bevel_area
+ − 519
450
+ − 520 Draw shadows for the given area in the given face.
428
+ − 521 ****************************************************************************/
+ − 522 static void
+ − 523 x_bevel_area (struct window *w, face_index findex,
+ − 524 int x, int y, int width, int height,
+ − 525 int shadow_thickness, int edges, enum edge_style style)
+ − 526 {
+ − 527 struct frame *f = XFRAME (w->frame);
+ − 528 struct device *d = XDEVICE (f->device);
+ − 529
+ − 530 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
+ − 531 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 532 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 533 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
+ − 534 Lisp_Object tmp_pixel;
+ − 535 XColor tmp_color;
+ − 536 XGCValues gcv;
+ − 537 GC top_shadow_gc, bottom_shadow_gc, background_gc;
+ − 538
+ − 539 int use_pixmap = 0;
+ − 540 int flip_gcs = 0;
+ − 541 unsigned long mask;
+ − 542
+ − 543 assert (shadow_thickness >=0);
+ − 544 memset (&gcv, ~0, sizeof (XGCValues));
+ − 545
+ − 546 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
+ − 547 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 548
+ − 549 /* First, get the GC's. */
+ − 550 top_shadow_pixel = tmp_color.pixel;
+ − 551 bottom_shadow_pixel = tmp_color.pixel;
+ − 552 background_pixel = tmp_color.pixel;
+ − 553
+ − 554 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
+ − 555 background_pixel, ef->core.background_pixel);
+ − 556
+ − 557 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
+ − 558 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 559 gcv.background = tmp_color.pixel;
+ − 560 gcv.graphics_exposures = False;
+ − 561 mask = GCForeground | GCBackground | GCGraphicsExposures;
+ − 562
+ − 563 /* If we can't distinguish one of the shadows (the color is the same as the
+ − 564 background), it's better to use a pixmap to generate a dithered gray. */
+ − 565 if (top_shadow_pixel == background_pixel ||
+ − 566 bottom_shadow_pixel == background_pixel)
+ − 567 use_pixmap = 1;
+ − 568
+ − 569 if (use_pixmap)
+ − 570 {
+ − 571 if (DEVICE_X_GRAY_PIXMAP (d) == None)
+ − 572 {
+ − 573 DEVICE_X_GRAY_PIXMAP (d) =
+ − 574 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
+ − 575 gray_width, gray_height, 1, 0, 1);
+ − 576 }
+ − 577
+ − 578 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
+ − 579 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 580 gcv.foreground = tmp_color.pixel;
+ − 581 /* this is needed because the GC draws with a pixmap here */
+ − 582 gcv.fill_style = FillOpaqueStippled;
+ − 583 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
+ − 584 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
+ − 585 (mask | GCStipple | GCFillStyle));
+ − 586
+ − 587 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
+ − 588 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 589 bottom_shadow_pixel = tmp_color.pixel;
+ − 590
+ − 591 flip_gcs = (bottom_shadow_pixel ==
+ − 592 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
+ − 593 }
+ − 594 else
+ − 595 {
+ − 596 gcv.foreground = top_shadow_pixel;
+ − 597 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
+ − 598 }
+ − 599
+ − 600 gcv.foreground = bottom_shadow_pixel;
+ − 601 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
+ − 602
+ − 603 if (use_pixmap && flip_gcs)
+ − 604 {
+ − 605 GC tmp_gc = bottom_shadow_gc;
+ − 606 bottom_shadow_gc = top_shadow_gc;
+ − 607 top_shadow_gc = tmp_gc;
+ − 608 }
+ − 609
+ − 610 gcv.foreground = background_pixel;
+ − 611 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
+ − 612
+ − 613 /* possibly revert the GC's This will give a depressed look to the
+ − 614 divider */
+ − 615 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
+ − 616 {
+ − 617 GC temp;
+ − 618
+ − 619 temp = top_shadow_gc;
+ − 620 top_shadow_gc = bottom_shadow_gc;
+ − 621 bottom_shadow_gc = temp;
+ − 622 }
+ − 623
+ − 624 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
+ − 625 shadow_thickness /= 2;
+ − 626
+ − 627 /* Draw the shadows around the divider line */
+ − 628 x_output_shadows (f, x, y, width, height,
+ − 629 top_shadow_gc, bottom_shadow_gc,
+ − 630 background_gc, shadow_thickness, edges);
+ − 631
+ − 632 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
+ − 633 {
+ − 634 /* Draw the shadows around the divider line */
+ − 635 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
+ − 636 width - 2*shadow_thickness, height - 2*shadow_thickness,
+ − 637 bottom_shadow_gc, top_shadow_gc,
+ − 638 background_gc, shadow_thickness, edges);
+ − 639 }
+ − 640 }
+ − 641
+ − 642 /*****************************************************************************
+ − 643 x_get_gc
+ − 644
+ − 645 Given a number of parameters return a GC with those properties.
+ − 646 ****************************************************************************/
+ − 647 static GC
+ − 648 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
+ − 649 Lisp_Object bg_pmap, Lisp_Object lwidth)
+ − 650 {
+ − 651 XGCValues gcv;
+ − 652 unsigned long mask;
+ − 653
+ − 654 memset (&gcv, ~0, sizeof (XGCValues));
+ − 655 gcv.graphics_exposures = False;
+ − 656 /* Make absolutely sure that we don't pick up a clipping region in
+ − 657 the GC returned by this function. */
+ − 658 gcv.clip_mask = None;
+ − 659 gcv.clip_x_origin = 0;
+ − 660 gcv.clip_y_origin = 0;
+ − 661 gcv.fill_style = FillSolid;
+ − 662 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
+ − 663 mask |= GCFillStyle;
+ − 664
+ − 665 if (!NILP (font))
+ − 666 {
+ − 667 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
+ − 668 mask |= GCFont;
+ − 669 }
+ − 670
+ − 671 /* evil kludge! */
+ − 672 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
+ − 673 {
+ − 674 /* #### I fixed once case where this was getting it. It was a
+ − 675 bad macro expansion (compiler bug). */
442
+ − 676 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
428
+ − 677 debug_print (fg);
+ − 678 fg = Qnil;
+ − 679 }
+ − 680
+ − 681 if (!NILP (fg))
+ − 682 {
+ − 683 if (COLOR_INSTANCEP (fg))
+ − 684 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
+ − 685 else
+ − 686 gcv.foreground = XINT (fg);
+ − 687 mask |= GCForeground;
+ − 688 }
+ − 689
+ − 690 if (!NILP (bg))
+ − 691 {
+ − 692 if (COLOR_INSTANCEP (bg))
+ − 693 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
+ − 694 else
+ − 695 gcv.background = XINT (bg);
+ − 696 mask |= GCBackground;
+ − 697 }
+ − 698
+ − 699 /* This special case comes from a request to draw text with a face which has
+ − 700 the dim property. We'll use a stippled foreground GC. */
+ − 701 if (EQ (bg_pmap, Qdim))
+ − 702 {
+ − 703 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
+ − 704
+ − 705 gcv.fill_style = FillStippled;
+ − 706 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
+ − 707 mask |= (GCFillStyle | GCStipple);
+ − 708 }
+ − 709 else if (IMAGE_INSTANCEP (bg_pmap)
+ − 710 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
+ − 711 {
+ − 712 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
+ − 713 {
+ − 714 gcv.fill_style = FillOpaqueStippled;
+ − 715 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
+ − 716 mask |= (GCStipple | GCFillStyle);
+ − 717 }
+ − 718 else
+ − 719 {
+ − 720 gcv.fill_style = FillTiled;
+ − 721 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
+ − 722 mask |= (GCTile | GCFillStyle);
+ − 723 }
+ − 724 }
+ − 725
+ − 726 if (!NILP (lwidth))
+ − 727 {
+ − 728 gcv.line_width = XINT (lwidth);
+ − 729 mask |= GCLineWidth;
+ − 730 }
+ − 731
+ − 732 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
+ − 733 }
+ − 734
+ − 735 /*****************************************************************************
+ − 736 x_output_string
+ − 737
+ − 738 Given a string and a starting position, output that string in the
+ − 739 given face. If cursor is true, draw a cursor around the string.
+ − 740 Correctly handles multiple charsets in the string.
+ − 741
+ − 742 The meaning of the parameters is something like this:
+ − 743
+ − 744 W Window that the text is to be displayed in.
+ − 745 DL Display line that this text is on. The values in the
+ − 746 structure are used to determine the vertical position and
+ − 747 clipping range of the text.
867
+ − 748 BUF Dynamic array of Ichars specifying what is actually to be
428
+ − 749 drawn.
+ − 750 XPOS X position in pixels where the text should start being drawn.
+ − 751 XOFFSET Number of pixels to be chopped off the left side of the
+ − 752 text. The effect is as if the text were shifted to the
+ − 753 left this many pixels and clipped at XPOS.
+ − 754 CLIP_START Clip everything left of this X position.
+ − 755 WIDTH Clip everything right of XPOS + WIDTH.
+ − 756 FINDEX Index for the face cache element describing how to display
+ − 757 the text.
+ − 758 CURSOR #### I don't understand this. There's something
+ − 759 strange and overcomplexified with this variable.
+ − 760 Chuck, explain please?
+ − 761 CURSOR_START Starting X position of cursor.
+ − 762 CURSOR_WIDTH Width of cursor in pixels.
+ − 763 CURSOR_HEIGHT Height of cursor in pixels.
+ − 764
+ − 765 Starting Y position of cursor is the top of the text line.
+ − 766 The cursor is drawn sometimes whether or not CURSOR is set. ???
+ − 767 ****************************************************************************/
+ − 768 void
+ − 769 x_output_string (struct window *w, struct display_line *dl,
867
+ − 770 Ichar_dynarr *buf, int xpos, int xoffset, int clip_start,
428
+ − 771 int width, face_index findex, int cursor,
+ − 772 int cursor_start, int cursor_width, int cursor_height)
+ − 773 {
+ − 774 /* General variables */
+ − 775 struct frame *f = XFRAME (w->frame);
+ − 776 struct device *d = XDEVICE (f->device);
+ − 777 Lisp_Object window;
+ − 778 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 779 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 780
+ − 781 int clip_end;
+ − 782
+ − 783 /* Cursor-related variables */
+ − 784 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
+ − 785 int cursor_clip;
+ − 786 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
+ − 787 WINDOW_BUFFER (w));
+ − 788 struct face_cachel *cursor_cachel = 0;
+ − 789
+ − 790 /* Text-related variables */
+ − 791 Lisp_Object bg_pmap;
+ − 792 GC bgc, gc;
+ − 793 int height;
+ − 794 int len = Dynarr_length (buf);
851
+ − 795 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len);
428
+ − 796 struct textual_run *runs = alloca_array (struct textual_run, len);
+ − 797 int nruns;
+ − 798 int i;
+ − 799 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
+ − 800
793
+ − 801 window = wrap_window (w);
428
+ − 802
+ − 803 if (width < 0)
+ − 804 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
+ − 805 height = DISPLAY_LINE_HEIGHT (dl);
+ − 806
+ − 807 /* Regularize the variables passed in. */
+ − 808
+ − 809 if (clip_start < xpos)
+ − 810 clip_start = xpos;
+ − 811 clip_end = xpos + width;
+ − 812 if (clip_start >= clip_end)
+ − 813 /* It's all clipped out. */
+ − 814 return;
+ − 815
+ − 816 xpos -= xoffset;
+ − 817
+ − 818 /* make sure the area we are about to display is subwindow free. */
+ − 819 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
+ − 820 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
+ − 821
+ − 822 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
+ − 823 Dynarr_length (buf));
+ − 824
+ − 825 cursor_clip = (cursor_start >= clip_start &&
+ − 826 cursor_start < clip_end);
+ − 827
+ − 828 /* This cursor code is really a mess. */
+ − 829 if (!NILP (w->text_cursor_visible_p)
+ − 830 && (cursor
+ − 831 || cursor_clip
+ − 832 || (cursor_width
+ − 833 && (cursor_start + cursor_width >= clip_start)
+ − 834 && !NILP (bar_cursor_value))))
+ − 835 {
+ − 836 /* These have to be in separate statements in order to avoid a
+ − 837 compiler bug. */
+ − 838 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
+ − 839 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
+ − 840
+ − 841 /* We have to reset this since any call to WINDOW_FACE_CACHEL
+ − 842 may cause the cache to resize and any pointers to it to
+ − 843 become invalid. */
+ − 844 cachel = WINDOW_FACE_CACHEL (w, findex);
+ − 845 }
+ − 846
+ − 847 #ifdef HAVE_XIM
+ − 848 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
+ − 849 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
+ − 850 #endif /* HAVE_XIM */
+ − 851
+ − 852 bg_pmap = cachel->background_pixmap;
+ − 853 if (!IMAGE_INSTANCEP (bg_pmap)
+ − 854 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
+ − 855 bg_pmap = Qnil;
+ − 856
+ − 857 if ((cursor && focus && NILP (bar_cursor_value)
+ − 858 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
+ − 859 bgc = 0;
+ − 860 else
+ − 861 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
+ − 862 bg_pmap, Qnil);
+ − 863
+ − 864 if (bgc)
+ − 865 XFillRectangle (dpy, x_win, bgc, clip_start,
+ − 866 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
+ − 867 height);
+ − 868
+ − 869 for (i = 0; i < nruns; i++)
+ − 870 {
+ − 871 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
440
+ − 872 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
428
+ − 873 int this_width;
+ − 874 int need_clipping;
+ − 875
+ − 876 if (EQ (font, Vthe_null_font_instance))
+ − 877 continue;
+ − 878
+ − 879 this_width = x_text_width_single_run (cachel, runs + i);
+ − 880 need_clipping = (dl->clip || clip_start > xpos ||
+ − 881 clip_end < xpos + this_width);
+ − 882
+ − 883 /* XDrawImageString only clears the area equal to the height of
+ − 884 the given font. It is possible that a font is being displayed
+ − 885 on a line taller than it is, so this would cause us to fail to
+ − 886 clear some areas. */
+ − 887 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
+ − 888 {
+ − 889 int clear_start = max (xpos, clip_start);
+ − 890 int clear_end = min (xpos + this_width, clip_end);
+ − 891
+ − 892 if (cursor)
+ − 893 {
+ − 894 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
+ − 895
+ − 896 ypos1_string = dl->ypos - fi->ascent;
+ − 897 ypos2_string = dl->ypos + fi->descent;
+ − 898 ypos1_line = DISPLAY_LINE_YPOS (dl);
+ − 899 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
+ − 900
+ − 901 /* Make sure we don't clear below the real bottom of the
+ − 902 line. */
+ − 903 if (ypos1_string > ypos2_line)
+ − 904 ypos1_string = ypos2_line;
+ − 905 if (ypos2_string > ypos2_line)
+ − 906 ypos2_string = ypos2_line;
+ − 907
+ − 908 if (ypos1_line < ypos1_string)
+ − 909 {
+ − 910 redisplay_clear_region (window, findex, clear_start, ypos1_line,
+ − 911 clear_end - clear_start,
+ − 912 ypos1_string - ypos1_line);
+ − 913 }
+ − 914
+ − 915 if (ypos2_line > ypos2_string)
+ − 916 {
+ − 917 redisplay_clear_region (window, findex, clear_start, ypos2_string,
+ − 918 clear_end - clear_start,
+ − 919 ypos2_line - ypos2_string);
+ − 920 }
+ − 921 }
+ − 922 else
+ − 923 {
+ − 924 redisplay_clear_region (window, findex, clear_start,
+ − 925 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
+ − 926 height);
+ − 927 }
+ − 928 }
+ − 929
+ − 930 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
+ − 931 gc = x_get_gc (d, font, cursor_cachel->foreground,
+ − 932 cursor_cachel->background, Qnil, Qnil);
+ − 933 else if (cachel->dim)
+ − 934 {
+ − 935 /* Ensure the gray bitmap exists */
+ − 936 if (DEVICE_X_GRAY_PIXMAP (d) == None)
+ − 937 DEVICE_X_GRAY_PIXMAP (d) =
+ − 938 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
+ − 939 gray_width, gray_height);
+ − 940
+ − 941 /* Request a GC with the gray stipple pixmap to draw dimmed text */
+ − 942 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
+ − 943 Qdim, Qnil);
+ − 944 }
+ − 945 else
+ − 946 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
+ − 947 Qnil, Qnil);
+ − 948
+ − 949 if (need_clipping)
+ − 950 {
+ − 951 XRectangle clip_box[1];
+ − 952
+ − 953 clip_box[0].x = 0;
+ − 954 clip_box[0].y = 0;
+ − 955 clip_box[0].width = clip_end - clip_start;
+ − 956 clip_box[0].height = height;
+ − 957
+ − 958 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
+ − 959 clip_box, 1, Unsorted);
+ − 960 }
+ − 961
+ − 962 if (runs[i].dimension == 1)
+ − 963 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
+ − 964 dl->ypos, (char *) runs[i].ptr,
+ − 965 runs[i].len);
+ − 966 else
+ − 967 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
+ − 968 dl->ypos,
+ − 969 (XChar2b *) runs[i].ptr,
+ − 970 runs[i].len);
+ − 971
+ − 972 /* We draw underlines in the same color as the text. */
+ − 973 if (cachel->underline)
+ − 974 {
647
+ − 975 int upos, uthick;
+ − 976 unsigned long upos_ext, uthick_ext;
428
+ − 977 XFontStruct *xfont;
+ − 978
+ − 979 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
647
+ − 980 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos_ext))
428
+ − 981 upos = dl->descent / 2;
647
+ − 982 else
+ − 983 upos = (int) upos_ext;
+ − 984 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick_ext))
428
+ − 985 uthick = 1;
647
+ − 986 else
+ − 987 uthick = (int) uthick_ext;
428
+ − 988
+ − 989 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
+ − 990 {
+ − 991 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
+ − 992 uthick = dl->descent - dl->clip - upos;
+ − 993
+ − 994 if (uthick == 1)
+ − 995 {
+ − 996 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
+ − 997 xpos + this_width, dl->ypos + upos);
+ − 998 }
+ − 999 else if (uthick > 1)
+ − 1000 {
+ − 1001 XFillRectangle (dpy, x_win, gc, xpos,
+ − 1002 dl->ypos + upos, this_width, uthick);
+ − 1003 }
+ − 1004 }
+ − 1005 }
+ − 1006
647
+ − 1007 if (cachel->strikethru)
+ − 1008 {
+ − 1009 int ascent, descent, upos, uthick;
+ − 1010 unsigned long ascent_ext, descent_ext, uthick_ext;
+ − 1011 XFontStruct *xfont;
428
+ − 1012
647
+ − 1013 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
+ − 1014
+ − 1015 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent_ext))
+ − 1016 ascent = xfont->ascent;
+ − 1017 else
+ − 1018 ascent = (int) ascent_ext;
+ − 1019 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent_ext))
+ − 1020 descent = xfont->descent;
+ − 1021 else
+ − 1022 descent = (int) descent_ext;
+ − 1023 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick_ext))
+ − 1024 uthick = 1;
+ − 1025 else
+ − 1026 uthick = (int) uthick_ext;
428
+ − 1027
647
+ − 1028 upos = ascent - ((ascent + descent) / 2) + 1;
428
+ − 1029
647
+ − 1030 /* Generally, upos will be positive (above the baseline),so
+ − 1031 subtract */
+ − 1032 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
+ − 1033 {
+ − 1034 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
+ − 1035 uthick = dl->descent - dl->clip + upos;
+ − 1036
+ − 1037 if (uthick == 1)
428
+ − 1038 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
+ − 1039 xpos + this_width, dl->ypos - upos);
647
+ − 1040 else if (uthick > 1)
428
+ − 1041 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
+ − 1042 this_width, uthick);
647
+ − 1043 }
+ − 1044 }
428
+ − 1045
+ − 1046 /* Restore the GC */
+ − 1047 if (need_clipping)
+ − 1048 {
+ − 1049 XSetClipMask (dpy, gc, None);
+ − 1050 XSetClipOrigin (dpy, gc, 0, 0);
+ − 1051 }
+ − 1052
+ − 1053 /* If we are actually superimposing the cursor then redraw with just
+ − 1054 the appropriate section highlighted. */
+ − 1055 if (cursor_clip && !cursor && focus && cursor_cachel)
+ − 1056 {
+ − 1057 GC cgc;
+ − 1058 XRectangle clip_box[1];
+ − 1059
+ − 1060 cgc = x_get_gc (d, font, cursor_cachel->foreground,
+ − 1061 cursor_cachel->background, Qnil, Qnil);
+ − 1062
+ − 1063 clip_box[0].x = 0;
+ − 1064 clip_box[0].y = 0;
+ − 1065 clip_box[0].width = cursor_width;
+ − 1066 clip_box[0].height = height;
+ − 1067
+ − 1068 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
+ − 1069 clip_box, 1, Unsorted);
+ − 1070
+ − 1071 if (runs[i].dimension == 1)
+ − 1072 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
+ − 1073 (char *) runs[i].ptr, runs[i].len);
+ − 1074 else
+ − 1075 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
+ − 1076 (XChar2b *) runs[i].ptr, runs[i].len);
+ − 1077
+ − 1078 XSetClipMask (dpy, cgc, None);
+ − 1079 XSetClipOrigin (dpy, cgc, 0, 0);
+ − 1080 }
+ − 1081
+ − 1082 xpos += this_width;
+ − 1083 }
+ − 1084
+ − 1085 /* Draw the non-focus box or bar-cursor as needed. */
+ − 1086 /* Can't this logic be simplified? */
+ − 1087 if (cursor_cachel
+ − 1088 && ((cursor && !focus && NILP (bar_cursor_value))
+ − 1089 || (cursor_width
+ − 1090 && (cursor_start + cursor_width >= clip_start)
+ − 1091 && !NILP (bar_cursor_value))))
+ − 1092 {
+ − 1093 int tmp_height, tmp_y;
+ − 1094 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
+ − 1095 int need_clipping = (cursor_start < clip_start
+ − 1096 || clip_end < cursor_start + cursor_width);
+ − 1097
+ − 1098 /* #### This value is correct (as far as I know) because
+ − 1099 all of the times we need to draw this cursor, we will
+ − 1100 be called with exactly one character, so we know we
+ − 1101 can always use runs[0].
+ − 1102
+ − 1103 This is bogus as all hell, however. The cursor handling in
+ − 1104 this function is way bogus and desperately needs to be
+ − 1105 cleaned up. (In particular, the drawing of the cursor should
+ − 1106 really really be separated out of this function. This may be
+ − 1107 a bit tricky now because this function itself does way too
+ − 1108 much stuff, a lot of which needs to be moved into
+ − 1109 redisplay.c) This is the only way to be able to easily add
+ − 1110 new cursor types or (e.g.) make the bar cursor be able to
+ − 1111 span two characters instead of overlaying just one. */
+ − 1112 int bogusly_obtained_ascent_value =
+ − 1113 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
+ − 1114
+ − 1115 if (!NILP (bar_cursor_value))
+ − 1116 {
+ − 1117 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
+ − 1118 make_int (bar_width));
+ − 1119 }
+ − 1120 else
+ − 1121 {
+ − 1122 gc = x_get_gc (d, Qnil, cursor_cachel->background,
+ − 1123 Qnil, Qnil, Qnil);
+ − 1124 }
+ − 1125
+ − 1126 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
+ − 1127 tmp_height = cursor_height;
+ − 1128 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
+ − 1129 {
+ − 1130 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
+ − 1131 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
+ − 1132 tmp_y = DISPLAY_LINE_YPOS (dl);
+ − 1133 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
+ − 1134 }
+ − 1135
+ − 1136 if (need_clipping)
+ − 1137 {
+ − 1138 XRectangle clip_box[1];
+ − 1139 clip_box[0].x = 0;
+ − 1140 clip_box[0].y = 0;
+ − 1141 clip_box[0].width = clip_end - clip_start;
+ − 1142 clip_box[0].height = tmp_height;
+ − 1143 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
+ − 1144 clip_box, 1, Unsorted);
+ − 1145 }
+ − 1146
+ − 1147 if (!focus && NILP (bar_cursor_value))
+ − 1148 {
+ − 1149 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
+ − 1150 cursor_width - 1, tmp_height - 1);
+ − 1151 }
+ − 1152 else if (focus && !NILP (bar_cursor_value))
+ − 1153 {
+ − 1154 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
+ − 1155 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
+ − 1156 }
+ − 1157
+ − 1158 /* Restore the GC */
+ − 1159 if (need_clipping)
+ − 1160 {
+ − 1161 XSetClipMask (dpy, gc, None);
+ − 1162 XSetClipOrigin (dpy, gc, 0, 0);
+ − 1163 }
+ − 1164 }
+ − 1165 }
+ − 1166
+ − 1167 void
440
+ − 1168 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
428
+ − 1169 int y, int xoffset, int yoffset,
440
+ − 1170 int width, int height, unsigned long fg, unsigned long bg,
428
+ − 1171 GC override_gc)
+ − 1172 {
+ − 1173 struct device *d = XDEVICE (f->device);
+ − 1174 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1175 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1176
+ − 1177 GC gc;
+ − 1178 XGCValues gcv;
+ − 1179 unsigned long pixmap_mask;
+ − 1180
+ − 1181 if (!override_gc)
+ − 1182 {
+ − 1183 memset (&gcv, ~0, sizeof (XGCValues));
+ − 1184 gcv.graphics_exposures = False;
+ − 1185 gcv.foreground = fg;
+ − 1186 gcv.background = bg;
+ − 1187 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
+ − 1188
+ − 1189 if (IMAGE_INSTANCE_X_MASK (p))
+ − 1190 {
+ − 1191 gcv.function = GXcopy;
+ − 1192 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
+ − 1193 gcv.clip_x_origin = x - xoffset;
+ − 1194 gcv.clip_y_origin = y - yoffset;
+ − 1195 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
+ − 1196 GCClipYOrigin);
+ − 1197 /* Can't set a clip rectangle because we already have a mask.
+ − 1198 Is it possible to get an equivalent effect by changing the
+ − 1199 args to XCopyArea below rather than messing with a clip box?
+ − 1200 - dkindred@cs.cmu.edu
+ − 1201 Yes. We don't clip at all now - andy@xemacs.org
+ − 1202 */
+ − 1203 }
+ − 1204
+ − 1205 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
+ − 1206 }
+ − 1207 else
+ − 1208 {
+ − 1209 gc = override_gc;
+ − 1210 /* override_gc might have a mask already--we don't want to nuke it.
+ − 1211 Maybe we can insist that override_gc have no mask, or use
+ − 1212 one of the suggestions above. */
+ − 1213 }
+ − 1214
+ − 1215 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
+ − 1216 XCopyPlane (1 = current foreground color, 0 = background) instead
+ − 1217 of XCopyArea, which means that the bits in the pixmap are actual
+ − 1218 pixel values, instead of symbolic of fg/bg. */
+ − 1219 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
+ − 1220 {
440
+ − 1221 XCopyArea (dpy,
+ − 1222 IMAGE_INSTANCE_X_PIXMAP_SLICE
428
+ − 1223 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
+ − 1224 yoffset, width,
+ − 1225 height, x, y);
+ − 1226 }
+ − 1227 else
+ − 1228 {
440
+ − 1229 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
428
+ − 1230 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
+ − 1231 xoffset, yoffset, width, height, x, y, 1L);
+ − 1232 }
+ − 1233 }
+ − 1234
+ − 1235 static void
+ − 1236 x_output_pixmap (struct window *w, Lisp_Object image_instance,
+ − 1237 struct display_box *db, struct display_glyph_area *dga,
+ − 1238 face_index findex, int cursor_start, int cursor_width,
2286
+ − 1239 int cursor_height, int UNUSED (bg_pixmap))
428
+ − 1240 {
+ − 1241 struct frame *f = XFRAME (w->frame);
+ − 1242 struct device *d = XDEVICE (f->device);
440
+ − 1243 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
428
+ − 1244
+ − 1245 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1246 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
440
+ − 1247
428
+ − 1248 /* Output the pixmap. */
+ − 1249 {
+ − 1250 Lisp_Object tmp_pixel;
+ − 1251 XColor tmp_bcolor, tmp_fcolor;
+ − 1252
+ − 1253 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
+ − 1254 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 1255 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
+ − 1256 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 1257
+ − 1258 x_output_x_pixmap (f, p, db->xpos, db->ypos,
+ − 1259 dga->xoffset, dga->yoffset,
+ − 1260 dga->width, dga->height,
+ − 1261 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
+ − 1262 }
+ − 1263
+ − 1264 /* Draw a cursor over top of the pixmap. */
+ − 1265 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
+ − 1266 && !NILP (w->text_cursor_visible_p)
+ − 1267 && (cursor_start < db->xpos + dga->width))
+ − 1268 {
+ − 1269 GC gc;
+ − 1270 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
+ − 1271 struct face_cachel *cursor_cachel =
+ − 1272 WINDOW_FACE_CACHEL (w,
+ − 1273 get_builtin_face_cache_index
+ − 1274 (w, Vtext_cursor_face));
+ − 1275
+ − 1276 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
+ − 1277
+ − 1278 if (cursor_width > db->xpos + dga->width - cursor_start)
+ − 1279 cursor_width = db->xpos + dga->width - cursor_start;
+ − 1280
+ − 1281 if (focus)
+ − 1282 {
+ − 1283 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
+ − 1284 cursor_height);
+ − 1285 }
+ − 1286 else
+ − 1287 {
+ − 1288 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
+ − 1289 cursor_height);
+ − 1290 }
+ − 1291 }
+ − 1292 }
+ − 1293
+ − 1294 /*****************************************************************************
+ − 1295 x_output_vertical_divider
+ − 1296
+ − 1297 Draw a vertical divider down the right side of the given window.
+ − 1298 ****************************************************************************/
+ − 1299 static void
+ − 1300 x_output_vertical_divider (struct window *w, int clear)
+ − 1301 {
+ − 1302 struct frame *f = XFRAME (w->frame);
+ − 1303 struct device *d = XDEVICE (f->device);
+ − 1304
+ − 1305 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1306 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1307 Lisp_Object tmp_pixel;
+ − 1308 XColor tmp_color;
+ − 1309 XGCValues gcv;
+ − 1310 GC background_gc;
+ − 1311 enum edge_style style;
+ − 1312
+ − 1313 unsigned long mask;
+ − 1314 int x, y1, y2, width, shadow_thickness, spacing, line_width;
647
+ − 1315 face_index div_face =
+ − 1316 get_builtin_face_cache_index (w, Vvertical_divider_face);
428
+ − 1317
+ − 1318 width = window_divider_width (w);
+ − 1319 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
+ − 1320 spacing = XINT (w->vertical_divider_spacing);
+ − 1321 line_width = XINT (w->vertical_divider_line_width);
+ − 1322 x = WINDOW_RIGHT (w) - width;
442
+ − 1323 y1 = WINDOW_TOP (w);
+ − 1324 y2 = WINDOW_BOTTOM (w);
428
+ − 1325
+ − 1326 memset (&gcv, ~0, sizeof (XGCValues));
+ − 1327
+ − 1328 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
+ − 1329 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 1330
+ − 1331 /* First, get the GC's. */
+ − 1332 gcv.background = tmp_color.pixel;
+ − 1333 gcv.foreground = tmp_color.pixel;
+ − 1334 gcv.graphics_exposures = False;
+ − 1335 mask = GCForeground | GCBackground | GCGraphicsExposures;
+ − 1336 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
+ − 1337
+ − 1338 /* Clear the divider area first. This needs to be done when a
+ − 1339 window split occurs. */
+ − 1340 if (clear)
+ − 1341 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
+ − 1342
+ − 1343 /* Draw the divider line. */
+ − 1344 XFillRectangle (dpy, x_win, background_gc,
+ − 1345 x + spacing + shadow_thickness, y1,
+ − 1346 line_width, y2 - y1);
+ − 1347
+ − 1348 if (shadow_thickness < 0)
+ − 1349 {
+ − 1350 shadow_thickness = -shadow_thickness;
+ − 1351 style = EDGE_BEVEL_IN;
+ − 1352 }
+ − 1353 else
+ − 1354 {
+ − 1355 style = EDGE_BEVEL_OUT;
+ − 1356 }
+ − 1357
+ − 1358 /* Draw the shadows around the divider line */
+ − 1359 x_bevel_area (w, div_face, x + spacing, y1,
+ − 1360 width - 2 * spacing, y2 - y1,
+ − 1361 shadow_thickness, EDGE_ALL, style);
+ − 1362 }
+ − 1363
+ − 1364 /*****************************************************************************
+ − 1365 x_output_blank
+ − 1366
+ − 1367 Output a blank by clearing the area it covers in the foreground color
+ − 1368 of its face.
+ − 1369 ****************************************************************************/
+ − 1370 static void
+ − 1371 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
+ − 1372 int start_pixpos, int cursor_start, int cursor_width)
+ − 1373 {
+ − 1374 struct frame *f = XFRAME (w->frame);
+ − 1375 struct device *d = XDEVICE (f->device);
+ − 1376
+ − 1377 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1378 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1379 GC gc;
+ − 1380 struct face_cachel *cursor_cachel =
+ − 1381 WINDOW_FACE_CACHEL (w,
+ − 1382 get_builtin_face_cache_index
+ − 1383 (w, Vtext_cursor_face));
+ − 1384 Lisp_Object bg_pmap;
+ − 1385 Lisp_Object buffer = WINDOW_BUFFER (w);
+ − 1386 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
+ − 1387 buffer);
+ − 1388
+ − 1389 int x = rb->xpos;
+ − 1390 int y = DISPLAY_LINE_YPOS (dl);
+ − 1391 int width = rb->width;
+ − 1392 int height = DISPLAY_LINE_HEIGHT (dl);
+ − 1393
+ − 1394 /* Unmap all subwindows in the area we are going to blank. */
+ − 1395 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
+ − 1396
+ − 1397 if (start_pixpos > x)
+ − 1398 {
+ − 1399 if (start_pixpos >= (x + width))
+ − 1400 return;
+ − 1401 else
+ − 1402 {
+ − 1403 width -= (start_pixpos - x);
+ − 1404 x = start_pixpos;
+ − 1405 }
+ − 1406 }
+ − 1407
+ − 1408 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
+ − 1409 if (!IMAGE_INSTANCEP (bg_pmap)
+ − 1410 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
+ − 1411 bg_pmap = Qnil;
+ − 1412
+ − 1413 if (NILP (bg_pmap))
+ − 1414 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
+ − 1415 Qnil, Qnil, Qnil);
+ − 1416 else
+ − 1417 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
+ − 1418 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
+ − 1419 Qnil);
+ − 1420
+ − 1421 XFillRectangle (dpy, x_win, gc, x, y, width, height);
+ − 1422
+ − 1423 /* If this rune is marked as having the cursor, then it is actually
+ − 1424 representing a tab. */
+ − 1425 if (!NILP (w->text_cursor_visible_p)
+ − 1426 && (rb->cursor_type == CURSOR_ON
+ − 1427 || (cursor_width
+ − 1428 && (cursor_start + cursor_width > x)
+ − 1429 && cursor_start < (x + width))))
+ − 1430 {
+ − 1431 int cursor_height, cursor_y;
+ − 1432 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
440
+ − 1433 Lisp_Font_Instance *fi;
428
+ − 1434
+ − 1435 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
+ − 1436 (WINDOW_FACE_CACHEL (w, rb->findex),
+ − 1437 Vcharset_ascii));
+ − 1438
+ − 1439 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
+ − 1440
+ − 1441 cursor_y = dl->ypos - fi->ascent;
+ − 1442 cursor_height = fi->height;
+ − 1443 if (cursor_y + cursor_height > y + height)
+ − 1444 cursor_height = y + height - cursor_y;
+ − 1445
+ − 1446 if (focus)
+ − 1447 {
+ − 1448 if (NILP (bar_cursor_value))
+ − 1449 {
+ − 1450 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
+ − 1451 fi->width, cursor_height);
+ − 1452 }
+ − 1453 else
+ − 1454 {
+ − 1455 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
+ − 1456
+ − 1457 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
+ − 1458 make_int (bar_width));
+ − 1459 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
+ − 1460 cursor_y, cursor_start + bar_width - 1,
+ − 1461 cursor_y + cursor_height - 1);
+ − 1462 }
+ − 1463 }
+ − 1464 else if (NILP (bar_cursor_value))
+ − 1465 {
+ − 1466 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
+ − 1467 fi->width - 1, cursor_height - 1);
+ − 1468 }
+ − 1469 }
+ − 1470 }
+ − 1471
+ − 1472 /*****************************************************************************
+ − 1473 x_output_hline
+ − 1474
+ − 1475 Output a horizontal line in the foreground of its face.
+ − 1476 ****************************************************************************/
+ − 1477 static void
+ − 1478 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
+ − 1479 {
+ − 1480 struct frame *f = XFRAME (w->frame);
+ − 1481 struct device *d = XDEVICE (f->device);
+ − 1482
+ − 1483 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1484 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1485 GC gc;
+ − 1486
+ − 1487 int x = rb->xpos;
+ − 1488 int width = rb->width;
+ − 1489 int height = DISPLAY_LINE_HEIGHT (dl);
+ − 1490 int ypos1, ypos2, ypos3, ypos4;
+ − 1491
+ − 1492 ypos1 = DISPLAY_LINE_YPOS (dl);
+ − 1493 ypos2 = ypos1 + rb->object.hline.yoffset;
+ − 1494 ypos3 = ypos2 + rb->object.hline.thickness;
+ − 1495 ypos4 = dl->ypos + dl->descent - dl->clip;
+ − 1496
+ − 1497 /* First clear the area not covered by the line. */
+ − 1498 if (height - rb->object.hline.thickness > 0)
+ − 1499 {
+ − 1500 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
+ − 1501 Qnil, Qnil, Qnil);
+ − 1502
+ − 1503 if (ypos2 - ypos1 > 0)
+ − 1504 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
+ − 1505 if (ypos4 - ypos3 > 0)
+ − 1506 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
+ − 1507 }
+ − 1508
+ − 1509 /* Now draw the line. */
+ − 1510 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
+ − 1511 Qnil, Qnil, Qnil);
+ − 1512
+ − 1513 if (ypos2 < ypos1)
+ − 1514 ypos2 = ypos1;
+ − 1515 if (ypos3 > ypos4)
+ − 1516 ypos3 = ypos4;
+ − 1517
+ − 1518 if (ypos3 - ypos2 > 0)
+ − 1519 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
+ − 1520 }
+ − 1521
+ − 1522 /*****************************************************************************
+ − 1523 x_output_shadows
+ − 1524
+ − 1525 Draw a shadow around the given area using the given GC's. It is the
+ − 1526 callers responsibility to set the GC's appropriately.
+ − 1527 ****************************************************************************/
+ − 1528 void
+ − 1529 x_output_shadows (struct frame *f, int x, int y, int width, int height,
2286
+ − 1530 GC top_shadow_gc, GC bottom_shadow_gc,
+ − 1531 GC UNUSED (background_gc), int shadow_thickness, int edges)
428
+ − 1532 {
+ − 1533 struct device *d = XDEVICE (f->device);
+ − 1534
+ − 1535 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1536 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1537
+ − 1538 XSegment top_shadow[20], bottom_shadow[20];
+ − 1539 int elt;
+ − 1540
+ − 1541 if (shadow_thickness > 10)
+ − 1542 shadow_thickness = 10;
+ − 1543 else if (shadow_thickness < 0)
+ − 1544 shadow_thickness = 0;
+ − 1545 if (shadow_thickness > (width / 2))
+ − 1546 shadow_thickness = width / 2;
+ − 1547 if (shadow_thickness > (height / 2))
+ − 1548 shadow_thickness = height / 2;
+ − 1549
+ − 1550 for (elt = 0; elt < shadow_thickness; elt++)
+ − 1551 {
+ − 1552 int seg1 = elt;
+ − 1553 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
+ − 1554 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
+ − 1555
+ − 1556 if (edges & EDGE_TOP)
+ − 1557 {
+ − 1558 top_shadow[seg1].x1 = x + elt;
+ − 1559 top_shadow[seg1].x2 = x + width - elt - 1;
+ − 1560 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
+ − 1561 }
+ − 1562 if (edges & EDGE_LEFT)
+ − 1563 {
+ − 1564 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
+ − 1565 top_shadow[seg2].y1 = y + elt;
+ − 1566 top_shadow[seg2].y2 = y + height - elt - 1;
+ − 1567 }
+ − 1568 if (edges & EDGE_BOTTOM)
+ − 1569 {
+ − 1570 bottom_shadow[seg1].x1 = x + elt;
+ − 1571 bottom_shadow[seg1].x2 = x + width - elt - 1;
+ − 1572 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
+ − 1573 }
+ − 1574 if (edges & EDGE_RIGHT)
+ − 1575 {
+ − 1576 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
+ − 1577 bottom_shadow[bot_seg2].y1 = y + elt;
+ − 1578 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
+ − 1579 }
+ − 1580 }
+ − 1581
+ − 1582 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
+ − 1583 ((edges & EDGE_TOP) ? shadow_thickness : 0)
+ − 1584 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
+ − 1585 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
+ − 1586 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
+ − 1587 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
+ − 1588 }
+ − 1589
+ − 1590 /*****************************************************************************
+ − 1591 x_generate_shadow_pixels
+ − 1592
+ − 1593 Given three pixels (top shadow, bottom shadow, background) massage
+ − 1594 the top and bottom shadow colors to guarantee that they differ. The
+ − 1595 background pixels are not allowed to be modified.
+ − 1596
+ − 1597 This function modifies its parameters.
+ − 1598
+ − 1599 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
+ − 1600 ****************************************************************************/
+ − 1601 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
+ − 1602 ? ((unsigned long) (x)) : ((unsigned long) (y)))
+ − 1603
+ − 1604 void
+ − 1605 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
+ − 1606 unsigned long *bottom_shadow,
+ − 1607 unsigned long background,
+ − 1608 unsigned long core_background)
+ − 1609 {
+ − 1610 struct device *d = XDEVICE (f->device);
+ − 1611 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1612 Colormap cmap = DEVICE_X_COLORMAP (d);
+ − 1613 Visual *visual = DEVICE_X_VISUAL (d);
+ − 1614
+ − 1615 XColor topc, botc;
+ − 1616 int top_frobbed = 0, bottom_frobbed = 0;
+ − 1617
+ − 1618 /* If the top shadow is the same color as the background, try to
+ − 1619 adjust it. */
+ − 1620 if (*top_shadow == background)
+ − 1621 {
+ − 1622 topc.pixel = background;
+ − 1623 XQueryColor (dpy, cmap, &topc);
+ − 1624 /* don't overflow/wrap! */
+ − 1625 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
+ − 1626 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
+ − 1627 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
+ − 1628 if (allocate_nearest_color (dpy, cmap, visual, &topc))
+ − 1629 {
+ − 1630 *top_shadow = topc.pixel;
+ − 1631 top_frobbed = 1;
+ − 1632 }
+ − 1633 }
+ − 1634
+ − 1635 /* If the bottom shadow is the same color as the background, try to
+ − 1636 adjust it. */
+ − 1637 if (*bottom_shadow == background)
+ − 1638 {
+ − 1639 botc.pixel = background;
+ − 1640 XQueryColor (dpy, cmap, &botc);
+ − 1641 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
+ − 1642 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
+ − 1643 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
+ − 1644 if (allocate_nearest_color (dpy, cmap, visual, &botc))
+ − 1645 {
+ − 1646 *bottom_shadow = botc.pixel;
+ − 1647 bottom_frobbed = 1;
+ − 1648 }
+ − 1649 }
+ − 1650
+ − 1651 /* If we had to adjust both shadows, then we have to do some
+ − 1652 additional work. */
+ − 1653 if (top_frobbed && bottom_frobbed)
+ − 1654 {
+ − 1655 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
+ − 1656 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
+ − 1657 if (bot_avg > top_avg)
+ − 1658 {
+ − 1659 Pixel tmp = *top_shadow;
+ − 1660
+ − 1661 *top_shadow = *bottom_shadow;
+ − 1662 *bottom_shadow = tmp;
+ − 1663 }
+ − 1664 else if (topc.pixel == botc.pixel)
+ − 1665 {
+ − 1666 if (botc.pixel == background)
+ − 1667 *top_shadow = core_background;
+ − 1668 else
+ − 1669 *bottom_shadow = background;
+ − 1670 }
+ − 1671 }
+ − 1672 }
+ − 1673
+ − 1674 /****************************************************************************
+ − 1675 x_clear_region
+ − 1676
+ − 1677 Clear the area in the box defined by the given parameters using the
+ − 1678 given face.
+ − 1679 ****************************************************************************/
+ − 1680 static void
2286
+ − 1681 x_clear_region (Lisp_Object UNUSED (locale), struct device* d,
+ − 1682 struct frame* f, face_index UNUSED (findex),
428
+ − 1683 int x, int y,
+ − 1684 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
+ − 1685 Lisp_Object background_pixmap)
+ − 1686 {
+ − 1687 Display *dpy;
+ − 1688 Window x_win;
+ − 1689 GC gc = NULL;
+ − 1690
+ − 1691 dpy = DEVICE_X_DISPLAY (d);
+ − 1692 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1693
+ − 1694 if (!UNBOUNDP (background_pixmap))
+ − 1695 {
+ − 1696 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
+ − 1697 }
+ − 1698
+ − 1699 if (gc)
+ − 1700 XFillRectangle (dpy, x_win, gc, x, y, width, height);
+ − 1701 else
+ − 1702 XClearArea (dpy, x_win, x, y, width, height, False);
+ − 1703 }
+ − 1704
+ − 1705 /*****************************************************************************
+ − 1706 x_output_eol_cursor
+ − 1707
+ − 1708 Draw a cursor at the end of a line. The end-of-line cursor is
+ − 1709 narrower than the normal cursor.
+ − 1710 ****************************************************************************/
+ − 1711 static void
+ − 1712 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
+ − 1713 face_index findex)
+ − 1714 {
+ − 1715 struct frame *f = XFRAME (w->frame);
+ − 1716 struct device *d = XDEVICE (f->device);
+ − 1717 Lisp_Object window;
+ − 1718
+ − 1719 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1720 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1721 GC gc;
+ − 1722 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
+ − 1723 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
+ − 1724
+ − 1725 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
+ − 1726 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
+ − 1727 WINDOW_BUFFER (w));
+ − 1728
+ − 1729 int x = xpos;
+ − 1730 int y = DISPLAY_LINE_YPOS (dl);
+ − 1731 int width = EOL_CURSOR_WIDTH;
+ − 1732 int height = DISPLAY_LINE_HEIGHT (dl);
+ − 1733 int cursor_height, cursor_y;
+ − 1734 int defheight, defascent;
+ − 1735
793
+ − 1736 window = wrap_window (w);
428
+ − 1737 redisplay_clear_region (window, findex, x, y, width, height);
+ − 1738
+ − 1739 if (NILP (w->text_cursor_visible_p))
+ − 1740 return;
+ − 1741
+ − 1742 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
+ − 1743
+ − 1744 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
+ − 1745
+ − 1746 /* make sure the cursor is entirely contained between y and y+height */
+ − 1747 cursor_height = min (defheight, height);
+ − 1748 cursor_y = max (y, min (y + height - cursor_height,
+ − 1749 dl->ypos - defascent));
+ − 1750
+ − 1751 if (focus)
+ − 1752 {
+ − 1753 #ifdef HAVE_XIM
+ − 1754 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
+ − 1755 #endif /* HAVE_XIM */
+ − 1756
+ − 1757 if (NILP (bar_cursor_value))
+ − 1758 {
+ − 1759 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
+ − 1760 }
+ − 1761 else
+ − 1762 {
+ − 1763 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
+ − 1764
+ − 1765 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
+ − 1766 make_int (bar_width));
+ − 1767 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
+ − 1768 x + bar_width - 1, cursor_y + cursor_height - 1);
+ − 1769 }
+ − 1770 }
+ − 1771 else if (NILP (bar_cursor_value))
+ − 1772 {
+ − 1773 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
+ − 1774 cursor_height - 1);
+ − 1775 }
+ − 1776 }
+ − 1777
+ − 1778 static void
+ − 1779 x_clear_frame_window (Lisp_Object window)
+ − 1780 {
+ − 1781 struct window *w = XWINDOW (window);
+ − 1782
+ − 1783 if (!NILP (w->vchild))
+ − 1784 {
+ − 1785 x_clear_frame_windows (w->vchild);
+ − 1786 return;
+ − 1787 }
+ − 1788
+ − 1789 if (!NILP (w->hchild))
+ − 1790 {
+ − 1791 x_clear_frame_windows (w->hchild);
+ − 1792 return;
+ − 1793 }
+ − 1794
440
+ − 1795 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
428
+ − 1796 WINDOW_TEXT_BOTTOM (w));
+ − 1797 }
+ − 1798
+ − 1799 static void
+ − 1800 x_clear_frame_windows (Lisp_Object window)
+ − 1801 {
+ − 1802 for (; !NILP (window); window = XWINDOW (window)->next)
+ − 1803 x_clear_frame_window (window);
+ − 1804 }
+ − 1805
+ − 1806 static void
+ − 1807 x_clear_frame (struct frame *f)
+ − 1808 {
+ − 1809 struct device *d = XDEVICE (f->device);
+ − 1810 Display *dpy = DEVICE_X_DISPLAY (d);
+ − 1811 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1812 int x, y, width, height;
+ − 1813 Lisp_Object frame;
+ − 1814
+ − 1815 x = FRAME_LEFT_BORDER_START (f);
+ − 1816 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
+ − 1817 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
+ − 1818 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
+ − 1819 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
+ − 1820 /* #### This adjustment by 1 should be being done in the macros.
+ − 1821 There is some small differences between when the menubar is on
+ − 1822 and off that we still need to deal with. */
+ − 1823 y = FRAME_TOP_BORDER_START (f) - 1;
+ − 1824 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
+ − 1825 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
+ − 1826 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
+ − 1827 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
+ − 1828
+ − 1829 XClearArea (dpy, x_win, x, y, width, height, False);
+ − 1830
793
+ − 1831 frame = wrap_frame (f);
428
+ − 1832
+ − 1833 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
+ − 1834 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
+ − 1835 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
+ − 1836 {
+ − 1837 x_clear_frame_windows (f->root_window);
+ − 1838 }
+ − 1839
1204
+ − 1840 if (!(check_if_pending_expose_event (d)))
+ − 1841 XFlush (DEVICE_X_DISPLAY (d));
428
+ − 1842 }
+ − 1843
+ − 1844 /* briefly swap the foreground and background colors.
+ − 1845 */
+ − 1846
+ − 1847 static int
+ − 1848 x_flash (struct device *d)
+ − 1849 {
+ − 1850 Display *dpy;
+ − 1851 Window win;
+ − 1852 XGCValues gcv;
+ − 1853 GC gc;
+ − 1854 XColor tmp_fcolor, tmp_bcolor;
+ − 1855 Lisp_Object tmp_pixel, frame;
+ − 1856 struct frame *f = device_selected_frame (d);
+ − 1857 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
+ − 1858 Widget shell = FRAME_X_SHELL_WIDGET (f);
442
+ − 1859 int flash_height;
428
+ − 1860
793
+ − 1861 frame = wrap_frame (f);
428
+ − 1862
+ − 1863 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
+ − 1864 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 1865 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
+ − 1866 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
+ − 1867
+ − 1868 dpy = XtDisplay (shell);
+ − 1869 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
+ − 1870 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
+ − 1871 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
+ − 1872 gcv.function = GXxor;
+ − 1873 gcv.graphics_exposures = False;
+ − 1874 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
+ − 1875 (GCForeground | GCFunction | GCGraphicsExposures));
442
+ − 1876 default_face_height_and_width (frame, &flash_height, 0);
+ − 1877
+ − 1878 /* If window is tall, flash top and bottom line. */
+ − 1879 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
+ − 1880 {
+ − 1881 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
+ − 1882 w->pixel_width, flash_height);
+ − 1883 XFillRectangle (dpy, win, gc, w->pixel_left,
+ − 1884 w->pixel_top + w->pixel_height - flash_height,
+ − 1885 w->pixel_width, flash_height);
+ − 1886 }
+ − 1887 else
+ − 1888 /* If it is short, flash it all. */
+ − 1889 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
+ − 1890 w->pixel_width, w->pixel_height);
+ − 1891
428
+ − 1892 XSync (dpy, False);
+ − 1893
+ − 1894 #ifdef HAVE_SELECT
+ − 1895 {
+ − 1896 int usecs = 100000;
+ − 1897 struct timeval tv;
+ − 1898 tv.tv_sec = usecs / 1000000L;
+ − 1899 tv.tv_usec = usecs % 1000000L;
+ − 1900 /* I'm sure someone is going to complain about this... */
+ − 1901 select (0, 0, 0, 0, &tv);
+ − 1902 }
+ − 1903 #else
+ − 1904 #ifdef HAVE_POLL
+ − 1905 poll (0, 0, 100);
+ − 1906 #else /* !HAVE_POLL */
+ − 1907 bite me
+ − 1908 #endif /* HAVE_POLL */
+ − 1909 #endif /* HAVE_SELECT */
+ − 1910
442
+ − 1911 /* If window is tall, flash top and bottom line. */
+ − 1912 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
+ − 1913 {
+ − 1914 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
+ − 1915 w->pixel_width, flash_height);
+ − 1916 XFillRectangle (dpy, win, gc, w->pixel_left,
+ − 1917 w->pixel_top + w->pixel_height - flash_height,
+ − 1918 w->pixel_width, flash_height);
+ − 1919 }
+ − 1920 else
+ − 1921 /* If it is short, flash it all. */
+ − 1922 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
+ − 1923 w->pixel_width, w->pixel_height);
+ − 1924
428
+ − 1925 XSync (dpy, False);
+ − 1926
+ − 1927 return 1;
+ − 1928 }
+ − 1929
+ − 1930 /* Make audible bell. */
+ − 1931
+ − 1932 static void
+ − 1933 x_ring_bell (struct device *d, int volume, int pitch, int duration)
+ − 1934 {
+ − 1935 Display *display = DEVICE_X_DISPLAY (d);
+ − 1936
+ − 1937 if (volume < 0) volume = 0;
+ − 1938 else if (volume > 100) volume = 100;
+ − 1939 if (pitch < 0 && duration < 0)
+ − 1940 {
+ − 1941 XBell (display, (volume * 2) - 100);
+ − 1942 XFlush (display);
+ − 1943 }
+ − 1944 else
+ − 1945 {
+ − 1946 XKeyboardState state;
+ − 1947 XKeyboardControl ctl;
+ − 1948 XSync (display, 0);
+ − 1949 /* #### grab server? */
+ − 1950 XGetKeyboardControl (display, &state);
+ − 1951
664
+ − 1952 ctl.bell_pitch = (pitch >= 0 ? pitch : (int) state.bell_pitch);
+ − 1953 ctl.bell_duration = (duration >= 0 ? duration : (int) state.bell_duration);
428
+ − 1954 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
+ − 1955
+ − 1956 XBell (display, (volume * 2) - 100);
+ − 1957
+ − 1958 ctl.bell_pitch = state.bell_pitch;
+ − 1959 ctl.bell_duration = state.bell_duration;
+ − 1960 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
+ − 1961
+ − 1962 /* #### ungrab server? */
+ − 1963 XSync (display, 0);
+ − 1964 }
+ − 1965 }
+ − 1966
+ − 1967
+ − 1968 /************************************************************************/
+ − 1969 /* initialization */
+ − 1970 /************************************************************************/
+ − 1971
+ − 1972 void
+ − 1973 console_type_create_redisplay_x (void)
+ − 1974 {
+ − 1975 /* redisplay methods */
+ − 1976 CONSOLE_HAS_METHOD (x, text_width);
+ − 1977 CONSOLE_HAS_METHOD (x, output_display_block);
+ − 1978 CONSOLE_HAS_METHOD (x, divider_height);
+ − 1979 CONSOLE_HAS_METHOD (x, eol_cursor_width);
+ − 1980 CONSOLE_HAS_METHOD (x, output_vertical_divider);
+ − 1981 CONSOLE_HAS_METHOD (x, clear_region);
+ − 1982 CONSOLE_HAS_METHOD (x, clear_frame);
442
+ − 1983 CONSOLE_HAS_METHOD (x, window_output_begin);
+ − 1984 CONSOLE_HAS_METHOD (x, window_output_end);
428
+ − 1985 CONSOLE_HAS_METHOD (x, flash);
+ − 1986 CONSOLE_HAS_METHOD (x, ring_bell);
+ − 1987 CONSOLE_HAS_METHOD (x, bevel_area);
+ − 1988 CONSOLE_HAS_METHOD (x, output_string);
+ − 1989 CONSOLE_HAS_METHOD (x, output_pixmap);
+ − 1990 }