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.
6 This file is part of SXEmacs
8 SXEmacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 SXEmacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 /* Synched up with: Not in FSF. */
24 /* Author: Chuck Thompson */
25 /* Gtk flavor by William Perry */
27 /* Lots of work done by Ben Wing for Mule */
32 #include "console-gtk.h"
33 #include "gccache-gtk.h"
34 #include "glyphs-gtk.h"
35 #include "objects-gtk.h"
41 #include "ui/gutter.h"
42 #include "ui/redisplay.h"
44 #include "ui/window.h"
46 #include "sysproc.h" /* for select() */
49 #include "mule/mule-ccl.h"
50 #include "mule/file-coding.h" /* for CCL conversion */
59 #define EOL_CURSOR_WIDTH 5
61 static void gtk_output_pixmap(struct window *w, struct display_line *dl,
62 Lisp_Object image_instance, int xpos,
64 int start_pixpos, int width, face_index findex,
65 int cursor_start, int cursor_width,
67 static void gtk_output_vertical_divider(struct window *w, int clear);
68 static void gtk_output_blank(struct window *w, struct display_line *dl,
69 struct rune *rb, int start_pixpos,
70 int cursor_start, int cursor_width);
71 static void gtk_output_hline(struct window *w, struct display_line *dl,
73 static void gtk_redraw_exposed_window(struct window *w, int x, int y,
74 int width, int height);
75 static void gtk_redraw_exposed_windows(Lisp_Object window, int x, int y,
76 int width, int height);
77 static void gtk_clear_region(Lisp_Object locale, struct device *d,
78 struct frame *f, face_index findex, int x, int y,
79 int width, int height, Lisp_Object fcolor,
80 Lisp_Object bcolor, Lisp_Object background_pixmap);
81 static void gtk_output_eol_cursor(struct window *w, struct display_line *dl,
82 int xpos, face_index findex);
83 static void gtk_clear_frame(struct frame *f);
84 static void gtk_clear_frame_windows(Lisp_Object window);
85 static void gtk_bevel_modeline(struct window *w, struct display_line *dl);
88 static void __describe_gc(GdkGC *);
98 /* Separate out the text in DYN into a series of textual runs of a
99 particular charset. Also convert the characters as necessary into
100 the format needed by XDrawImageString(), XDrawImageString16(), et
101 al. (This means converting to one or two byte format, possibly
102 tweaking the high bits, and possibly running a CCL program.) You
103 must pre-allocate the space used and pass it in. (This is done so
104 you can alloca() the space.) You need to allocate (2 * len) bytes
105 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
106 RUN_STORAGE, where LEN is the length of the dynarr.
108 Returns the number of runs actually used. */
111 separate_textual_runs(unsigned char *text_storage,
112 struct textual_run *run_storage,
113 CONST Emchar * str, Charcount len)
115 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
116 possible valid charset when
117 MULE is not defined */
121 struct ccl_program char_converter;
122 int need_ccl_conversion = 0;
125 for (i = 0; i < len; i++) {
132 BREAKUP_CHAR(ch, charset, byte1, byte2);
133 dimension = XCHARSET_DIMENSION(charset);
134 graphic = XCHARSET_GRAPHIC(charset);
136 if (!EQ(charset, prev_charset)) {
137 run_storage[runs_so_far].ptr = text_storage;
138 run_storage[runs_so_far].charset = charset;
139 run_storage[runs_so_far].dimension = dimension;
142 run_storage[runs_so_far - 1].len =
143 text_storage - run_storage[runs_so_far -
145 if (run_storage[runs_so_far - 1].dimension == 2)
146 run_storage[runs_so_far - 1].len >>= 1;
149 prev_charset = charset;
152 Lisp_Object ccl_prog =
153 XCHARSET_CCL_PROGRAM(charset);
154 need_ccl_conversion = !NILP(ccl_prog);
155 if (need_ccl_conversion)
156 setup_ccl_program(&char_converter,
165 } else if (graphic == 1) {
170 if (need_ccl_conversion) {
171 char_converter.reg[0] = XCHARSET_ID(charset);
172 char_converter.reg[1] = byte1;
173 char_converter.reg[2] = byte2;
174 ccl_driver(&char_converter, 0, 0, 0, 0,
176 byte1 = char_converter.reg[1];
177 byte2 = char_converter.reg[2];
180 *text_storage++ = (unsigned char)byte1;
182 *text_storage++ = (unsigned char)byte2;
186 run_storage[runs_so_far - 1].len =
187 text_storage - run_storage[runs_so_far - 1].ptr;
188 if (run_storage[runs_so_far - 1].dimension == 2)
189 run_storage[runs_so_far - 1].len >>= 1;
195 /****************************************************************************/
197 /* Gtk output routines */
199 /****************************************************************************/
202 gtk_text_width_single_run(struct face_cachel *cachel, struct textual_run *run)
204 Lisp_Object font_inst = FACE_CACHEL_FONT(cachel, run->charset);
205 struct Lisp_Font_Instance *fi = XFONT_INSTANCE(font_inst);
207 if (!fi->proportional_p) {
208 return fi->width * run->len;
210 if (run->dimension == 2) {
211 stderr_out("Measuring wide characters\n");
212 return gdk_text_width_wc(FONT_INSTANCE_GTK_FONT(fi),
213 (GdkWChar *) run->ptr,
216 return gdk_text_width(FONT_INSTANCE_GTK_FONT(fi),
217 (char *)run->ptr, run->len);
225 Given a string and a face, return the string's length in pixels when
226 displayed in the font associated with the face.
230 gtk_text_width(struct frame *f, struct face_cachel *cachel, CONST Emchar * str,
233 int width_so_far = 0;
234 unsigned char *text_storage = (unsigned char *)alloca(2 * len);
235 struct textual_run *runs = alloca_array(struct textual_run, len);
239 nruns = separate_textual_runs(text_storage, runs, str, len);
241 for (i = 0; i < nruns; i++)
242 width_so_far += gtk_text_width_single_run(cachel, runs + i);
247 /*****************************************************************************
250 Return the height of the horizontal divider. This is a function because
251 divider_height is a device method.
253 #### If we add etched horizontal divider lines this will have to get
255 ****************************************************************************/
256 static int gtk_divider_height(void)
261 /*****************************************************************************
264 Return the width of the end-of-line cursor. This is a function
265 because eol_cursor_width is a device method.
266 ****************************************************************************/
267 static int gtk_eol_cursor_width(void)
269 return EOL_CURSOR_WIDTH;
272 /*****************************************************************************
273 gtk_output_display_block
275 Given a display line, a block number for that start line, output all
276 runes between start and end in the specified display block.
277 ****************************************************************************/
279 gtk_output_display_block(struct window *w, struct display_line *dl, int block,
280 int start, int end, int start_pixpos, int cursor_start,
281 int cursor_width, int cursor_height)
283 struct frame *f = XFRAME(w->frame);
284 Emchar_dynarr *buf = NULL;
287 struct display_block *db = Dynarr_atp(dl->display_blocks, block);
288 rune_dynarr *rba = db->runes;
294 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
295 MULE is not defined */
297 XSETWINDOW(window, w);
298 rb = Dynarr_atp(rba, start);
301 /* Nothing to do so don't do anything. */
307 if (rb->type == RUNE_CHAR)
308 charset = CHAR_CHARSET(rb->object.chr.ch);
312 end = Dynarr_length(rba);
313 buf = Dynarr_new(Emchar);
316 rb = Dynarr_atp(rba, elt);
318 if (rb->findex == findex && rb->type == RUNE_CHAR
319 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
320 && EQ(charset, CHAR_CHARSET(rb->object.chr.ch))) {
321 Dynarr_add(buf, rb->object.chr.ch);
325 if (Dynarr_length(buf)) {
326 gtk_output_string(w, dl, buf, xpos, 0,
327 start_pixpos, width, findex,
328 0, cursor_start, cursor_width,
336 if (rb->type == RUNE_CHAR) {
339 charset = CHAR_CHARSET(rb->object.chr.ch);
341 if (rb->cursor_type == CURSOR_ON) {
342 if (rb->object.chr.ch == '\n') {
343 gtk_output_eol_cursor(w, dl,
349 gtk_output_string(w, dl, buf,
362 } else if (rb->object.chr.ch == '\n') {
363 /* Clear in case a cursor was formerly here. */
365 dl->ascent + dl->descent - dl->clip;
367 redisplay_clear_region(window, findex,
375 } else if (rb->type == RUNE_BLANK
376 || rb->type == RUNE_HLINE) {
377 if (rb->type == RUNE_BLANK)
378 gtk_output_blank(w, dl, rb,
383 /* #### Our flagging of when we need to redraw the
384 modeline shadows sucks. Since RUNE_HLINE is only used
385 by the modeline at the moment it is a good bet
386 that if it gets redrawn then we should also
387 redraw the shadows. This won't be true forever.
388 We borrow the shadow_thickness_changed flag for
390 w->shadow_thickness_changed = 1;
391 gtk_output_hline(w, dl, rb);
396 rb = Dynarr_atp(rba, elt);
401 } else if (rb->type == RUNE_DGLYPH) {
402 Lisp_Object instance;
403 struct display_box dbox;
404 struct display_glyph_area dga;
405 redisplay_calculate_display_boxes(dl, rb->xpos,
416 XSETWINDOW(window, w);
418 glyph_image_instance(rb->object.dglyph.
423 if (IMAGE_INSTANCEP(instance))
424 switch (XIMAGE_INSTANCE_TYPE(instance)) {
427 /* #### This is way losing. See the comment in
430 XIMAGE_INSTANCE_TEXT_STRING
432 convert_bufbyte_string_into_emchar_dynarr
438 gtk_output_string(w, dl,
459 case IMAGE_MONO_PIXMAP:
460 case IMAGE_COLOR_PIXMAP:
461 gtk_output_pixmap(w, dl,
480 (XIMAGE_INSTANCE_WIDGET_TYPE
481 (instance), Qlayout)) {
482 redisplay_output_layout
492 case IMAGE_SUBWINDOW:
493 redisplay_output_subwindow(w,
504 /* nothing is as nothing does */
518 if (Dynarr_length(buf))
519 gtk_output_string(w, dl, buf, xpos, 0, start_pixpos, width,
520 findex, 0, cursor_start, cursor_width,
523 /* #### This is really conditionalized well for optimized
525 if (dl->modeline && !EQ(Qzero, w->modeline_shadow_thickness)
527 || f->windows_structure_changed || w->shadow_thickness_changed))
528 gtk_bevel_modeline(w, dl);
533 /*****************************************************************************
536 Draw a 3d border around the modeline on window W.
537 ****************************************************************************/
538 static void gtk_bevel_modeline(struct window *w, struct display_line *dl)
540 struct frame *f = XFRAME(w->frame);
541 int shadow_thickness = MODELINE_SHADOW_THICKNESS(w);
542 int x, y, width, height;
544 x = WINDOW_MODELINE_LEFT(w);
545 width = WINDOW_MODELINE_RIGHT(w) - x;
546 y = dl->ypos - dl->ascent - shadow_thickness;
547 height = dl->ascent + dl->descent + 2 * shadow_thickness;
549 gtk_output_shadows(f, x, y, width, height, shadow_thickness);
552 /*****************************************************************************
555 Given a number of parameters return a GC with those properties.
556 ****************************************************************************/
557 GdkGC *gtk_get_gc(struct device *d, Lisp_Object font, Lisp_Object fg,
558 Lisp_Object bg, Lisp_Object bg_pmap, Lisp_Object lwidth)
563 memset(&gcv, ~0, sizeof(gcv));
564 gcv.graphics_exposures = FALSE;
565 /* Make absolutely sure that we don't pick up a clipping region in
566 the GC returned by this function. */
568 gcv.clip_x_origin = 0;
569 gcv.clip_y_origin = 0;
570 gcv.fill = GDK_SOLID;
572 GDK_GC_EXPOSURES | GDK_GC_CLIP_MASK | GDK_GC_CLIP_X_ORIGIN |
573 GDK_GC_CLIP_Y_ORIGIN;
577 gcv.font = FONT_INSTANCE_GTK_FONT(XFONT_INSTANCE(font));
582 if (!NILP(fg) && !COLOR_INSTANCEP(fg) && !INTP(fg)) {
583 /* #### I fixed once case where this was getting it. It was a
584 bad macro expansion (compiler bug). */
585 fprintf(stderr, "Help! gtk_get_gc got a bogus fg value! fg = ");
591 if (COLOR_INSTANCEP(fg))
593 *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(fg));
595 gcv.foreground.pixel = XINT(fg);
596 mask |= GDK_GC_FOREGROUND;
600 if (COLOR_INSTANCEP(bg))
602 *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(bg));
604 gcv.background.pixel = XINT(fg);
605 mask |= GDK_GC_BACKGROUND;
608 if (IMAGE_INSTANCEP(bg_pmap)
609 && IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(bg_pmap))) {
610 if (XIMAGE_INSTANCE_PIXMAP_DEPTH(bg_pmap) == 0) {
611 gcv.fill = GDK_OPAQUE_STIPPLED;
612 gcv.stipple = XIMAGE_INSTANCE_GTK_PIXMAP(bg_pmap);
613 mask |= (GDK_GC_STIPPLE | GDK_GC_FILL);
615 gcv.fill = GDK_TILED;
616 gcv.tile = XIMAGE_INSTANCE_GTK_PIXMAP(bg_pmap);
617 mask |= (GDK_GC_TILE | GDK_GC_FILL);
622 gcv.line_width = XINT(lwidth);
623 mask |= GDK_GC_LINE_WIDTH;
626 return gc_cache_lookup(DEVICE_GTK_GC_CACHE(d), &gcv, mask);
629 /*****************************************************************************
632 Given a string and a starting position, output that string in the
633 given face. If cursor is true, draw a cursor around the string.
634 Correctly handles multiple charsets in the string.
636 The meaning of the parameters is something like this:
638 W Window that the text is to be displayed in.
639 DL Display line that this text is on. The values in the
640 structure are used to determine the vertical position and
641 clipping range of the text.
642 BUF Dynamic array of Emchars specifying what is actually to be
644 XPOS X position in pixels where the text should start being drawn.
645 XOFFSET Number of pixels to be chopped off the left side of the
646 text. The effect is as if the text were shifted to the
647 left this many pixels and clipped at XPOS.
648 CLIP_START Clip everything left of this X position.
649 WIDTH Clip everything right of XPOS + WIDTH.
650 FINDEX Index for the face cache element describing how to display
652 CURSOR #### I don't understand this. There's something
653 strange and overcomplexified with this variable.
654 Chuck, explain please?
655 CURSOR_START Starting X position of cursor.
656 CURSOR_WIDTH Width of cursor in pixels.
657 CURSOR_HEIGHT Height of cursor in pixels.
659 Starting Y position of cursor is the top of the text line.
660 The cursor is drawn sometimes whether or not CURSOR is set. ???
661 ****************************************************************************/
663 gdk_draw_text_image(GdkDrawable * drawable,
666 gint x, gint y, const gchar * text, gint text_length);
669 gtk_output_string(struct window *w, struct display_line *dl,
670 Emchar_dynarr * buf, int xpos, int xoffset, int clip_start,
671 int width, face_index findex, int cursor,
672 int cursor_start, int cursor_width, int cursor_height)
674 /* General variables */
675 struct frame *f = XFRAME(w->frame);
676 struct device *d = XDEVICE(f->device);
679 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
683 /* Cursor-related variables */
684 int focus = EQ(w->frame, DEVICE_FRAME_WITH_FOCUS_REAL(d));
686 Lisp_Object bar_cursor_value = symbol_value_in_buffer(Qbar_cursor,
688 struct face_cachel *cursor_cachel = 0;
690 /* Text-related variables */
694 int len = Dynarr_length(buf);
695 unsigned char *text_storage = (unsigned char *)alloca(2 * len);
696 struct textual_run *runs = alloca_array(struct textual_run, len);
699 struct face_cachel *cachel = WINDOW_FACE_CACHEL(w, findex);
701 XSETDEVICE(device, d);
702 XSETWINDOW(window, w);
706 gtk_text_width(f, cachel, Dynarr_atp(buf, 0),
708 height = dl->ascent + dl->descent - dl->clip;
710 /* Regularize the variables passed in. */
712 if (clip_start < xpos)
714 clip_end = xpos + width;
715 if (clip_start >= clip_end)
716 /* It's all clipped out. */
721 nruns = separate_textual_runs(text_storage, runs, Dynarr_atp(buf, 0),
724 cursor_clip = (cursor_start >= clip_start && cursor_start < clip_end);
726 /* This cursor code is really a mess. */
727 if (!NILP(w->text_cursor_visible_p)
730 || (cursor_width && (cursor_start + cursor_width >= clip_start)
731 && !NILP(bar_cursor_value)))) {
732 /* These have to be in separate statements in order to avoid a
735 get_builtin_face_cache_index(w, Vtext_cursor_face);
736 cursor_cachel = WINDOW_FACE_CACHEL(w, sucks);
738 /* We have to reset this since any call to WINDOW_FACE_CACHEL
739 may cause the cache to resize and any pointers to it to
741 cachel = WINDOW_FACE_CACHEL(w, findex);
744 bg_pmap = cachel->background_pixmap;
745 if (!IMAGE_INSTANCEP(bg_pmap)
746 || !IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(bg_pmap)))
749 if ((cursor && focus && NILP(bar_cursor_value)
750 && !NILP(w->text_cursor_visible_p)) || NILP(bg_pmap))
754 gtk_get_gc(d, Qnil, cachel->foreground, cachel->background,
758 gdk_draw_rectangle(GDK_DRAWABLE(x_win), bgc, TRUE, clip_start,
759 dl->ypos - dl->ascent, clip_end - clip_start,
762 for (i = 0; i < nruns; i++) {
763 Lisp_Object font = FACE_CACHEL_FONT(cachel, runs[i].charset);
764 struct Lisp_Font_Instance *fi = XFONT_INSTANCE(font);
765 GdkFont *gdk_font = FONT_INSTANCE_GTK_FONT(fi);
769 if (EQ(font, Vthe_null_font_instance))
772 this_width = gtk_text_width_single_run(cachel, runs + i);
773 need_clipping = (dl->clip || clip_start > xpos ||
774 clip_end < xpos + this_width);
776 /* XDrawImageString only clears the area equal to the height of
777 the given font. It is possible that a font is being displayed
778 on a line taller than it is, so this would cause us to fail to
780 if ((int)fi->height < (int)(height + dl->clip)) {
781 int clear_start = max(xpos, clip_start);
782 int clear_end = min(xpos + this_width, clip_end);
785 int ypos1_line, ypos1_string, ypos2_line,
788 ypos1_string = dl->ypos - fi->ascent;
789 ypos2_string = dl->ypos + fi->descent;
790 ypos1_line = dl->ypos - dl->ascent;
791 ypos2_line = dl->ypos + dl->descent - dl->clip;
793 /* Make sure we don't clear below the real bottom of the
795 if (ypos1_string > ypos2_line)
796 ypos1_string = ypos2_line;
797 if (ypos2_string > ypos2_line)
798 ypos2_string = ypos2_line;
800 if (ypos1_line < ypos1_string) {
801 redisplay_clear_region(window, findex,
810 if (ypos2_line > ypos2_string) {
811 redisplay_clear_region(window, findex,
820 redisplay_clear_region(window, findex,
822 dl->ypos - dl->ascent,
823 clear_end - clear_start,
828 if (cursor && cursor_cachel && focus && NILP(bar_cursor_value)) {
829 gc = gtk_get_gc(d, font, cursor_cachel->foreground,
830 cursor_cachel->background, Qnil, Qnil);
832 gc = gtk_get_gc(d, font, cachel->foreground,
833 cachel->background, Qnil, Qnil);
837 GdkRectangle clip_box;
841 clip_box.width = clip_end - clip_start;
842 clip_box.height = height;
844 gdk_gc_set_clip_rectangle(gc, &clip_box);
845 gdk_gc_set_clip_origin(gc, clip_start,
846 dl->ypos - dl->ascent);
849 /* The X specific called different functions (XDraw*String
850 vs. XDraw*String16), but apparently gdk_draw_text takes care
853 BUT, gdk_draw_text also does too much, by dividing the length
854 by 2. So we fake them out my multiplying the length by the
855 dimension of the text. This will do the right thing for
856 single-dimension runs as well of course.
858 (bgc ? gdk_draw_text :
859 gdk_draw_text_image) (GDK_DRAWABLE(x_win), gdk_font, gc, xpos,
860 dl->ypos, (char *)runs[i].ptr,
861 runs[i].len * runs[i].dimension);
863 /* We draw underlines in the same color as the text. */
864 if (cachel->underline) {
865 unsigned long upos, uthick;
867 /* Cannot get at font properties in Gtk, so we resort to
869 upos = dl->descent / 2;
872 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip) {
873 if (dl->ypos + upos + uthick >
874 dl->ypos + dl->descent - dl->clip)
875 uthick = dl->descent - dl->clip - upos;
878 gdk_draw_line(GDK_DRAWABLE(x_win), gc,
879 xpos, dl->ypos + upos,
882 } else if (uthick > 1) {
883 gdk_draw_rectangle(GDK_DRAWABLE(x_win),
891 if (cachel->strikethru) {
892 unsigned long ascent, descent, upos, uthick;
894 FONT_INSTANCE_GTK_FONT(XFONT_INSTANCE(font));
896 /* Cannot get at font properties in Gtk, so we resort to
899 ascent = gfont->ascent;
900 descent = gfont->descent;
903 upos = ascent - ((ascent + descent) / 2) + 1;
905 /* Generally, upos will be positive (above the baseline),so subtract */
906 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip) {
907 if (dl->ypos - upos + uthick >
908 dl->ypos + dl->descent - dl->clip)
909 uthick = dl->descent - dl->clip + upos;
912 gdk_draw_line(GDK_DRAWABLE(x_win), gc,
913 xpos, dl->ypos - upos,
916 } else if (uthick > 1) {
917 gdk_draw_rectangle(GDK_DRAWABLE(x_win),
927 gdk_gc_set_clip_rectangle(gc, NULL);
928 gdk_gc_set_clip_origin(gc, 0, 0);
931 /* If we are actually superimposing the cursor then redraw with just
932 the appropriate section highlighted. */
933 if (cursor_clip && !cursor && focus && cursor_cachel) {
935 GdkRectangle clip_box;
937 cgc = gtk_get_gc(d, font, cursor_cachel->foreground,
938 cursor_cachel->background, Qnil, Qnil);
942 clip_box.width = cursor_width;
943 clip_box.height = height;
945 gdk_gc_set_clip_rectangle(cgc, &clip_box);
946 gdk_gc_set_clip_origin(cgc, cursor_start,
947 dl->ypos - dl->ascent);
949 /* The X specific called different functions (XDraw*String
950 vs. XDraw*String16), but apparently gdk_draw_text takes care
953 BUT, gdk_draw_text also does too much, by dividing the
954 length by 2. So we fake them out my multiplying the
955 length by the dimension of the text. This will do the
956 right thing for single-dimension runs as well of course.
958 gdk_draw_text_image(GDK_DRAWABLE(x_win), gdk_font, cgc,
959 xpos, dl->ypos, (char *)runs[i].ptr,
960 runs[i].len * runs[i].dimension);
962 gdk_gc_set_clip_rectangle(cgc, NULL);
963 gdk_gc_set_clip_origin(cgc, 0, 0);
969 /* Draw the non-focus box or bar-cursor as needed. */
970 /* Can't this logic be simplified? */
971 if (cursor_cachel && ((cursor && !focus && NILP(bar_cursor_value))
973 && (cursor_start + cursor_width >= clip_start)
974 && !NILP(bar_cursor_value)))) {
975 int tmp_height, tmp_y;
976 int bar_width = EQ(bar_cursor_value, Qt) ? 1 : 2;
977 int need_clipping = (cursor_start < clip_start
978 || clip_end < cursor_start + cursor_width);
980 /* #### This value is correct (as far as I know) because
981 all of the times we need to draw this cursor, we will
982 be called with exactly one character, so we know we
983 can always use runs[0].
985 This is bogus as all hell, however. The cursor handling in
986 this function is way bogus and desperately needs to be
987 cleaned up. (In particular, the drawing of the cursor should
988 really really be separated out of this function. This may be
989 a bit tricky now because this function itself does way too
990 much stuff, a lot of which needs to be moved into
991 redisplay.c) This is the only way to be able to easily add
992 new cursor types or (e.g.) make the bar cursor be able to
993 span two characters instead of overlaying just one. */
994 int bogusly_obtained_ascent_value =
995 XFONT_INSTANCE(FACE_CACHEL_FONT(cachel, runs[0].charset))->
998 if (!NILP(bar_cursor_value)) {
999 gc = gtk_get_gc(d, Qnil, cursor_cachel->background,
1000 Qnil, Qnil, make_int(bar_width));
1002 gc = gtk_get_gc(d, Qnil, cursor_cachel->background,
1006 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1007 tmp_height = cursor_height;
1008 if (tmp_y + tmp_height > (int)(dl->ypos - dl->ascent + height)) {
1009 tmp_y = dl->ypos - dl->ascent + height - tmp_height;
1010 if (tmp_y < (int)(dl->ypos - dl->ascent))
1011 tmp_y = dl->ypos - dl->ascent;
1012 tmp_height = dl->ypos - dl->ascent + height - tmp_y;
1015 if (need_clipping) {
1016 GdkRectangle clip_box;
1019 clip_box.width = clip_end - clip_start;
1020 clip_box.height = tmp_height;
1022 gdk_gc_set_clip_rectangle(gc, &clip_box);
1023 gdk_gc_set_clip_origin(gc, clip_start, tmp_y);
1026 if (!focus && NILP(bar_cursor_value)) {
1027 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, FALSE,
1028 cursor_start, tmp_y,
1029 cursor_width - 1, tmp_height - 1);
1030 } else if (focus && !NILP(bar_cursor_value)) {
1031 gdk_draw_line(GDK_DRAWABLE(x_win), gc,
1032 cursor_start + bar_width - 1, tmp_y,
1033 cursor_start + bar_width - 1,
1034 tmp_y + tmp_height - 1);
1037 /* Restore the GC */
1038 if (need_clipping) {
1039 gdk_gc_set_clip_rectangle(gc, NULL);
1040 gdk_gc_set_clip_origin(gc, 0, 0);
1046 our_draw_bitmap(GdkDrawable * drawable,
1050 gint ysrc, gint xdest, gint ydest, gint width, gint height);
1053 gtk_output_gdk_pixmap(struct frame *f, struct Lisp_Image_Instance *p, int x,
1054 int y, int clip_x, int clip_y, int clip_width,
1055 int clip_height, int width, int height, int pixmap_offset,
1056 GdkColor * fg, GdkColor * bg, GdkGC * override_gc)
1058 struct device *d = XDEVICE(f->device);
1059 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1063 unsigned long pixmap_mask;
1064 int need_clipping = (clip_x || clip_y);
1067 memset(&gcv, ~0, sizeof(gcv));
1068 gcv.graphics_exposures = FALSE;
1069 gcv.foreground = *fg;
1070 gcv.background = *bg;
1072 GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_EXPOSURES;
1074 if (IMAGE_INSTANCE_GTK_MASK(p)) {
1075 gcv.function = GDK_COPY;
1076 gcv.clip_mask = IMAGE_INSTANCE_GTK_MASK(p);
1077 gcv.clip_x_origin = x;
1078 gcv.clip_y_origin = y - pixmap_offset;
1080 (GDK_GC_FUNCTION | GDK_GC_CLIP_MASK |
1081 GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
1082 /* Can't set a clip rectangle below because we already have a mask.
1083 We could conceivably create a new clipmask by zeroing out
1084 everything outside the clip region. Is it worth it?
1085 Is it possible to get an equivalent effect by changing the
1086 args to XCopyArea below rather than messing with a clip box?
1087 - dkindred@cs.cmu.edu */
1091 gc = gc_cache_lookup(DEVICE_GTK_GC_CACHE(d), &gcv, pixmap_mask);
1094 /* override_gc might have a mask already--we don't want to nuke it.
1095 Maybe we can insist that override_gc have no mask, or use
1096 one of the suggestions above. */
1100 if (need_clipping) {
1101 GdkRectangle clip_box;
1103 clip_box.x = clip_x;
1104 clip_box.y = clip_y;
1105 clip_box.width = clip_width;
1106 clip_box.height = clip_height;
1108 gdk_gc_set_clip_rectangle(gc, &clip_box);
1109 gdk_gc_set_clip_origin(gc, x, y);
1112 if (IMAGE_INSTANCE_PIXMAP_DEPTH(p) > 0) {
1113 gdk_draw_pixmap(GDK_DRAWABLE(x_win), gc,
1114 IMAGE_INSTANCE_GTK_PIXMAP(p),
1115 0, pixmap_offset, x, y, width, height);
1117 our_draw_bitmap(GDK_DRAWABLE(x_win), gc,
1118 IMAGE_INSTANCE_GTK_PIXMAP(p),
1119 0, pixmap_offset, x, y, width, height);
1122 if (need_clipping) {
1123 gdk_gc_set_clip_rectangle(gc, NULL);
1124 gdk_gc_set_clip_origin(gc, 0, 0);
1129 gtk_output_pixmap(struct window *w, struct display_line *dl,
1130 Lisp_Object image_instance, int xpos, int xoffset,
1131 int start_pixpos, int width, face_index findex,
1132 int cursor_start, int cursor_width, int cursor_height)
1134 struct frame *f = XFRAME(w->frame);
1135 struct device *d = XDEVICE(f->device);
1136 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
1139 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1140 int lheight = dl->ascent + dl->descent - dl->clip;
1142 ((int)IMAGE_INSTANCE_PIXMAP_HEIGHT(p) >
1143 lheight ? lheight : IMAGE_INSTANCE_PIXMAP_HEIGHT(p));
1144 int pwidth = min(width + xoffset, (int)IMAGE_INSTANCE_PIXMAP_WIDTH(p));
1145 int clip_x, clip_y, clip_width, clip_height;
1147 /* The pixmap_offset is used to center the pixmap on lines which are
1148 shorter than it is. This results in odd effects when scrolling
1149 pixmaps off of the bottom. Let's try not using it. */
1152 (int)(IMAGE_INSTANCE_PIXMAP_HEIGHT(p) - lheight) / 2;
1154 int pixmap_offset = 0;
1157 XSETWINDOW(window, w);
1159 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset) {
1160 if (start_pixpos > xpos && start_pixpos > xpos + width)
1165 if (start_pixpos > xpos) {
1166 clip_x += (start_pixpos - xpos);
1167 clip_width -= (start_pixpos - xpos);
1174 /* Place markers for possible future functionality (clipping the top
1175 half instead of the bottom half; think pixel scrolling). */
1177 clip_height = pheight;
1179 /* Clear the area the pixmap is going into. The pixmap itself will
1180 always take care of the full width. We don't want to clear where
1181 it is going to go in order to avoid flicker. So, all we have to
1182 take care of is any area above or below the pixmap. */
1183 /* #### We take a shortcut for now. We know that since we have
1184 pixmap_offset hardwired to 0 that the pixmap is against the top
1185 edge so all we have to worry about is below it. */
1186 /* #### Unless the pixmap has a mask in which case we have to clear
1187 the whole damn thing since we can't yet clear just the area not
1188 included in the mask. */
1189 if (((int)(dl->ypos - dl->ascent + pheight) <
1190 (int)(dl->ypos + dl->descent - dl->clip))
1191 || IMAGE_INSTANCE_GTK_MASK(p)) {
1192 int clear_x, clear_y, clear_width, clear_height;
1194 if (IMAGE_INSTANCE_GTK_MASK(p)) {
1195 clear_y = dl->ypos - dl->ascent;
1196 clear_height = lheight;
1198 clear_y = dl->ypos - dl->ascent + pheight;
1199 clear_height = lheight - pheight;
1202 if (start_pixpos >= 0 && start_pixpos > xpos) {
1203 clear_x = start_pixpos;
1204 clear_width = xpos + width - start_pixpos;
1207 clear_width = width;
1210 redisplay_clear_region(window, findex, clear_x, clear_y,
1211 clear_width, clear_height);
1214 /* Output the pixmap. */
1216 Lisp_Object tmp_pixel;
1217 GdkColor *tmp_bcolor, *tmp_fcolor;
1219 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND(w, findex);
1221 COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(tmp_pixel));
1222 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND(w, findex);
1224 COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(tmp_pixel));
1226 gtk_output_gdk_pixmap(f, p, xpos - xoffset,
1227 dl->ypos - dl->ascent, clip_x, clip_y,
1228 clip_width, clip_height, pwidth, pheight,
1229 pixmap_offset, tmp_fcolor, tmp_bcolor, 0);
1232 /* Draw a cursor over top of the pixmap. */
1233 if (cursor_width && cursor_height && (cursor_start >= xpos)
1234 && !NILP(w->text_cursor_visible_p)
1235 && (cursor_start < xpos + pwidth)) {
1237 int focus = EQ(w->frame, DEVICE_FRAME_WITH_FOCUS_REAL(d));
1238 int y = dl->ypos - dl->ascent;
1239 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL(w,
1240 get_builtin_face_cache_index
1242 Vtext_cursor_face));
1244 gc = gtk_get_gc(d, Qnil, cursor_cachel->background, Qnil, Qnil,
1247 if (cursor_width > xpos + pwidth - cursor_start)
1248 cursor_width = xpos + pwidth - cursor_start;
1250 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc,
1251 focus ? TRUE : FALSE, cursor_start, y,
1252 cursor_width, cursor_height);
1256 /*****************************************************************************
1257 gtk_output_vertical_divider
1259 Draw a vertical divider down the right side of the given window.
1260 ****************************************************************************/
1261 static void gtk_output_vertical_divider(struct window *w, int clear)
1263 struct frame *f = XFRAME(w->frame);
1264 struct device *d = XDEVICE(f->device);
1265 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1266 GdkGC *background_gc;
1267 Lisp_Object tmp_pixel;
1270 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1271 face_index div_face =
1272 get_builtin_face_cache_index(w, Vvertical_divider_face);
1274 width = window_divider_width(w);
1275 shadow_thickness = XINT(w->vertical_divider_shadow_thickness);
1276 spacing = XINT(w->vertical_divider_spacing);
1277 line_width = XINT(w->vertical_divider_line_width);
1278 x = WINDOW_RIGHT(w) - width;
1280 y2 = WINDOW_BOTTOM(w);
1282 memset(&gcv, ~0, sizeof(gcv));
1284 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND(w, div_face);
1286 gcv.background = *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(tmp_pixel));
1287 gcv.foreground = gcv.background;
1288 gcv.graphics_exposures = FALSE;
1289 mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_EXPOSURES;
1291 background_gc = gc_cache_lookup(DEVICE_GTK_GC_CACHE(d), &gcv, mask);
1293 /* Clear the divider area first. This needs to be done when a
1294 window split occurs. */
1296 gdk_draw_rectangle(GDK_DRAWABLE(x_win), background_gc, TRUE,
1297 x, y1, width, y2 - y1);
1300 /* Draw the divider line. */
1301 gdk_draw_rectangle(GDK_DRAWABLE(x_win), background_gc, TRUE,
1302 x + spacing + shadow_thickness, y1,
1303 line_width, y2 - y1);
1306 /* Draw the shadows around the divider line */
1307 gtk_output_shadows(f, x + spacing, y1,
1308 width - 2 * spacing, y2 - y1, shadow_thickness);
1311 /*****************************************************************************
1314 Output a blank by clearing the area it covers in the foreground color
1316 ****************************************************************************/
1318 gtk_output_blank(struct window *w, struct display_line *dl, struct rune *rb,
1319 int start_pixpos, int cursor_start, int cursor_width)
1321 struct frame *f = XFRAME(w->frame);
1322 struct device *d = XDEVICE(f->device);
1324 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1326 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL(w,
1327 get_builtin_face_cache_index
1329 Vtext_cursor_face));
1330 Lisp_Object bg_pmap;
1331 Lisp_Object buffer = WINDOW_BUFFER(w);
1332 Lisp_Object bar_cursor_value = symbol_value_in_buffer(Qbar_cursor,
1336 int y = dl->ypos - dl->ascent;
1337 int width = rb->width;
1338 int height = dl->ascent + dl->descent - dl->clip;
1340 if (start_pixpos > x) {
1341 if (start_pixpos >= (x + width))
1344 width -= (start_pixpos - x);
1349 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP(w, rb->findex);
1350 if (!IMAGE_INSTANCEP(bg_pmap)
1351 || !IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(bg_pmap)))
1355 gc = gtk_get_gc(d, Qnil,
1356 WINDOW_FACE_CACHEL_BACKGROUND(w, rb->findex),
1359 gc = gtk_get_gc(d, Qnil,
1360 WINDOW_FACE_CACHEL_FOREGROUND(w, rb->findex),
1361 WINDOW_FACE_CACHEL_BACKGROUND(w, rb->findex),
1364 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, TRUE, x, y, width, height);
1366 /* If this rune is marked as having the cursor, then it is actually
1367 representing a tab. */
1368 if (!NILP(w->text_cursor_visible_p)
1369 && (rb->cursor_type == CURSOR_ON
1370 || (cursor_width && (cursor_start + cursor_width > x)
1371 && cursor_start < (x + width)))) {
1372 int cursor_height, cursor_y;
1373 int focus = EQ(w->frame, DEVICE_FRAME_WITH_FOCUS_REAL(d));
1374 struct Lisp_Font_Instance *fi;
1376 fi = XFONT_INSTANCE(FACE_CACHEL_FONT
1377 (WINDOW_FACE_CACHEL(w, rb->findex),
1380 gc = gtk_get_gc(d, Qnil, cursor_cachel->background, Qnil, Qnil,
1383 cursor_y = dl->ypos - fi->ascent;
1384 cursor_height = fi->height;
1385 if (cursor_y + cursor_height > y + height)
1386 cursor_height = y + height - cursor_y;
1389 if (NILP(bar_cursor_value)) {
1390 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc,
1391 TRUE, cursor_start, cursor_y,
1392 fi->width, cursor_height);
1395 EQ(bar_cursor_value, Qt) ? 1 : 2;
1397 gc = gtk_get_gc(d, Qnil,
1398 cursor_cachel->background, Qnil,
1399 Qnil, make_int(bar_width));
1400 gdk_draw_line(GDK_DRAWABLE(x_win), gc,
1401 cursor_start + bar_width - 1,
1403 cursor_start + bar_width - 1,
1404 cursor_y + cursor_height - 1);
1406 } else if (NILP(bar_cursor_value)) {
1407 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, FALSE,
1408 cursor_start, cursor_y,
1409 fi->width - 1, cursor_height - 1);
1414 /*****************************************************************************
1417 Output a horizontal line in the foreground of its face.
1418 ****************************************************************************/
1420 gtk_output_hline(struct window *w, struct display_line *dl, struct rune *rb)
1422 struct frame *f = XFRAME(w->frame);
1423 struct device *d = XDEVICE(f->device);
1424 GtkStyle *style = FRAME_GTK_TEXT_WIDGET(f)->style;
1426 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1430 int width = rb->width;
1431 int height = dl->ascent + dl->descent - dl->clip;
1433 int ypos1, ypos2, ypos3, ypos4;
1435 ypos1 = dl->ypos - dl->ascent;
1436 ypos2 = ypos1 + rb->object.hline.yoffset;
1437 ypos3 = ypos2 + rb->object.hline.thickness;
1438 ypos4 = dl->ypos + dl->descent - dl->clip;
1440 /* First clear the area not covered by the line. */
1441 if (height - rb->object.hline.thickness > 0) {
1442 gc = gtk_get_gc(d, Qnil,
1443 WINDOW_FACE_CACHEL_FOREGROUND(w, rb->findex),
1446 if (ypos2 - ypos1 > 0)
1447 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, TRUE, x,
1448 ypos1, width, ypos2 - ypos1);
1449 if (ypos4 - ypos3 > 0)
1450 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, TRUE, x,
1451 ypos1, width, ypos2 - ypos1);
1454 gtk_paint_hline(style, x_win, GTK_STATE_NORMAL, NULL,
1455 FRAME_GTK_TEXT_WIDGET(f), "hline", x, x + width, ypos2);
1457 /* Now draw the line. */
1458 gc = gtk_get_gc(d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND(w, rb->findex),
1466 if (ypos3 - ypos2 > 0)
1467 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, TRUE, x, ypos2,
1468 width, ypos3 - ypos2);
1472 /*****************************************************************************
1475 Draw a shadow around the given area using the standard theme engine routines.
1476 ****************************************************************************/
1478 gtk_output_shadows(struct frame *f, int x, int y, int width, int height,
1479 int shadow_thickness)
1481 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1482 GtkStyle *style = FRAME_GTK_TEXT_WIDGET(f)->style;
1483 GtkShadowType stype = GTK_SHADOW_OUT;
1485 if (shadow_thickness < 0) {
1486 stype = GTK_SHADOW_IN;
1487 } else if (shadow_thickness == 0) {
1488 stype = GTK_SHADOW_NONE;
1491 /* Do we want to have some magic constants to set
1492 GTK_SHADOW_ETCHED_IN or GTK_SHADOW_ETCHED_OUT? */
1494 gtk_paint_shadow(style, x_win, GTK_STATE_NORMAL, stype, NULL,
1495 FRAME_GTK_TEXT_WIDGET(f), "modeline",
1496 x, y, width, height);
1499 /*****************************************************************************
1500 gtk_clear_to_window_end
1502 Clear the area between ypos1 and ypos2. Each margin area and the
1503 text area is handled separately since they may each have their own
1505 ****************************************************************************/
1506 static void gtk_clear_to_window_end(struct window *w, int ypos1, int ypos2)
1508 int height = ypos2 - ypos1;
1511 struct frame *f = XFRAME(w->frame);
1513 int bflag = (window_needs_vertical_divider(w) ? 0 : 1);
1514 layout_bounds bounds;
1516 bounds = calculate_display_line_boundaries(w, bflag);
1517 XSETWINDOW(window, w);
1519 if (window_is_leftmost(w))
1520 redisplay_clear_region(window, DEFAULT_INDEX,
1521 FRAME_LEFT_BORDER_START(f),
1522 ypos1, FRAME_BORDER_WIDTH(f),
1525 if (bounds.left_in - bounds.left_out > 0)
1526 redisplay_clear_region(window,
1527 get_builtin_face_cache_index(w,
1529 bounds.left_out, ypos1,
1530 bounds.left_in - bounds.left_out,
1533 if (bounds.right_in - bounds.left_in > 0)
1534 redisplay_clear_region(window, DEFAULT_INDEX,
1535 bounds.left_in, ypos1,
1536 bounds.right_in - bounds.left_in,
1539 if (bounds.right_out - bounds.right_in > 0)
1540 redisplay_clear_region(window,
1541 get_builtin_face_cache_index(w,
1542 Vright_margin_face),
1543 bounds.right_in, ypos1,
1545 bounds.right_in, height);
1547 if (window_is_rightmost(w))
1548 redisplay_clear_region(window, DEFAULT_INDEX,
1549 FRAME_RIGHT_BORDER_START(f),
1550 ypos1, FRAME_BORDER_WIDTH(f),
1555 /*****************************************************************************
1556 gtk_redraw_exposed_window
1558 Given a bounding box for an area that needs to be redrawn, determine
1559 what parts of what lines are contained within and re-output their
1561 ****************************************************************************/
1563 gtk_redraw_exposed_window(struct window *w, int x, int y, int width, int height)
1565 struct frame *f = XFRAME(w->frame);
1567 int start_x, start_y, end_x, end_y;
1568 int orig_windows_structure_changed;
1570 display_line_dynarr *cdla = window_display_lines(w, CURRENT_DISP);
1572 if (!NILP(w->vchild)) {
1573 gtk_redraw_exposed_windows(w->vchild, x, y, width, height);
1575 } else if (!NILP(w->hchild)) {
1576 gtk_redraw_exposed_windows(w->hchild, x, y, width, height);
1580 /* If the window doesn't intersect the exposed region, we're done here. */
1581 if (x >= WINDOW_RIGHT(w) || (x + width) <= WINDOW_LEFT(w)
1582 || y >= WINDOW_BOTTOM(w) || (y + height) <= WINDOW_TOP(w)) {
1585 start_x = max(WINDOW_LEFT(w), x);
1586 end_x = min(WINDOW_RIGHT(w), (x + width));
1587 start_y = max(WINDOW_TOP(w), y);
1588 end_y = min(WINDOW_BOTTOM(w), y + height);
1590 /* We do this to make sure that the 3D modelines get redrawn if
1591 they are in the exposed region. */
1592 orig_windows_structure_changed = f->windows_structure_changed;
1593 f->windows_structure_changed = 1;
1596 if (window_needs_vertical_divider(w)) {
1597 gtk_output_vertical_divider(w, 0);
1600 for (line = 0; line < Dynarr_length(cdla); line++) {
1601 struct display_line *cdl = Dynarr_atp(cdla, line);
1602 int top_y = cdl->ypos - cdl->ascent;
1603 int bottom_y = cdl->ypos + cdl->descent;
1605 if (bottom_y >= start_y) {
1606 if (top_y > end_y) {
1612 output_display_line(w, 0, cdla, line, start_x,
1618 f->windows_structure_changed = orig_windows_structure_changed;
1620 /* If there have never been any face cache_elements created, then this
1621 expose event doesn't actually have anything to do. */
1622 if (Dynarr_largest(w->face_cachels))
1623 redisplay_clear_bottom_of_window(w, cdla, start_y, end_y);
1626 /*****************************************************************************
1627 gtk_redraw_exposed_windows
1629 For each window beneath the given window in the window hierarchy,
1630 ensure that it is redrawn if necessary after an Expose event.
1631 ****************************************************************************/
1633 gtk_redraw_exposed_windows(Lisp_Object window, int x, int y, int width,
1636 for (; !NILP(window); window = XWINDOW(window)->next)
1637 gtk_redraw_exposed_window(XWINDOW(window), x, y, width, height);
1640 /*****************************************************************************
1641 gtk_redraw_exposed_area
1643 For each window on the given frame, ensure that any area in the
1644 Exposed area is redrawn.
1645 ****************************************************************************/
1647 gtk_redraw_exposed_area(struct frame *f, int x, int y, int width, int height)
1649 /* If any window on the frame has had its face cache reset then the
1650 redisplay structures are effectively invalid. If we attempt to
1651 use them we'll blow up. We mark the frame as changed to ensure
1652 that redisplay will do a full update. This probably isn't
1653 necessary but it can't hurt. */
1655 #ifdef HAVE_TOOLBARS
1656 /* #### We would rather put these off as well but there is currently
1657 no combination of flags which will force an unchanged toolbar to
1659 MAYBE_FRAMEMETH(f, redraw_exposed_toolbars, (f, x, y, width, height));
1661 redraw_exposed_gutters(f, x, y, width, height);
1663 if (!f->window_face_cache_reset) {
1664 gtk_redraw_exposed_windows(f->root_window, x, y, width, height);
1666 MARK_FRAME_CHANGED(f);
1669 /****************************************************************************
1672 Clear the area in the box defined by the given parameters using the
1674 ****************************************************************************/
1676 gtk_clear_region(Lisp_Object locale, struct device *d, struct frame *f,
1677 face_index findex, int x, int y, int width, int height,
1678 Lisp_Object fcolor, Lisp_Object bcolor,
1679 Lisp_Object background_pixmap)
1684 x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1686 if (!UNBOUNDP(background_pixmap)) {
1687 gc = gtk_get_gc(d, Qnil, fcolor, bcolor, background_pixmap,
1692 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, TRUE,
1693 x, y, width, height);
1695 gdk_window_clear_area(x_win, x, y, width, height);
1699 /*****************************************************************************
1700 gtk_output_eol_cursor
1702 Draw a cursor at the end of a line. The end-of-line cursor is
1703 narrower than the normal cursor.
1704 ****************************************************************************/
1706 gtk_output_eol_cursor(struct window *w, struct display_line *dl, int xpos,
1709 struct frame *f = XFRAME(w->frame);
1710 struct device *d = XDEVICE(f->device);
1713 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1715 face_index elt = get_builtin_face_cache_index(w, Vtext_cursor_face);
1716 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL(w, elt);
1718 int focus = EQ(w->frame, DEVICE_FRAME_WITH_FOCUS_REAL(d));
1719 Lisp_Object bar_cursor_value = symbol_value_in_buffer(Qbar_cursor,
1723 int y = dl->ypos - dl->ascent;
1724 int width = EOL_CURSOR_WIDTH;
1725 int height = dl->ascent + dl->descent - dl->clip;
1726 int cursor_height, cursor_y;
1727 int defheight, defascent;
1729 XSETWINDOW(window, w);
1730 redisplay_clear_region(window, findex, x, y, width, height);
1732 if (NILP(w->text_cursor_visible_p))
1735 gc = gtk_get_gc(d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1737 default_face_font_info(window, &defascent, 0, &defheight, 0, 0);
1739 /* make sure the cursor is entirely contained between y and y+height */
1740 cursor_height = min(defheight, height);
1741 cursor_y = max(y, min(y + height - cursor_height,
1742 dl->ypos - defascent));
1745 if (NILP(bar_cursor_value)) {
1746 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, TRUE, x,
1747 cursor_y, width, cursor_height);
1749 int bar_width = EQ(bar_cursor_value, Qt) ? 1 : 2;
1751 gc = gtk_get_gc(d, Qnil, cursor_cachel->background,
1752 Qnil, Qnil, make_int(bar_width));
1753 gdk_draw_line(GDK_DRAWABLE(x_win), gc,
1754 x + bar_width - 1, cursor_y,
1756 cursor_y + cursor_height - 1);
1758 } else if (NILP(bar_cursor_value)) {
1759 gdk_draw_rectangle(GDK_DRAWABLE(x_win), gc, FALSE, x, cursor_y,
1760 width - 1, cursor_height - 1);
1764 static void gtk_clear_frame_window(Lisp_Object window)
1766 struct window *w = XWINDOW(window);
1768 if (!NILP(w->vchild)) {
1769 gtk_clear_frame_windows(w->vchild);
1773 if (!NILP(w->hchild)) {
1774 gtk_clear_frame_windows(w->hchild);
1778 gtk_clear_to_window_end(w, WINDOW_TEXT_TOP(w), WINDOW_TEXT_BOTTOM(w));
1781 static void gtk_clear_frame_windows(Lisp_Object window)
1783 for (; !NILP(window); window = XWINDOW(window)->next)
1784 gtk_clear_frame_window(window);
1787 static void gtk_clear_frame(struct frame *f)
1789 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f));
1790 int x, y, width, height;
1793 x = FRAME_LEFT_BORDER_START(f);
1794 width = (FRAME_PIXWIDTH(f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH(f) -
1795 FRAME_REAL_RIGHT_TOOLBAR_WIDTH(f) -
1796 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH(f) -
1797 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH(f));
1798 /* #### This adjustment by 1 should be being done in the macros.
1799 There is some small differences between when the menubar is on
1800 and off that we still need to deal with. */
1801 y = FRAME_TOP_BORDER_START(f) - 1;
1802 height = (FRAME_PIXHEIGHT(f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT(f) -
1803 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT(f) -
1804 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH(f) -
1805 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH(f)) + 1;
1807 gdk_window_clear_area(x_win, x, y, width, height);
1809 XSETFRAME(frame, f);
1811 if (!UNBOUNDP(FACE_BACKGROUND_PIXMAP(Vdefault_face, frame))
1812 || !UNBOUNDP(FACE_BACKGROUND_PIXMAP(Vleft_margin_face, frame))
1813 || !UNBOUNDP(FACE_BACKGROUND_PIXMAP(Vright_margin_face, frame))) {
1814 gtk_clear_frame_windows(f->root_window);
1818 static int gtk_flash(struct device *d)
1822 GdkColor tmp_fcolor, tmp_bcolor;
1823 Lisp_Object tmp_pixel, frame;
1824 struct frame *f = device_selected_frame(d);
1825 struct window *w = XWINDOW(FRAME_ROOT_WINDOW(f));
1827 XSETFRAME(frame, f);
1829 tmp_pixel = FACE_FOREGROUND(Vdefault_face, frame);
1830 tmp_fcolor = *(COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(tmp_pixel)));
1831 tmp_pixel = FACE_BACKGROUND(Vdefault_face, frame);
1832 tmp_bcolor = *(COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(tmp_pixel)));
1834 memset(&gcv, ~0, sizeof(gcv)); /* initialize all slots to ~0 */
1835 gcv.foreground.pixel = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1836 gcv.function = GDK_XOR;
1837 gcv.graphics_exposures = FALSE;
1838 gc = gc_cache_lookup(DEVICE_GTK_GC_CACHE(XDEVICE(f->device)), &gcv,
1839 GDK_GC_FOREGROUND | GDK_GC_FUNCTION |
1842 gdk_draw_rectangle(GDK_DRAWABLE
1843 (GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f))),
1844 gc, TRUE, w->pixel_left, w->pixel_top,
1845 w->pixel_width, w->pixel_height);
1851 #else /* !HAVE_POLL */
1856 tv.tv_sec = usecs / 1000000L;
1857 tv.tv_usec = usecs % 1000000L;
1858 /* I'm sure someone is going to complain about this... */
1859 select(0, 0, 0, 0, &tv);
1863 #endif /* HAVE_POLL */
1864 #endif /* HAVE_SELECT */
1865 gdk_draw_rectangle(GDK_DRAWABLE
1866 (GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f))),
1867 gc, TRUE, w->pixel_left, w->pixel_top,
1868 w->pixel_width, w->pixel_height);
1876 gtk_bevel_area(struct window *w, face_index findex,
1877 int x, int y, int width, int height,
1878 int shadow_thickness, int edges, enum edge_style style)
1880 struct frame *f = XFRAME(w->frame);
1881 struct device *d = XDEVICE(f->device);
1883 gtk_output_shadows(f, x, y, width, height, shadow_thickness);
1886 /* Make audible bell. */
1887 static void gtk_ring_bell(struct device *d, int volume, int pitch, int duration)
1889 /* Gdk does not allow us to control the duration / pitch / volume */
1893 /************************************************************************/
1894 /* initialization */
1895 /************************************************************************/
1897 void console_type_create_redisplay_gtk(void)
1899 /* redisplay methods */
1900 CONSOLE_HAS_METHOD(gtk, text_width);
1901 CONSOLE_HAS_METHOD(gtk, output_display_block);
1902 CONSOLE_HAS_METHOD(gtk, divider_height);
1903 CONSOLE_HAS_METHOD(gtk, eol_cursor_width);
1904 CONSOLE_HAS_METHOD(gtk, output_vertical_divider);
1905 CONSOLE_HAS_METHOD(gtk, clear_to_window_end);
1906 CONSOLE_HAS_METHOD(gtk, clear_region);
1907 CONSOLE_HAS_METHOD(gtk, clear_frame);
1908 CONSOLE_HAS_METHOD(gtk, flash);
1909 CONSOLE_HAS_METHOD(gtk, ring_bell);
1910 CONSOLE_HAS_METHOD(gtk, bevel_area);
1911 CONSOLE_HAS_METHOD(gtk, output_string);
1912 /* CONSOLE_HAS_METHOD (gtk, output_pixmap); */
1915 /* This makes me feel incredibly dirty... but there is no other way to
1916 get this done right other than calling clear_area before every
1917 single $#!%@ing piece of text, which I do NOT want to do. */
1918 #define USE_X_SPECIFIC_DRAW_ROUTINES 1
1920 #include <gdk/gdkx.h>
1923 gdk_draw_text_image(GdkDrawable * drawable,
1926 gint x, gint y, const gchar * text, gint text_length)
1928 #if !USE_X_SPECIFIC_DRAW_ROUTINES
1929 int width = gdk_text_measure(font, text, text_length);
1930 int height = gdk_text_height(font, text, text_length);
1932 gdk_draw_rectangle(drawable, gc, TRUE, x, y, width, height);
1933 gdk_draw_text(drawable, font, gc, x, y, text, text_length);
1935 GdkWindowPrivate *drawable_private;
1936 GdkFontPrivate *font_private;
1937 GdkGCPrivate *gc_private;
1939 g_return_if_fail(drawable != NULL);
1940 g_return_if_fail(font != NULL);
1941 g_return_if_fail(gc != NULL);
1942 g_return_if_fail(text != NULL);
1944 drawable_private = (GdkWindowPrivate *) drawable;
1945 if (drawable_private->destroyed)
1947 gc_private = (GdkGCPrivate *) gc;
1948 font_private = (GdkFontPrivate *) font;
1950 if (font->type == GDK_FONT_FONT) {
1951 XFontStruct *xfont = (XFontStruct *) font_private->xfont;
1952 XSetFont(drawable_private->xdisplay, gc_private->xgc,
1954 if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) {
1955 XDrawImageString(drawable_private->xdisplay,
1956 drawable_private->xwindow,
1957 gc_private->xgc, x, y, text,
1960 XDrawImageString16(drawable_private->xdisplay,
1961 drawable_private->xwindow,
1962 gc_private->xgc, x, y,
1963 (XChar2b *) text, text_length / 2);
1965 } else if (font->type == GDK_FONT_FONTSET) {
1966 XFontSet fontset = (XFontSet) font_private->xfont;
1967 XmbDrawImageString(drawable_private->xdisplay,
1968 drawable_private->xwindow, fontset,
1969 gc_private->xgc, x, y, text, text_length);
1971 g_error("undefined font type\n");
1976 our_draw_bitmap(GdkDrawable * drawable,
1980 gint ysrc, gint xdest, gint ydest, gint width, gint height)
1982 GdkWindowPrivate *drawable_private;
1983 GdkWindowPrivate *src_private;
1984 GdkGCPrivate *gc_private;
1986 g_return_if_fail(drawable != NULL);
1987 g_return_if_fail(src != NULL);
1988 g_return_if_fail(gc != NULL);
1990 drawable_private = (GdkWindowPrivate *) drawable;
1991 src_private = (GdkWindowPrivate *) src;
1992 if (drawable_private->destroyed || src_private->destroyed)
1994 gc_private = (GdkGCPrivate *) gc;
1997 width = src_private->width;
1999 height = src_private->height;
2001 XCopyPlane(drawable_private->xdisplay,
2002 src_private->xwindow,
2003 drawable_private->xwindow,
2005 xsrc, ysrc, width, height, xdest, ydest, 1L);