X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/6ff3e5e3cdba7a0b98a5e23f2900089194b303b2..8030369ccb5c871d3ce11b96c220f318bc741ed8:/src/w32term.c diff --git a/src/w32term.c b/src/w32term.c index 6c7cbe8b23..c9628277a4 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -84,9 +84,17 @@ enum fringe_bitmap_type `indicate-empty-lines' is non-nil. */ #define zv_width 8 -#define zv_height 8 +#define zv_height 72 +#define zv_period 3 static unsigned short zv_bits[] = { - 0x00, 0x00, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00}; + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00}; static HBITMAP zv_bmp; /* An arrow like this: `<-'. */ @@ -162,6 +170,10 @@ static Lisp_Object previous_help_echo; static int any_help_event_p; +/* Non-zero means autoselect window with the mouse cursor. */ + +int mouse_autoselect_window; + /* Non-zero means draw block and hollow cursor as wide as the glyph under it. For example, if a block cursor is over a tab, it will be drawn as wide as that tab on the display. */ @@ -176,8 +188,6 @@ extern unsigned int msh_mousewheel; extern void free_frame_menubar (); -extern void w32_menu_display_help (HMENU menu, UINT menu_item, UINT flags); - extern int w32_codepage_for_font (char *fontname); extern glyph_metric *w32_BDF_TextMetric(bdffont *fontp, @@ -216,10 +226,10 @@ struct cursor_pos output_cursor; /* The handle of the frame that currently owns the system caret. */ HWND w32_system_caret_hwnd; -int w32_system_caret_width; int w32_system_caret_height; int w32_system_caret_x; int w32_system_caret_y; +int w32_use_visible_system_caret; /* Flag to enable Unicode output in case users wish to use programs like Twinbridge on '95 rather than installed system level support @@ -323,7 +333,7 @@ extern int errno; /* A mask of extra modifier bits to put into every keyboard char. */ -extern int extra_keyboard_modifiers; +extern EMACS_INT extra_keyboard_modifiers; /* Enumeration for overriding/changing the face to use for drawing glyphs in x_draw_glyphs. */ @@ -382,12 +392,13 @@ static void x_clear_frame P_ ((void)); static void x_clear_cursor P_ ((struct window *)); static void frame_highlight P_ ((struct frame *)); static void frame_unhighlight P_ ((struct frame *)); -static void w32_new_focus_frame P_ ((struct w32_display_info *, - struct frame *)); +static void x_new_focus_frame P_ ((struct w32_display_info *, + struct frame *)); static void w32_frame_rehighlight P_ ((struct frame *)); static void x_frame_rehighlight P_ ((struct w32_display_info *)); static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); -static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int)); +static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int, + enum text_cursor_kinds)); static void expose_frame P_ ((struct frame *, int, int, int, int)); static int expose_window_tree P_ ((struct window *, RECT *)); static int expose_window P_ ((struct window *, RECT *)); @@ -401,13 +412,17 @@ static void x_update_window_cursor P_ ((struct window *, int)); static void x_erase_phys_cursor P_ ((struct window *)); void x_display_cursor P_ ((struct window *w, int, int, int, int, int)); void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int)); -static void w32_draw_fringe_bitmap P_ ((struct window *, HDC hdc, struct glyph_row *, - enum fringe_bitmap_type)); +static void w32_draw_fringe_bitmap P_ ((struct window *, HDC hdc, + struct glyph_row *, + enum fringe_bitmap_type, int left_p)); static void w32_clip_to_row P_ ((struct window *, struct glyph_row *, HDC, int)); static int x_phys_cursor_in_rect_p P_ ((struct window *, RECT *)); -static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *)); -static void notice_overwritten_cursor P_ ((struct window *, int, int)); +static void x_draw_row_fringe_bitmaps P_ ((struct window *, + struct glyph_row *)); +static void notice_overwritten_cursor P_ ((struct window *, + enum glyph_row_area, + int, int, int, int)); static Lisp_Object Qvendor_specific_keysyms; @@ -583,6 +598,10 @@ x_update_window_begin (w) struct frame *f = XFRAME (WINDOW_FRAME (w)); struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f); + /* Hide the system caret during an update. */ + if (w32_use_visible_system_caret) + SendMessage (w32_system_caret_hwnd, WM_EMACS_HIDE_CARET, 0, 0); + updated_window = w; set_output_cursor (&w->cursor); @@ -704,6 +723,12 @@ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p) dpyinfo->mouse_face_window = Qnil; } + /* Unhide the caret. This won't actually show the cursor, unless it + was visible before the corresponding call to HideCaret in + x_update_window_begin. */ + if (w32_use_visible_system_caret) + SendMessage (w32_system_caret_hwnd, WM_EMACS_SHOW_CARET, 0, 0); + updated_window = NULL; } @@ -752,7 +777,7 @@ w32_frame_up_to_date (f) /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay arrow bitmaps, or clear the fringes if no bitmaps are required before DESIRED_ROW is made current. The window being updated is - found in updated_window. This function It is called from + found in updated_window. This function is called from update_window_line only if it is known that there are differences between bitmaps to be drawn between current row and DESIRED_ROW. */ @@ -812,16 +837,18 @@ x_after_update_window_line (desired_row) drawn. */ static void -w32_draw_fringe_bitmap (w, hdc, row, which) +w32_draw_fringe_bitmap (w, hdc, row, which, left_p) struct window *w; HDC hdc; struct glyph_row *row; enum fringe_bitmap_type which; + int left_p; { struct frame *f = XFRAME (WINDOW_FRAME (w)); Window window = FRAME_W32_WINDOW (f); HDC compat_hdc; int x, y, wd, h, dy; + int b1, b2; HBITMAP pixmap; HANDLE horig_obj; struct face *face; @@ -829,71 +856,118 @@ w32_draw_fringe_bitmap (w, hdc, row, which) /* Must clip because of partially visible lines. */ w32_clip_to_row (w, row, hdc, 1); + /* Convert row to frame coordinates. */ + y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + switch (which) { + case NO_FRINGE_BITMAP: + wd = 0; + h = 0; + break; + case LEFT_TRUNCATION_BITMAP: wd = left_width; h = left_height; pixmap = left_bmp; - x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) - - wd - - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2); break; case OVERLAY_ARROW_BITMAP: wd = ov_width; h = ov_height; pixmap = ov_bmp; - x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) - - wd - - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2); break; case RIGHT_TRUNCATION_BITMAP: wd = right_width; h = right_height; pixmap = right_bmp; - x = window_box_right (w, -1); - x += (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2; break; case CONTINUED_LINE_BITMAP: wd = continued_width; h = continued_height; pixmap = continued_bmp; - x = window_box_right (w, -1); - x += (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2; break; case CONTINUATION_LINE_BITMAP: wd = continuation_width; h = continuation_height; pixmap = continuation_bmp; - x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) - - wd - - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2); break; case ZV_LINE_BITMAP: wd = zv_width; - h = zv_height; + h = zv_height - (y % zv_period); pixmap = zv_bmp; - x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) - - wd - - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2); break; default: abort (); } - /* Convert to frame coordinates. Set dy to the offset in the row to - start drawing the bitmap. */ - y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + /* Clip bitmap if too high. */ + if (h > row->height) + h = row->height; + + /* Set dy to the offset in the row to start drawing the bitmap. */ dy = (row->height - h) / 2; /* Draw the bitmap. */ face = FACE_FROM_ID (f, FRINGE_FACE_ID); + PREPARE_FACE_FOR_DISPLAY (f, face); + + /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill + the fringe. */ + b1 = -1; + if (left_p) + { + if (wd > FRAME_X_LEFT_FRINGE_WIDTH (f)) + wd = FRAME_X_LEFT_FRINGE_WIDTH (f); + x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) + - wd + - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2); + if (wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > h) + { + /* If W has a vertical border to its left, don't draw over it. */ + int border = ((XFASTINT (w->left) > 0 + && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + ? 1 : 0); + b1 = (window_box_left (w, -1) + - FRAME_X_LEFT_FRINGE_WIDTH (f) + + border); + b2 = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border); + } + } + else + { + if (wd > FRAME_X_RIGHT_FRINGE_WIDTH (f)) + wd = FRAME_X_RIGHT_FRINGE_WIDTH (f); + x = (window_box_right (w, -1) + + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2); + /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill + the fringe. */ + if (wd < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > h) + { + b1 = window_box_right (w, -1); + b2 = FRAME_X_RIGHT_FRINGE_WIDTH (f); + } + } + + if (b1 >= 0) + { + int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); + + w32_fill_area (f, hdc, face->background, + b1, + WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, + row->y)), + b2, + row->visible_height); + } + + if (which == NO_FRINGE_BITMAP) + return; compat_hdc = CreateCompatibleDC (hdc); SaveDC (hdc); @@ -902,7 +976,9 @@ w32_draw_fringe_bitmap (w, hdc, row, which) SetTextColor (hdc, face->background); SetBkColor (hdc, face->foreground); - BitBlt (hdc, x, y + dy, wd, h, compat_hdc, 0, 0, SRCCOPY); + BitBlt (hdc, x, y + dy, wd, h, compat_hdc, 0, + (which == ZV_LINE_BITMAP ? (row->y % zv_period) : 0), + SRCCOPY); SelectObject (compat_hdc, horig_obj); DeleteDC (compat_hdc); @@ -920,8 +996,6 @@ x_draw_row_fringe_bitmaps (w, row) { struct frame *f = XFRAME (w->frame); enum fringe_bitmap_type bitmap; - struct face *face; - int header_line_height = -1; HDC hdc; xassert (interrupt_input_blocked); @@ -931,81 +1005,40 @@ x_draw_row_fringe_bitmaps (w, row) if (row->visible_height <= 0) return; - face = FACE_FROM_ID (f, FRINGE_FACE_ID); - PREPARE_FACE_FOR_DISPLAY (f, face); - - /* Decide which bitmap to draw in the left fringe. */ - if (row->overlay_arrow_p) - bitmap = OVERLAY_ARROW_BITMAP; - else if (row->truncated_on_left_p) - bitmap = LEFT_TRUNCATION_BITMAP; - else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) - bitmap = CONTINUATION_LINE_BITMAP; - else if (row->indicate_empty_line_p) - bitmap = ZV_LINE_BITMAP; - else - bitmap = NO_FRINGE_BITMAP; - hdc = get_frame_dc (f); - /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill - the fringe. */ - if (bitmap == NO_FRINGE_BITMAP - || FRAME_FRINGE_BITMAP_WIDTH (f) < FRAME_X_LEFT_FRINGE_WIDTH (f) - || row->height > FRAME_FRINGE_BITMAP_HEIGHT (f)) - { - /* If W has a vertical border to its left, don't draw over it. */ - int border = ((XFASTINT (w->left) > 0 - && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)) - ? 1 : 0); - int left = window_box_left (w, -1); - - if (header_line_height < 0) - header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); - - w32_fill_area (f, hdc, face->background, - left - FRAME_X_LEFT_FRINGE_WIDTH (f) + border, - WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, - row->y)), - FRAME_X_LEFT_FRINGE_WIDTH (f) - border, - row->visible_height); - } - - /* Draw the left bitmap. */ - if (bitmap != NO_FRINGE_BITMAP) - w32_draw_fringe_bitmap (w, hdc, row, bitmap); + if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0) + { + /* Decide which bitmap to draw in the left fringe. */ + if (row->overlay_arrow_p) + bitmap = OVERLAY_ARROW_BITMAP; + else if (row->truncated_on_left_p) + bitmap = LEFT_TRUNCATION_BITMAP; + else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) + bitmap = CONTINUATION_LINE_BITMAP; + else if (row->indicate_empty_line_p) + bitmap = ZV_LINE_BITMAP; + else + bitmap = NO_FRINGE_BITMAP; - /* Decide which bitmap to draw in the right fringe. */ - if (row->truncated_on_right_p) - bitmap = RIGHT_TRUNCATION_BITMAP; - else if (row->continued_p) - bitmap = CONTINUED_LINE_BITMAP; - else - bitmap = NO_FRINGE_BITMAP; + w32_draw_fringe_bitmap (w, hdc, row, bitmap, 1); + } - /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill - the fringe. */ - if (bitmap == NO_FRINGE_BITMAP - || FRAME_FRINGE_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FRINGE_WIDTH (f) - || row->height > FRAME_FRINGE_BITMAP_HEIGHT (f)) + if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0) { - int right = window_box_right (w, -1); - - if (header_line_height < 0) - header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); + /* Decide which bitmap to draw in the right fringe. */ + if (row->truncated_on_right_p) + bitmap = RIGHT_TRUNCATION_BITMAP; + else if (row->continued_p) + bitmap = CONTINUED_LINE_BITMAP; + else if (row->indicate_empty_line_p && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0) + bitmap = ZV_LINE_BITMAP; + else + bitmap = NO_FRINGE_BITMAP; - w32_fill_area (f, hdc, face->background, - right, - WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, - row->y)), - FRAME_X_RIGHT_FRINGE_WIDTH (f), - row->visible_height); + w32_draw_fringe_bitmap (w, hdc, row, bitmap, 0); } - /* Draw the right bitmap. */ - if (bitmap != NO_FRINGE_BITMAP) - w32_draw_fringe_bitmap (w, hdc, row, bitmap); - release_frame_dc (f, hdc); } @@ -1192,9 +1225,24 @@ w32_native_per_char_metric (font, char2b, font_type, pcm) if (retval) { +#if 0 + /* Disabled until we can find a way to get the right results + on all versions of Windows. */ + + /* Don't trust the ABC widths. For synthesized fonts they are + wrong, and so is the result of GetCharWidth()! */ + int real_width; + GetCharWidth (hdc, *char2b, *char2b, &real_width); +#endif pcm->width = char_widths.abcA + char_widths.abcB + char_widths.abcC; +#if 0 + /* As far as I can tell, this is the best way to determine what + ExtTextOut will do with the broken font. */ + if (pcm->width != real_width) + pcm->width = (pcm->width + real_width) / 2; +#endif pcm->lbearing = char_widths.abcA; - pcm->rbearing = pcm->width - char_widths.abcC; + pcm->rbearing = char_widths.abcA + char_widths.abcB; pcm->ascent = FONT_BASE (font); pcm->descent = FONT_DESCENT (font); } @@ -1797,7 +1845,7 @@ x_append_stretch_glyph (it, object, width, height, ascent) 4. `:height HEIGHT' specifies that the height of the stretch produced should be HEIGHT, measured in canonical character units. - 5. `:relative-height FACTOR' specifies that the height of the the + 5. `:relative-height FACTOR' specifies that the height of the stretch should be FACTOR times the height of the characters having the glyph property. @@ -2688,7 +2736,8 @@ struct glyph_string /* Encapsulate the different ways of displaying text under W32. */ -void W32_TEXTOUT (s, x, y,chars,nchars) +static void +w32_text_out (s, x, y,chars,nchars) struct glyph_string * s; int x, y; wchar_t * chars; @@ -2702,8 +2751,8 @@ void W32_TEXTOUT (s, x, y,chars,nchars) else if (s->first_glyph->w32_font_type == UNICODE_FONT) ExtTextOutW (s->hdc, x, y, 0, NULL, chars, nchars, NULL); else - ExtTextOut (s->hdc, x, y, 0, NULL, (char *) chars, - nchars * charset_dim, NULL); + ExtTextOutA (s->hdc, x, y, 0, NULL, (char *) chars, + nchars * charset_dim, NULL); } #if GLYPH_DEBUG @@ -3436,7 +3485,7 @@ x_draw_glyph_string_foreground (s) char1b[i] = BYTE2 (s->char2b[i]); /* Draw text with TextOut and friends. */ - W32_TEXTOUT (s, x, s->ybase - boff, s->char2b, s->nchars); + w32_text_out (s, x, s->ybase - boff, s->char2b, s->nchars); } if (s->font && s->font->hfont) SelectObject (s->hdc, old_font); @@ -3483,7 +3532,7 @@ x_draw_composite_glyph_string_foreground (s) else { for (i = 0; i < s->nchars; i++, ++s->gidx) - W32_TEXTOUT (s, x + s->cmp->offsets[s->gidx * 2], + w32_text_out (s, x + s->cmp->offsets[s->gidx * 2], s->ybase - s->cmp->offsets[s->gidx * 2 + 1], s->char2b + i, 1); } @@ -3632,6 +3681,7 @@ x_setup_relief_colors (s) if (s->face->use_box_color_for_shadows_p) color = s->face->box_color; else if (s->first_glyph->type == IMAGE_GLYPH + && s->img->pixmap && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0)) color = IMAGE_BACKGROUND (s->img, s->f, 0); else @@ -3679,14 +3729,14 @@ w32_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, for (i = 0; i < width; ++i) w32_fill_area (f, hdc, gc.foreground, left_x + i * left_p, top_y + i, - (right_x + 1 - i * right_p) - (left_x + i * left_p) + 1, 1); + right_x - left_x - i * (left_p + right_p ) + 1, 1); /* Left. */ if (left_p) for (i = 0; i < width; ++i) w32_fill_area (f, hdc, gc.foreground, left_x + i, top_y + i, 1, - (bottom_y - i) - (top_y + i) + 2); + bottom_y - top_y - 2 * i + 1); if (raised_p) gc.foreground = f->output_data.w32->black_relief.gc->foreground; @@ -3697,14 +3747,14 @@ w32_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, for (i = 0; i < width; ++i) w32_fill_area (f, hdc, gc.foreground, left_x + i * left_p, bottom_y - i, - (right_x - i * right_p) - (left_x + i * left_p) + 2, 1); + right_x - left_x - i * (left_p + right_p) + 1, 1); /* Right. */ if (right_p) for (i = 0; i < width; ++i) w32_fill_area (f, hdc, gc.foreground, right_x - i, top_y + i + 1, 1, - (bottom_y - i) - (top_y + i)); + bottom_y - top_y - 2 * i - 1); w32_set_clip_rectangle (hdc, NULL); @@ -3897,8 +3947,12 @@ x_draw_image_foreground (s) the image. I believe it's looking better if we do nothing here for mouse-face. */ if (s->hl == DRAW_CURSOR) - w32_draw_rectangle (s->hdc, s->gc, x, y, s->img->width - 1, - s->img->height - 1); + { + int r = s->img->relief; + if (r < 0) r = -r; + w32_draw_rectangle (s->hdc, s->gc, x - r, y - r , + s->img->width + r*2 - 1, s->img->height + r*2 - 1); + } w32_set_clip_rectangle (s->hdc, NULL); } } @@ -3938,7 +3992,7 @@ x_draw_image_relief (s) if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED) { - thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : 3; + thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF; raised_p = s->hl == DRAW_IMAGE_RAISED; } else @@ -4038,8 +4092,12 @@ w32_draw_image_foreground_1 (s, pixmap) the image. I believe it's looking better if we do nothing here for mouse-face. */ if (s->hl == DRAW_CURSOR) - w32_draw_rectangle (hdc, s->gc, x, y, s->img->width - 1, - s->img->height - 1); + { + int r = s->img->relief; + if (r < 0) r = -r; + w32_draw_rectangle (s->hdc, s->gc, x - r, y - r , + s->img->width + r*2 - 1, s->img->height + r*2 - 1); + } } } else @@ -4900,7 +4958,6 @@ x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) /* X is relative to the left edge of W, without scroll bars or fringes. */ struct frame *f = XFRAME (WINDOW_FRAME (w)); - /* int width = FRAME_FRINGE_WIDTH (f); */ int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f); x += window_left_x; @@ -5022,7 +5079,12 @@ x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) for (s = head; s; s = s->next) x_draw_glyph_string (s); - if (area == TEXT_AREA && !row->full_width_p) + if (area == TEXT_AREA + && !row->full_width_p + /* When drawing overlapping rows, only the glyph strings' + foreground is drawn, which doesn't erase a cursor + completely. */ + && !overlaps_p) { int x0 = head ? head->x : x; int x1 = tail ? tail->x + tail->background_width : x; @@ -5037,7 +5099,8 @@ x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) x1 -= left_area_width; } - notice_overwritten_cursor (w, x0, x1); + notice_overwritten_cursor (w, area, x0, x1, + row->y, MATRIX_ROW_BOTTOM_Y (row)); } /* Value is the x-position up to which drawn, relative to AREA of W. @@ -5257,10 +5320,13 @@ x_clear_end_of_line (to_x) /* Notice if the cursor will be cleared by this operation. */ if (!updated_row->full_width_p) - notice_overwritten_cursor (w, output_cursor.x, -1); + notice_overwritten_cursor (w, updated_area, + output_cursor.x, -1, + updated_row->y, + MATRIX_ROW_BOTTOM_Y (updated_row)); from_x = output_cursor.x; - + /* Translate to frame coordinates. */ if (updated_row->full_width_p) { @@ -5405,7 +5471,8 @@ x_scroll_run (w, run) { struct frame *f = XFRAME (w->frame); int x, y, width, height, from_y, to_y, bottom_y; - HDC hdc = get_frame_dc (f); + HWND hwnd = FRAME_W32_WINDOW (f); + HRGN expect_dirty; /* Get frame-relative bounding box of the text display area of W, without mode lines. Include in this box the left and right @@ -5426,6 +5493,7 @@ x_scroll_run (w, run) height = bottom_y - from_y; else height = run->height; + expect_dirty = CreateRectRgn (x, y + height, x + width, bottom_y); } else { @@ -5435,6 +5503,7 @@ x_scroll_run (w, run) height = bottom_y - to_y; else height = run->height; + expect_dirty = CreateRectRgn (x, y, x + width, to_y); } BLOCK_INPUT; @@ -5443,10 +5512,32 @@ x_scroll_run (w, run) updated_window = w; x_clear_cursor (w); - BitBlt (hdc, x, to_y, width, height, hdc, x, from_y, SRCCOPY); - + { + RECT from; + RECT to; + HRGN dirty = CreateRectRgn (0, 0, 0, 0); + HRGN combined = CreateRectRgn (0, 0, 0, 0); + + from.left = to.left = x; + from.right = to.right = x + width; + from.top = from_y; + from.bottom = from_y + height; + to.top = y; + to.bottom = bottom_y; + + ScrollWindowEx (hwnd, 0, to_y - from_y, &from, &to, dirty, + NULL, SW_INVALIDATE); + + /* Combine this with what we expect to be dirty. This covers the + case where not all of the region we expect is actually dirty. */ + CombineRgn (combined, dirty, expect_dirty, RGN_OR); + + /* If the dirty region is not what we expected, redraw the entire frame. */ + if (!EqualRgn (combined, expect_dirty)) + SET_FRAME_GARBAGED (f); + } + UNBLOCK_INPUT; - release_frame_dc (f, hdc); } @@ -6010,9 +6101,13 @@ glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y) return success_p; } +/* Parse a button MESSAGE. The button index is returned in PBUTTON, and + the state in PUP. XBUTTON provides extra information for extended mouse + button messages. Returns FALSE if unable to parse the message. */ BOOL -parse_button (message, pbutton, pup) +parse_button (message, xbutton, pbutton, pup) int message; + int xbutton; int * pbutton; int * pup; { @@ -6057,6 +6152,14 @@ parse_button (message, pbutton, pup) button = 1; up = 1; break; + case WM_XBUTTONDOWN: + button = xbutton + 2; + up = 0; + break; + case WM_XBUTTONUP: + button = xbutton + 2; + up = 1; + break; default: return (FALSE); } @@ -6082,11 +6185,12 @@ construct_mouse_click (result, msg, f) int button; int up; - parse_button (msg->msg.message, &button, &up); + parse_button (msg->msg.message, HIWORD (msg->msg.wParam), + &button, &up); - /* Make the event type no_event; we'll change that when we decide + /* Make the event type NO_EVENT; we'll change that when we decide otherwise. */ - result->kind = mouse_click; + result->kind = MOUSE_CLICK_EVENT; result->code = button; result->timestamp = msg->msg.time; result->modifiers = (msg->dwModifiers @@ -6108,7 +6212,7 @@ construct_mouse_wheel (result, msg, f) struct frame *f; { POINT p; - result->kind = mouse_wheel; + result->kind = MOUSE_WHEEL_EVENT; result->code = (short) HIWORD (msg->msg.wParam); result->timestamp = msg->msg.time; result->modifiers = msg->dwModifiers; @@ -6136,7 +6240,7 @@ construct_drag_n_drop (result, msg, f) char *name; int i, len; - result->kind = drag_n_drop; + result->kind = DRAG_N_DROP_EVENT; result->code = 0; result->timestamp = msg->msg.time; result->modifiers = msg->dwModifiers; @@ -6163,7 +6267,7 @@ construct_drag_n_drop (result, msg, f) continue; name = alloca (len + 1); DragQueryFile (hdrop, i, name, len + 1); - files = Fcons (build_string (name), files); + files = Fcons (DECODE_FILE (build_string (name)), files); } DragFinish (hdrop); @@ -6200,6 +6304,28 @@ note_mouse_movement (frame, msg) memcpy (&last_mouse_motion_event, msg, sizeof (last_mouse_motion_event)); XSETFRAME (last_mouse_motion_frame, frame); +#if 0 /* Calling Lisp asynchronously is not safe. */ + if (mouse_autoselect_window) + { + int area; + Lisp_Object window; + static Lisp_Object last_window; + + window = window_from_coordinates (frame, mouse_x, mouse_y, &area, 0); + + /* Window will be selected only when it is not selected now and + last mouse movement event was not in it. Minibuffer window + will be selected iff it is active. */ + if (!EQ (window, last_window) + && !EQ (window, selected_window) + && (!MINI_WINDOW_P (XWINDOW (window)) + || (EQ (window, minibuf_window) && minibuf_level > 0))) + Fselect_window (window); + + last_window=window; + } +#endif + if (msg->hwnd != FRAME_W32_WINDOW (frame)) { frame->mouse_moved = 1; @@ -6224,11 +6350,6 @@ note_mouse_movement (frame, msg) } } -/* This is used for debugging, to turn off note_mouse_highlight. */ - -int disable_mouse_highlight; - - /************************************************************************ Mouse Face @@ -6387,9 +6508,9 @@ note_mode_line_highlight (w, x, mode_line_p) if (glyph < end && STRINGP (glyph->object) - && XSTRING (glyph->object)->intervals + && STRING_INTERVALS (glyph->object) && glyph->charpos >= 0 - && glyph->charpos < XSTRING (glyph->object)->size) + && glyph->charpos < SCHARS (glyph->object)) { /* If we're on a string with `help-echo' text property, arrange for the help to be displayed. This is done by @@ -6445,7 +6566,7 @@ note_mouse_highlight (f, x, y) if (popup_activated ()) return; - if (disable_mouse_highlight + if (NILP (Vmouse_highlight) || !f->glyphs_initialized_p) return; @@ -6708,7 +6829,7 @@ note_mouse_highlight (f, x, y) if (NILP (b)) b = make_number (0); if (NILP (e)) - e = make_number (XSTRING (object)->size - 1); + e = make_number (SCHARS (object) - 1); fast_find_string_pos (w, XINT (b), object, &dpyinfo->mouse_face_beg_col, &dpyinfo->mouse_face_beg_row, @@ -6806,7 +6927,7 @@ note_mouse_highlight (f, x, y) /* Try text properties. */ if (STRINGP (object) && charpos >= 0 - && charpos < XSTRING (object)->size) + && charpos < SCHARS (object)) { help = Fget_text_property (make_number (charpos), Qhelp_echo, object); @@ -6954,7 +7075,7 @@ w32_handle_tool_bar_click (f, button_event) if (NILP (enabled_p)) return; - if (button_event->kind == mouse_click) + if (button_event->modifiers & down_modifier) { /* Show item in pressed state. */ show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN); @@ -6981,7 +7102,8 @@ w32_handle_tool_bar_click (f, button_event) event.kind = TOOL_BAR_EVENT; event.frame_or_window = frame; event.arg = key; - event.modifiers = button_event->modifiers; + /* The keyboard buffer doesn't like the up modifier being set. */ + event.modifiers = button_event->modifiers & ~up_modifier; kbd_buffer_store_event (&event); last_tool_bar_item = -1; } @@ -7258,7 +7380,7 @@ fast_find_position (w, pos, hpos, vpos, x, y, stop) #endif /* not 0 */ -/* Find the position of the the glyph for position POS in OBJECT in +/* Find the position of the glyph for position POS in OBJECT in window W's current matrix, and return in *X/*Y the pixel coordinates, and return in *HPOS/*VPOS the column/row of the glyph. @@ -7354,6 +7476,8 @@ show_mouse_face (dpyinfo, draw) if (/* If window is in the process of being destroyed, don't bother to do anything. */ w->current_matrix != NULL + /* Don't update mouse highlight if hidden */ + && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden) /* Recognize when we are called to operate on rows that don't exist anymore. This can happen when a window is split. */ && dpyinfo->mouse_face_end_row < w->current_matrix->nrows) @@ -7390,7 +7514,8 @@ show_mouse_face (dpyinfo, draw) x_draw_glyphs (w, start_x, row, TEXT_AREA, start_hpos, end_hpos, draw, 0); - row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED; + row->mouse_face_p + = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED; } } @@ -7480,6 +7605,8 @@ cancel_mouse_face (f) static struct scroll_bar *x_window_to_scroll_bar (); static void x_scroll_bar_report_motion (); +static void x_check_fullscreen P_ ((struct frame *)); +static void x_check_fullscreen_move P_ ((struct frame *)); static int glyph_rect P_ ((struct frame *f, int, int, RECT *)); @@ -7495,7 +7622,7 @@ glyph_rect (f, x, y, rect) RECT *rect; { Lisp_Object window; - int part, found = 0; + int part; window = window_from_coordinates (f, x, y, &part, 0); if (!NILP (window)) @@ -7505,27 +7632,44 @@ glyph_rect (f, x, y, rect) struct glyph_row *end = r + w->current_matrix->nrows - 1; frame_to_window_pixel_xy (w, &x, &y); - - for (; !found && r < end && r->enabled_p; ++r) - if (r->y + r->height >= y) + + for (; r < end && r->enabled_p; ++r) + if (r->y <= y && r->y + r->height > y) { + /* Found the row at y. */ struct glyph *g = r->glyphs[TEXT_AREA]; struct glyph *end = g + r->used[TEXT_AREA]; int gx; - - for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g) - if (gx + g->pixel_width >= x) + + rect->top = WINDOW_TO_FRAME_PIXEL_Y (w, r->y); + rect->bottom = rect->top + r->height; + + if (x < r->x) + { + /* x is to the left of the first glyph in the row. */ + rect->left = XINT (w->left); + rect->right = WINDOW_TO_FRAME_PIXEL_X (w, r->x); + return 1; + } + + for (gx = r->x; g < end; gx += g->pixel_width, ++g) + if (gx <= x && gx + g->pixel_width > x) { + /* x is on a glyph. */ rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx); - rect->top = WINDOW_TO_FRAME_PIXEL_Y (w, r->y); rect->right = rect->left + g->pixel_width; - rect->bottom = rect->top + r->height; - found = 1; + return 1; } + + /* x is to the right of the last glyph in the row. */ + rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx); + rect->right = XINT (w->left) + XINT (w->width); + return 1; } } - return found; + /* The y is not on any row. */ + return 0; } /* Record the position of the mouse in last_mouse_glyph. */ @@ -7797,7 +7941,7 @@ my_create_scrollbar (f, bar) (LPARAM) bar); } -//#define ATTACH_THREADS +/*#define ATTACH_THREADS*/ BOOL my_show_window (FRAME_PTR f, HWND hwnd, int how) @@ -8051,7 +8195,7 @@ w32_set_vertical_scroll_bar (w, portion, whole, position) SetScrollRange (hwnd, SB_CTL, 0, VERTICAL_SCROLL_BAR_TOP_RANGE (f, height), FALSE); my_show_window (f, hwnd, SW_NORMAL); - // InvalidateRect (w, NULL, FALSE); + /* InvalidateRect (w, NULL, FALSE); */ /* Remember new settings. */ XSETINT (bar->left, sb_left); @@ -8175,7 +8319,7 @@ w32_judge_scroll_bars (f) } /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind - is set to something other than no_event, it is enqueued. + is set to something other than NO_EVENT, it is enqueued. This may be called from a signal handler, so we have to ignore GC mark bits. */ @@ -8189,7 +8333,7 @@ w32_scroll_bar_handle_click (bar, msg, emacs_event) if (! GC_WINDOWP (bar->window)) abort (); - emacs_event->kind = w32_scroll_bar_click; + emacs_event->kind = W32_SCROLL_BAR_CLICK_EVENT; emacs_event->code = 0; /* not really meaningful to distinguish up/down */ emacs_event->modifiers = msg->dwModifiers; @@ -8289,7 +8433,7 @@ w32_scroll_bar_handle_click (bar, msg, emacs_event) } /* fall through */ default: - emacs_event->kind = no_event; + emacs_event->kind = NO_EVENT; return FALSE; } @@ -8403,12 +8547,6 @@ x_scroll_bar_clear (f) /* The main W32 event-reading loop - w32_read_socket. */ -/* Time stamp of enter window event. This is only used by w32_read_socket, - but we have to put it out here, since static variables within functions - sometimes don't work. */ - -static Time enter_timestamp; - /* Record the last 100 characters stored to help debug the loss-of-chars-during-GC problem. */ @@ -8464,7 +8602,7 @@ w32_read_socket (sd, bufp, numchars, expected) if (numchars <= 0) abort (); /* Don't think this happens. */ - /* TODO: tooltips, tool-bars, ghostscript integration, mouse + /* TODO: tool-bars, ghostscript integration, mouse cursors. */ while (get_next_msg (&msg, FALSE)) { @@ -8481,7 +8619,7 @@ w32_read_socket (sd, bufp, numchars, expected) /* We may get paint messages even though the client area is clipped - these are not expose events. */ DebPrint (("clipped frame %p (%s) got WM_PAINT - ignored\n", f, - XSTRING (f->name)->data)); + SDATA (f->name))); } else if (f->async_visible != 1) { @@ -8490,13 +8628,13 @@ w32_read_socket (sd, bufp, numchars, expected) f->async_iconified = 0; SET_FRAME_GARBAGED (f); DebPrint (("frame %p (%s) reexposed by WM_PAINT\n", f, - XSTRING (f->name)->data)); + SDATA (f->name))); /* WM_PAINT serves as MapNotify as well, so report visibility changes properly. */ if (f->iconified) { - bufp->kind = deiconify_event; + bufp->kind = DEICONIFY_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp++; @@ -8534,7 +8672,7 @@ w32_read_socket (sd, bufp, numchars, expected) if (numchars == 0) abort (); - bufp->kind = language_change_event; + bufp->kind = LANGUAGE_CHANGE_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp->code = msg.msg.wParam; @@ -8551,10 +8689,16 @@ w32_read_socket (sd, bufp, numchars, expected) if (f && !f->iconified) { + if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) + { + dpyinfo->mouse_face_hidden = 1; + clear_mouse_face (dpyinfo); + } + if (temp_index == sizeof temp_buffer / sizeof (short)) temp_index = 0; temp_buffer[temp_index++] = msg.msg.wParam; - bufp->kind = non_ascii_keystroke; + bufp->kind = NON_ASCII_KEYSTROKE_EVENT; bufp->code = msg.msg.wParam; bufp->modifiers = msg.dwModifiers; XSETFRAME (bufp->frame_or_window, f); @@ -8572,10 +8716,16 @@ w32_read_socket (sd, bufp, numchars, expected) if (f && !f->iconified) { + if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) + { + dpyinfo->mouse_face_hidden = 1; + clear_mouse_face (dpyinfo); + } + if (temp_index == sizeof temp_buffer / sizeof (short)) temp_index = 0; temp_buffer[temp_index++] = msg.msg.wParam; - bufp->kind = ascii_keystroke; + bufp->kind = ASCII_KEYSTROKE_EVENT; bufp->code = msg.msg.wParam; bufp->modifiers = msg.dwModifiers; XSETFRAME (bufp->frame_or_window, f); @@ -8598,6 +8748,12 @@ w32_read_socket (sd, bufp, numchars, expected) else f = x_window_to_frame (dpyinfo, msg.msg.hwnd); + if (dpyinfo->mouse_face_hidden) + { + dpyinfo->mouse_face_hidden = 0; + clear_mouse_face (dpyinfo); + } + if (f) note_mouse_movement (f, &msg.msg); else @@ -8633,6 +8789,8 @@ w32_read_socket (sd, bufp, numchars, expected) case WM_MBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: { /* If we decide we want to generate an event to be seen by the rest of Emacs, we put it here. */ @@ -8641,7 +8799,7 @@ w32_read_socket (sd, bufp, numchars, expected) int button; int up; - emacs_event.kind = no_event; + emacs_event.kind = NO_EVENT; if (dpyinfo->grabbed && last_mouse_frame && FRAME_LIVE_P (last_mouse_frame)) @@ -8658,13 +8816,14 @@ w32_read_socket (sd, bufp, numchars, expected) && XFASTINT (XWINDOW (f->tool_bar_window)->height)) { Lisp_Object window; - int p; + int p, x, y; + + x = XFASTINT (emacs_event.x); + y = XFASTINT (emacs_event.y); /* Set x and y. */ - window = window_from_coordinates (f, - emacs_event.x, - emacs_event.y, - &p, 1); + window = window_from_coordinates (f, x, y, &p, 1); + if (EQ (window, f->tool_bar_window)) { w32_handle_tool_bar_click (f, &emacs_event); @@ -8684,8 +8843,9 @@ w32_read_socket (sd, bufp, numchars, expected) } } - parse_button (msg.msg.message, &button, &up); - + parse_button (msg.msg.message, HIWORD (msg.msg.wParam), + &button, &up); + if (up) { dpyinfo->grabbed &= ~ (1 << button); @@ -8728,16 +8888,6 @@ w32_read_socket (sd, bufp, numchars, expected) } break; - case WM_MENUSELECT: - { - HMENU menu = (HMENU) msg.msg.lParam; - UINT menu_item = (UINT) LOWORD (msg.msg.wParam); - UINT flags = (UINT) HIWORD (msg.msg.wParam); - - w32_menu_display_help (menu, menu_item, flags); - } - break; - case WM_DROPFILES: f = x_window_to_frame (dpyinfo, msg.msg.hwnd); @@ -8768,8 +8918,22 @@ w32_read_socket (sd, bufp, numchars, expected) } case WM_WINDOWPOSCHANGED: + f = x_window_to_frame (dpyinfo, msg.msg.hwnd); + if (f) + { + x_check_fullscreen_move(f); + if (f->output_data.w32->want_fullscreen & FULLSCREEN_WAIT) + f->output_data.w32->want_fullscreen &= + ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH); + } + check_visibility = 1; + break; + case WM_ACTIVATE: case WM_ACTIVATEAPP: + f = x_window_to_frame (dpyinfo, msg.msg.hwnd); + if (f) + x_check_fullscreen (f); check_visibility = 1; break; @@ -8789,6 +8953,15 @@ w32_read_socket (sd, bufp, numchars, expected) break; case WM_SHOWWINDOW: + /* wParam non-zero means Window is about to be shown, 0 means + about to be hidden. */ + /* Redo the mouse-highlight after the tooltip has gone. */ + if (!msg.msg.wParam && msg.msg.hwnd == tip_window) + { + tip_window = NULL; + redo_mouse_highlight (); + } + /* If window has been obscured or exposed by another window being maximised or minimised/restored, then recheck visibility of all frames. Direct changes to our own @@ -8818,7 +8991,7 @@ w32_read_socket (sd, bufp, numchars, expected) f->async_visible = 0; f->async_iconified = 1; - bufp->kind = iconify_event; + bufp->kind = ICONIFY_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp++; @@ -8848,7 +9021,7 @@ w32_read_socket (sd, bufp, numchars, expected) f->output_data.w32->left_pos = x; f->output_data.w32->top_pos = y; - bufp->kind = deiconify_event; + bufp->kind = DEICONIFY_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp++; @@ -8904,6 +9077,36 @@ w32_read_socket (sd, bufp, numchars, expected) check_visibility = 1; break; + case WM_MOUSELEAVE: + f = x_any_window_to_frame (dpyinfo, msg.msg.hwnd); + if (f) + { + if (f == dpyinfo->mouse_face_mouse_frame) + { + /* If we move outside the frame, then we're + certainly no longer on any text in the frame. */ + clear_mouse_face (dpyinfo); + dpyinfo->mouse_face_mouse_frame = 0; + } + + /* Generate a nil HELP_EVENT to cancel a help-echo. + Do it only if there's something to cancel. + Otherwise, the startup message is cleared when + the mouse leaves the frame. */ + if (any_help_event_p) + { + Lisp_Object frame; + int n; + + XSETFRAME (frame, f); + help_echo = Qnil; + n = gen_help_event (bufp, numchars, + Qnil, frame, Qnil, Qnil, 0); + bufp += n, count += n, numchars -= n; + } + } + break; + case WM_SETFOCUS: f = x_any_window_to_frame (dpyinfo, msg.msg.hwnd); @@ -8966,7 +9169,7 @@ w32_read_socket (sd, bufp, numchars, expected) if (numchars == 0) abort (); - bufp->kind = delete_window_event; + bufp->kind = DELETE_WINDOW_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp++; @@ -8983,7 +9186,7 @@ w32_read_socket (sd, bufp, numchars, expected) if (numchars == 0) abort (); - bufp->kind = menu_bar_activate_event; + bufp->kind = MENU_BAR_ACTIVATE_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp++; @@ -9068,6 +9271,11 @@ w32_read_socket (sd, bufp, numchars, expected) FOR_EACH_FRAME (tail, frame) { FRAME_PTR f = XFRAME (frame); + /* The tooltip has been drawn already. Avoid the + SET_FRAME_GARBAGED below. */ + if (EQ (frame, tip_frame)) + continue; + /* Check "visible" frames and mark each as obscured or not. Note that async_visible is nonzero for unobscured and obscured frames, but zero for hidden and iconified frames. */ @@ -9100,7 +9308,7 @@ w32_read_socket (sd, bufp, numchars, expected) if (!FRAME_OBSCURED_P (f)) { DebPrint (("frame %p (%s) obscured\n", f, - XSTRING (f->name)->data)); + SDATA (f->name))); } } else @@ -9112,7 +9320,7 @@ w32_read_socket (sd, bufp, numchars, expected) { SET_FRAME_GARBAGED (f); DebPrint (("obscured frame %p (%s) found to be visible\n", f, - XSTRING (f->name)->data)); + SDATA (f->name))); /* Force a redisplay sooner or later. */ record_asynch_buffer_change (); @@ -9140,15 +9348,17 @@ w32_read_socket (sd, bufp, numchars, expected) of the line after START_X has been written. */ static void -notice_overwritten_cursor (w, start_x, end_x) +notice_overwritten_cursor (w, area, x0, x1, y0, y1) struct window *w; - int start_x, end_x; + enum glyph_row_area area; + int x0, x1, y0, y1; { - if (updated_area == TEXT_AREA + if (area == TEXT_AREA && w->phys_cursor_on_p - && output_cursor.vpos == w->phys_cursor.vpos - && start_x <= w->phys_cursor.x - && (end_x < 0 || end_x > w->phys_cursor.x)) + && y0 <= w->phys_cursor.y + && y1 >= w->phys_cursor.y + w->phys_cursor_height + && x0 <= w->phys_cursor.x + && (x1 < 0 || x1 > w->phys_cursor.x)) w->phys_cursor_on_p = 0; } @@ -9212,7 +9422,7 @@ x_draw_hollow_cursor (w, row) rect.left = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); rect.top = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) + row->ascent - w->phys_cursor_ascent); - rect.bottom = rect.top + row->height - 1; + rect.bottom = rect.top + row->height; /* Get the glyph the cursor is on. If we can't tell because the current matrix is invalid or such, give up. */ @@ -9224,7 +9434,7 @@ x_draw_hollow_cursor (w, row) glyph, and `x-stretch-block-cursor' is nil, don't draw a rectangle as wide as the glyph, but use a canonical character width instead. */ - wd = cursor_glyph->pixel_width - 1; + wd = cursor_glyph->pixel_width; if (cursor_glyph->type == STRETCH_GLYPH && !x_stretch_cursor_p) wd = min (CANON_X_UNIT (f), wd); @@ -9246,10 +9456,11 @@ x_draw_hollow_cursor (w, row) --gerd. */ static void -x_draw_bar_cursor (w, row, width) +x_draw_bar_cursor (w, row, width, kind) struct window *w; struct glyph_row *row; int width; + enum text_cursor_kinds kind; { struct frame *f = XFRAME (w->frame); struct glyph *cursor_glyph; @@ -9279,6 +9490,7 @@ x_draw_bar_cursor (w, row, width) if (width < 0) width = f->output_data.w32->cursor_width; + width = min (cursor_glyph->pixel_width, width); /* If the glyph's background equals the color we normally draw the bar cursor in, the bar cursor in its normal color is @@ -9291,10 +9503,20 @@ x_draw_bar_cursor (w, row, width) x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); hdc = get_frame_dc (f); w32_clip_to_row (w, row, hdc, 0); - w32_fill_area (f, hdc, cursor_color, x, - WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), - min (cursor_glyph->pixel_width, width), - row->height); + + if (kind == BAR_CURSOR) + { + w32_fill_area (f, hdc, cursor_color, x, + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), + width, row->height); + } + else + { + w32_fill_area (f, hdc, cursor_color, x, + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y + + row->height - width), + cursor_glyph->pixel_width, width); + } release_frame_dc (f, hdc); } } @@ -9382,6 +9604,12 @@ x_erase_phys_cursor (w) if (!cursor_row->enabled_p) goto mark_cursor_off; + /* If row is completely invisible, don't attempt to delete a cursor which + isn't there. This may happen if cursor is at top of window, and + we switch to a buffer with a header line in that window. */ + if (cursor_row->visible_height <= 0) + goto mark_cursor_off; + /* This can happen when the new row is shorter than the old one. In this case, either x_draw_glyphs or clear_end_of_line should have cleared the cursor. Note that we wouldn't be @@ -9556,8 +9784,6 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) else new_cursor_type = HOLLOW_BOX_CURSOR; } - else if (w->cursor_off_p) - new_cursor_type = NO_CURSOR; else { struct buffer *b = XBUFFER (w->buffer); @@ -9567,6 +9793,15 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) else new_cursor_type = x_specified_cursor_type (b->cursor_type, &new_cursor_width); + if (w->cursor_off_p) + { + if (new_cursor_type == FILLED_BOX_CURSOR) + new_cursor_type = HOLLOW_BOX_CURSOR; + else if (new_cursor_type == BAR_CURSOR && new_cursor_width > 1) + new_cursor_width = 1; + else + new_cursor_type = NO_CURSOR; + } } } @@ -9577,7 +9812,9 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) && (!on || w->phys_cursor.x != x || w->phys_cursor.y != y - || new_cursor_type != w->phys_cursor_type)) + || new_cursor_type != w->phys_cursor_type + || (new_cursor_type == BAR_CURSOR + && new_cursor_width != w->phys_cursor_width))) x_erase_phys_cursor (w); /* If the cursor is now invisible and we want it to be visible, @@ -9593,7 +9830,23 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) w->phys_cursor.y = glyph_row->y; w->phys_cursor.hpos = hpos; w->phys_cursor.vpos = vpos; - w->phys_cursor_type = new_cursor_type; + + /* If the user wants to use the system caret, make sure our own + cursor remains invisible. */ + if (w32_use_visible_system_caret) + { + if (w->phys_cursor_type != NO_CURSOR) + x_erase_phys_cursor (w); + + new_cursor_type = w->phys_cursor_type = NO_CURSOR; + w->phys_cursor_width = -1; + } + else + { + w->phys_cursor_type = new_cursor_type; + w->phys_cursor_width = new_cursor_width; + } + w->phys_cursor_on_p = 1; /* If this is the active cursor, we need to track it with the @@ -9601,33 +9854,24 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) and speech synthesizers can follow the cursor. */ if (active_cursor) { - struct glyph * cursor_glyph = get_phys_cursor_glyph (w); - if (cursor_glyph) - { - HWND hwnd = FRAME_W32_WINDOW (f); - int caret_width = cursor_glyph->pixel_width; - w32_system_caret_x - = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); - w32_system_caret_y - = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) - + glyph_row->ascent - w->phys_cursor_ascent); - - /* If the size of the active cursor changed, destroy the old - system caret. */ - if (w32_system_caret_hwnd - && (w32_system_caret_height != w->phys_cursor_height - || w32_system_caret_width != caret_width)) - PostMessage (hwnd, WM_EMACS_DESTROY_CARET, NULL, NULL); - - if (!w32_system_caret_hwnd) - { - w32_system_caret_height = w->phys_cursor_height; - w32_system_caret_width = caret_width; - } + HWND hwnd = FRAME_W32_WINDOW (f); - /* Move the system caret. */ - PostMessage (hwnd, WM_EMACS_TRACK_CARET, NULL, NULL); - } + w32_system_caret_x + = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + w32_system_caret_y + = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) + + glyph_row->ascent - w->phys_cursor_ascent); + + /* If the size of the active cursor changed, destroy the old + system caret. */ + if (w32_system_caret_hwnd + && (w32_system_caret_height != w->phys_cursor_height)) + PostMessage (hwnd, WM_EMACS_DESTROY_CARET, 0, 0); + + w32_system_caret_height = w->phys_cursor_height; + + /* Move the system caret. */ + PostMessage (hwnd, WM_EMACS_TRACK_CARET, 0, 0); } switch (new_cursor_type) @@ -9641,7 +9885,11 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) break; case BAR_CURSOR: - x_draw_bar_cursor (w, glyph_row, new_cursor_width); + x_draw_bar_cursor (w, glyph_row, new_cursor_width, BAR_CURSOR); + break; + + case HBAR_CURSOR: + x_draw_bar_cursor (w, glyph_row, new_cursor_width, HBAR_CURSOR); break; case NO_CURSOR: @@ -9743,7 +9991,7 @@ x_bitmap_icon (f, icon) if (NILP (icon)) hicon = LoadIcon (hinst, EMACS_CLASS); else if (STRINGP (icon)) - hicon = LoadImage (NULL, (LPCTSTR) XSTRING (icon)->data, IMAGE_ICON, 0, 0, + hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); else if (SYMBOLP (icon)) { @@ -9873,7 +10121,7 @@ x_new_fontset (f, fontsetname) to do. */ return fontset_name (fontset); - result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data)); + result = x_new_font (f, (SDATA (fontset_ascii (fontset)))); if (!STRINGP (result)) /* Can't load ASCII font. */ @@ -9885,6 +10133,90 @@ x_new_fontset (f, fontsetname) return build_string (fontsetname); } +/* Compute actual fringe widths */ + +void +x_compute_fringe_widths (f, redraw) + struct frame *f; + int redraw; +{ + int o_left = f->output_data.w32->left_fringe_width; + int o_right = f->output_data.w32->right_fringe_width; + int o_cols = f->output_data.w32->fringe_cols; + + Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist); + Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist); + int left_fringe_width, right_fringe_width; + + if (!NILP (left_fringe)) + left_fringe = Fcdr (left_fringe); + if (!NILP (right_fringe)) + right_fringe = Fcdr (right_fringe); + + left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 : + XINT (left_fringe)); + right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 : + XINT (right_fringe)); + + if (left_fringe_width || right_fringe_width) + { + int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width; + int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width; + int conf_wid = left_wid + right_wid; + int font_wid = FONT_WIDTH (f->output_data.w32->font); + int cols = (left_wid + right_wid + font_wid-1) / font_wid; + int real_wid = cols * font_wid; + if (left_wid && right_wid) + { + if (left_fringe_width < 0) + { + /* Left fringe width is fixed, adjust right fringe if necessary */ + f->output_data.w32->left_fringe_width = left_wid; + f->output_data.w32->right_fringe_width = real_wid - left_wid; + } + else if (right_fringe_width < 0) + { + /* Right fringe width is fixed, adjust left fringe if necessary */ + f->output_data.w32->left_fringe_width = real_wid - right_wid; + f->output_data.w32->right_fringe_width = right_wid; + } + else + { + /* Adjust both fringes with an equal amount. + Note that we are doing integer arithmetic here, so don't + lose a pixel if the total width is an odd number. */ + int fill = real_wid - conf_wid; + f->output_data.w32->left_fringe_width = left_wid + fill/2; + f->output_data.w32->right_fringe_width = right_wid + fill - fill/2; + } + } + else if (left_fringe_width) + { + f->output_data.w32->left_fringe_width = real_wid; + f->output_data.w32->right_fringe_width = 0; + } + else + { + f->output_data.w32->left_fringe_width = 0; + f->output_data.w32->right_fringe_width = real_wid; + } + f->output_data.w32->fringe_cols = cols; + f->output_data.w32->fringes_extra = real_wid; + } + else + { + f->output_data.w32->left_fringe_width = 0; + f->output_data.w32->right_fringe_width = 0; + f->output_data.w32->fringe_cols = 0; + f->output_data.w32->fringes_extra = 0; + } + + if (redraw && FRAME_VISIBLE_P (f)) + if (o_left != f->output_data.w32->left_fringe_width || + o_right != f->output_data.w32->right_fringe_width || + o_cols != f->output_data.w32->fringe_cols) + redraw_frame (f); +} /*********************************************************************** TODO: W32 Input Methods @@ -9998,6 +10330,115 @@ x_set_offset (f, xoff, yoff, change_gravity) UNBLOCK_INPUT; } + +/* Check if we need to resize the frame due to a fullscreen request. + If so needed, resize the frame. */ +static void +x_check_fullscreen (f) + struct frame *f; +{ + if (f->output_data.w32->want_fullscreen & FULLSCREEN_BOTH) + { + int width, height, ign; + + x_real_positions (f, &f->output_data.w32->left_pos, + &f->output_data.w32->top_pos); + + x_fullscreen_adjust (f, &width, &height, &ign, &ign); + + /* We do not need to move the window, it shall be taken care of + when setting WM manager hints. + If the frame is visible already, the position is checked by + x_check_fullscreen_move. */ + if (f->width != width || f->height != height) + { + change_frame_size (f, height, width, 0, 1, 0); + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + + /* Wait for the change of frame size to occur */ + f->output_data.w32->want_fullscreen |= FULLSCREEN_WAIT; + } + } +} + +/* If frame parameters are set after the frame is mapped, we need to move + the window. This is done in xfns.c. + Some window managers moves the window to the right position, some + moves the outer window manager window to the specified position. + Here we check that we are in the right spot. If not, make a second + move, assuming we are dealing with the second kind of window manager. */ +static void +x_check_fullscreen_move (f) + struct frame *f; +{ + if (f->output_data.w32->want_fullscreen & FULLSCREEN_MOVE_WAIT) + { + int expect_top = f->output_data.w32->top_pos; + int expect_left = f->output_data.w32->left_pos; + + if (f->output_data.w32->want_fullscreen & FULLSCREEN_HEIGHT) + expect_top = 0; + if (f->output_data.w32->want_fullscreen & FULLSCREEN_WIDTH) + expect_left = 0; + + if (expect_top != f->output_data.w32->top_pos + || expect_left != f->output_data.w32->left_pos) + x_set_offset (f, expect_left, expect_top, 1); + + /* Just do this once */ + f->output_data.w32->want_fullscreen &= ~FULLSCREEN_MOVE_WAIT; + } +} + + +/* Calculate fullscreen size. Return in *TOP_POS and *LEFT_POS the + wanted positions of the WM window (not emacs window). + Return in *WIDTH and *HEIGHT the wanted width and height of Emacs + window (FRAME_X_WINDOW). + */ +void +x_fullscreen_adjust (f, width, height, top_pos, left_pos) + struct frame *f; + int *width; + int *height; + int *top_pos; + int *left_pos; +{ + int newwidth = f->width, newheight = f->height; + + *top_pos = f->output_data.w32->top_pos; + *left_pos = f->output_data.w32->left_pos; + + if (f->output_data.w32->want_fullscreen & FULLSCREEN_HEIGHT) + { + int ph; + + ph = FRAME_X_DISPLAY_INFO (f)->height; + newheight = PIXEL_TO_CHAR_HEIGHT (f, ph); + ph = CHAR_TO_PIXEL_HEIGHT (f, newheight) + - f->output_data.w32->y_pixels_diff; + newheight = PIXEL_TO_CHAR_HEIGHT (f, ph); + *top_pos = 0; + } + + if (f->output_data.w32->want_fullscreen & FULLSCREEN_WIDTH) + { + int pw; + + pw = FRAME_X_DISPLAY_INFO (f)->width; + newwidth = PIXEL_TO_CHAR_WIDTH (f, pw); + pw = CHAR_TO_PIXEL_WIDTH (f, newwidth) + - f->output_data.w32->x_pixels_diff; + newwidth = PIXEL_TO_CHAR_WIDTH (f, pw); + *left_pos = 0; + } + + *width = newwidth; + *height = newheight; +} + + /* Call this to change the size of frame F's x-window. If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity for this size change and subsequent size changes. @@ -10018,8 +10459,9 @@ x_set_window_size (f, change_gravity, cols, rows) = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f) ? 0 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font))); - f->output_data.w32->fringes_extra - = FRAME_FRINGE_WIDTH (f); + + x_compute_fringe_widths (f, 0); + pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols); pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows); @@ -10269,7 +10711,7 @@ x_make_frame_visible (f) f->output_data.w32->asked_for_visible = 1; -// my_show_window (f, FRAME_W32_WINDOW (f), f->async_iconified ? SW_RESTORE : SW_SHOW); +/* my_show_window (f, FRAME_W32_WINDOW (f), f->async_iconified ? SW_RESTORE : SW_SHOW); */ my_show_window (f, FRAME_W32_WINDOW (f), SW_SHOWNORMAL); } @@ -10605,11 +11047,11 @@ w32_initialize_display_info (display_name) dpyinfo->name_list_element = XCAR (w32_display_name_list); dpyinfo->w32_id_name - = (char *) xmalloc (XSTRING (Vinvocation_name)->size - + XSTRING (Vsystem_name)->size + = (char *) xmalloc (SCHARS (Vinvocation_name) + + SCHARS (Vsystem_name) + 2); sprintf (dpyinfo->w32_id_name, "%s@%s", - XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data); + SDATA (Vinvocation_name), SDATA (Vsystem_name)); /* Default Console mode values - overridden when running in GUI mode with values obtained from system metrics. */ @@ -10628,6 +11070,7 @@ w32_initialize_display_info (display_name) dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID; dpyinfo->mouse_face_window = Qnil; dpyinfo->mouse_face_overlay = Qnil; + dpyinfo->mouse_face_hidden = 0; /* TODO: dpyinfo->gray */ } @@ -10837,7 +11280,6 @@ w32_initialize () w32_system_caret_hwnd = NULL; w32_system_caret_height = 0; - w32_system_caret_width = 0; w32_system_caret_x = 0; w32_system_caret_y = 0; @@ -10971,21 +11413,42 @@ affect on NT machines. */); staticpro (&previous_help_echo); help_echo_pos = -1; + DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window, + doc: /* *Non-nil means autoselect window with mouse pointer. */); + mouse_autoselect_window = 0; + + DEFVAR_BOOL ("w32-use-visible-system-caret", + &w32_use_visible_system_caret, + doc: /* Flag to make the system caret visible. +When this is non-nil, Emacs will indicate the position of point by +using the system caret instead of drawing its own cursor. Some screen +reader software does not track the system cursor properly when it is +invisible, and gets confused by Emacs drawing its own cursor, so this +variable is initialized to t when Emacs detects that screen reader +software is running as it starts up. + +When this variable is set, other variables affecting the appearance of +the cursor have no effect. */); + + /* Initialize w32_use_visible_system_caret based on whether a screen + reader is in use. */ + if (!SystemParametersInfo (SPI_GETSCREENREADER, 0, + &w32_use_visible_system_caret, 0)) + w32_use_visible_system_caret = 0; + DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p, doc: /* *Non-nil means draw block cursor as wide as the glyph under it. For example, if a block cursor is over a tab, it will be drawn as wide as that tab on the display. */); x_stretch_cursor_p = 0; -#if 0 /* TODO: Setting underline position from font properties. */ DEFVAR_BOOL ("x-use-underline-position-properties", &x_use_underline_position_properties, doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties. -Nil means ignore them. If you encounter fonts with bogus +nil means ignore them. If you encounter fonts with bogus UNDERLINE_POSITION font properties, for example 7x13 on XFree prior to 4.1, set this to nil. */); x_use_underline_position_properties = 1; -#endif DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars, doc: /* If not nil, Emacs uses toolkit scroll bars. */);