/* Implementation of GUI terminal on the Microsoft W32 API.
Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <setjmp.h>
#include "lisp.h"
#include "blockinput.h"
#include "w32term.h"
#include <ctype.h>
#include <errno.h>
-#include <setjmp.h>
#include <sys/stat.h>
+#include <imm.h>
#include "charset.h"
#include "character.h"
#endif
/* Dynamic linking to SetLayeredWindowAttribute (only since 2000). */
-BOOL (PASCAL *pfnSetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
+BOOL (WINAPI *pfnSetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
#ifndef LWA_ALPHA
#define LWA_ALPHA 0x02
/* Mouse movement. */
/* Where the mouse was last time we reported a mouse event. */
-
static RECT last_mouse_glyph;
static FRAME_PTR last_mouse_glyph_frame;
static Lisp_Object last_mouse_press_frame;
along with the position query. So, we just keep track of the time
of the last movement we received, and return that in hopes that
it's somewhat accurate. */
-
static Time last_mouse_movement_time;
/* Incremented by w32_read_socket whenever it really tries to read
events. */
-
#ifdef __STDC__
static int volatile input_signal_count;
#else
#endif
/* A mask of extra modifier bits to put into every keyboard char. */
-
extern EMACS_INT extra_keyboard_modifiers;
+/* Keyboard code page - may be changed by language-change events. */
+static int keyboard_codepage;
+
static void x_update_window_end P_ ((struct window *, int, int));
static void w32_handle_tool_bar_click P_ ((struct frame *,
struct input_event *));
else if (INTEGERP (Vframe_alpha_lower_limit))
alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
- if (alpha < 0.0 || 1.0 < alpha)
+ if (alpha < 0.0)
+ return;
+ else if (alpha > 1.0)
alpha = 1.0;
else if (alpha < alpha_min && alpha_min <= 1.0)
alpha = alpha_min;
pfnSetLayeredWindowAttributes (window, 0, opac, LWA_ALPHA);
}
+int
+x_display_pixel_height (dpyinfo)
+ struct w32_display_info *dpyinfo;
+{
+ HDC dc = GetDC (NULL);
+ int pixels = GetDeviceCaps (dc, VERTRES);
+ ReleaseDC (NULL, dc);
+ return pixels;
+}
+
+int
+x_display_pixel_width (dpyinfo)
+ struct w32_display_info *dpyinfo;
+{
+ HDC dc = GetDC (NULL);
+ int pixels = GetDeviceCaps (dc, HORZRES);
+ ReleaseDC (NULL, dc);
+ return pixels;
+}
+
\f
/***********************************************************************
Starting and ending an update
struct glyph_string *s;
{
int i, j, x;
+ struct font *font = s->font;
/* If first glyph of S has a left box line, start drawing the text
of S to the right of that box line. */
else
x = s->x;
- /* S is a glyph string for a composition. S->gidx is the index of
- the first character drawn for glyphs of this composition.
- S->gidx == 0 means we are drawing the very first character of
+ /* S is a glyph string for a composition. S->cmp_from is the index
+ of the first character drawn for glyphs of this composition.
+ S->cmp_from == 0 means we are drawing the very first character of
this composition. */
SetTextColor (s->hdc, s->gc->foreground);
first character of the composition could not be loaded. */
if (s->font_not_found_p)
{
- if (s->gidx == 0)
+ if (s->cmp_from == 0)
w32_draw_rectangle (s->hdc, s->gc, x, s->y, s->width - 1,
s->height - 1);
}
+ else if (! s->first_glyph->u.cmp.automatic)
+ {
+ int y = s->ybase;
+ int width = 0;
+ HFONT old_font;
+
+ old_font = SelectObject (s->hdc, FONT_HANDLE (font));
+
+ for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
+ if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
+ {
+ int xx = x + s->cmp->offsets[j * 2];
+ int yy = y - s->cmp->offsets[j * 2 + 1];
+
+ font->driver->draw (s, j, j + 1, xx, yy, 0);
+ if (s->face->overstrike)
+ font->driver->draw (s, j, j + 1, xx + 1, yy, 0);
+ }
+ SelectObject (s->hdc, old_font);
+ }
else
{
- struct font *font = s->font;
+ Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
+ Lisp_Object glyph;
int y = s->ybase;
int width = 0;
HFONT old_font;
old_font = SelectObject (s->hdc, FONT_HANDLE (font));
- if (s->cmp->method == COMPOSITION_WITH_GLYPH_STRING)
+ for (i = j = s->cmp_from; i < s->cmp_to; i++)
{
- Lisp_Object gstring = AREF (XHASH_TABLE (composition_hash_table)
- ->key_and_value,
- s->cmp->hash_index * 2);
- int from;
-
- for (i = from = 0; i < s->nchars; i++)
+ glyph = LGSTRING_GLYPH (gstring, i);
+ if (NILP (LGLYPH_ADJUSTMENT (glyph)))
+ width += LGLYPH_WIDTH (glyph);
+ else
{
- Lisp_Object g = LGSTRING_GLYPH (gstring, i);
- Lisp_Object adjustment = LGLYPH_ADJUSTMENT (g);
int xoff, yoff, wadjust;
- if (! VECTORP (adjustment))
+ if (j < i)
{
- width += LGLYPH_WIDTH (g);
- continue;
- }
- if (from < i)
- {
- font->driver->draw (s, from, i, x, y, 0);
+ font->driver->draw (s, j, i, x, y, 0);
x += width;
}
- xoff = XINT (AREF (adjustment, 0));
- yoff = XINT (AREF (adjustment, 1));
- wadjust = XINT (AREF (adjustment, 2));
-
+ xoff = LGLYPH_XOFF (glyph);
+ yoff = LGLYPH_YOFF (glyph);
+ wadjust = LGLYPH_WADJUST (glyph);
font->driver->draw (s, i, i + 1, x + xoff, y + yoff, 0);
x += wadjust;
- from = i + 1;
+ j = i + 1;
width = 0;
}
- if (from < i)
- font->driver->draw (s, from, i, x, y, 0);
}
- else
- {
- for (i = 0, j = s->gidx; i < s->nchars; i++, j++)
- if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
- {
- int xx = x + s->cmp->offsets[j * 2];
- int yy = y - s->cmp->offsets[j * 2 + 1];
+ if (j < i)
+ font->driver->draw (s, j, i, x, y, 0);
- font->driver->draw (s, j, j + 1, xx, yy, 0);
- if (s->face->overstrike)
- font->driver->draw (s, j, j + 1, xx + 1, yy, 0);
- }
- }
SelectObject (s->hdc, old_font);
}
}
return 1;
}
+/* On frame F, translate pixel colors to RGB values for the NCOLORS
+ colors in COLORS. On W32, we no longer try to map colors to
+ a palette. */
+void
+x_query_colors (f, colors, ncolors)
+ struct frame *f;
+ XColor *colors;
+ int ncolors;
+{
+ int i;
+
+ for (i = 0; i < ncolors; i++)
+ {
+ DWORD pixel = colors[i].pixel;
+ /* Convert to a 16 bit value in range 0 - 0xffff. */
+ colors[i].red = GetRValue (pixel) * 257;
+ colors[i].green = GetGValue (pixel) * 257;
+ colors[i].blue = GetBValue (pixel) * 257;
+ }
+}
+
+void
+x_query_color (f, color)
+ struct frame *f;
+ XColor *color;
+{
+ x_query_colors (f, color, 1);
+}
+
/* Set up the foreground color for drawing relief lines of glyph
string S. RELIEF is a pointer to a struct relief containing the GC
{
int width;
struct glyph_string *next;
- for (width = 0, next = s->next; next;
+ for (width = 0, next = s->next;
+ next && width < s->right_overhang;
width += next->width, next = next->next)
if (next->first_glyph->type != IMAGE_GLYPH)
{
x_set_glyph_string_gc (next);
x_set_glyph_string_clipping (next);
- x_draw_glyph_string_background (next, 1);
+ if (next->first_glyph->type == STRETCH_GLYPH)
+ x_draw_stretch_glyph_string (next);
+ else
+ x_draw_glyph_string_background (next, 1);
next->num_clips = 0;
}
}
break;
case COMPOSITE_GLYPH:
- if (s->for_overlaps || s->gidx > 0)
+ if (s->for_overlaps || (s->cmp_from > 0
+ && ! s->first_glyph->u.cmp.automatic))
s->background_filled_p = 1;
else
x_draw_glyph_string_background (s, 1);
if (s->face->underline_defaulted_p)
{
w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
- y, s->background_width, 1);
+ y, s->width, 1);
}
else
{
w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x,
- y, s->background_width, 1);
+ y, s->width, 1);
}
}
/* Draw overline. */
if (s->face->overline_color_defaulted_p)
{
w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
- s->y + dy, s->background_width, h);
+ s->y + dy, s->width, h);
}
else
{
w32_fill_area (s->f, s->hdc, s->face->overline_color, s->x,
- s->y + dy, s->background_width, h);
+ s->y + dy, s->width, h);
}
}
return value;
}
+static int codepage_for_locale(LCID locale)
+{
+ char cp[20];
+
+ if (GetLocaleInfo (locale, LOCALE_IDEFAULTANSICODEPAGE, cp, 20) > 0)
+ return atoi (cp);
+ else
+ return CP_ACP;
+}
\f
/* Mouse clicks and mouse movement. Rah. */
switch (msg.msg.message)
{
- case WM_PAINT:
+ case WM_EMACS_PAINT:
f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
if (f)
/* Generate a language change event. */
f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+ /* lParam contains the input lang ID. Use it to update our
+ record of the keyboard codepage. */
+ keyboard_codepage = codepage_for_locale ((LCID)(msg.msg.lParam
+ & 0xffff));
+
if (f)
{
inev.kind = LANGUAGE_CHANGE_EVENT;
{
dbcs[0] = dbcs_lead;
dbcs_lead = 0;
- if (!MultiByteToWideChar (CP_ACP, 0, dbcs, 2, &code, 1))
+ if (!MultiByteToWideChar (keyboard_codepage, 0,
+ dbcs, 2, &code, 1))
{
/* Garbage */
DebPrint (("Invalid DBCS sequence: %d %d\n",
break;
}
}
- else if (IsDBCSLeadByteEx (CP_ACP, (BYTE) msg.msg.wParam))
+ else if (IsDBCSLeadByteEx (keyboard_codepage,
+ (BYTE) msg.msg.wParam))
{
dbcs_lead = (char) msg.msg.wParam;
inev.kind = NO_EVENT;
}
else
{
- if (!MultiByteToWideChar (CP_ACP, 0, &dbcs[1], 1,
- &code, 1))
+ if (!MultiByteToWideChar (keyboard_codepage, 0,
+ &dbcs[1], 1, &code, 1))
{
/* What to do with garbage? */
DebPrint (("Invalid character: %d\n", dbcs[1]));
if (f)
{
- dpyinfo->width = (short) LOWORD (msg.msg.lParam);
- dpyinfo->height = (short) HIWORD (msg.msg.lParam);
dpyinfo->n_cbits = msg.msg.wParam;
- DebPrint (("display change: %d %d\n", dpyinfo->width,
- dpyinfo->height));
+ DebPrint (("display change: %d %d\n",
+ (short) LOWORD (msg.msg.lParam),
+ (short) HIWORD (msg.msg.lParam)));
}
check_visibility = 1;
{
struct frame *f = XFRAME (w->frame);
struct glyph *cursor_glyph;
- int x;
- HDC hdc;
/* If cursor is out of bounds, don't draw garbage. This can happen
in mini-buffer windows when switching between echo area glyphs
{
COLORREF cursor_color = f->output_data.w32->cursor_pixel;
struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
+ int x;
+ HDC hdc;
/* If the glyph's background equals the color we normally draw
the bar cursor in, the bar cursor in its normal color is
x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
- if (width < 0)
- width = FRAME_CURSOR_WIDTH (f);
- width = min (cursor_glyph->pixel_width, width);
-
- w->phys_cursor_width = width;
-
-
hdc = get_frame_dc (f);
w32_clip_to_row (w, row, TEXT_AREA, hdc);
if (kind == BAR_CURSOR)
{
+ if (width < 0)
+ width = FRAME_CURSOR_WIDTH (f);
+ width = min (cursor_glyph->pixel_width, width);
+
+ w->phys_cursor_width = width;
+
w32_fill_area (f, hdc, cursor_color, x,
WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
width, row->height);
}
else
{
+ int dummy_x, dummy_y, dummy_h;
+
+ if (width < 0)
+ width = row->height;
+
+ width = min (row->height, width);
+
+ get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
+ &dummy_y, &dummy_h);
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);
+ w->phys_cursor_width, width);
}
w32_set_clip_rectangle (hdc, NULL);
= (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
+ glyph_row->ascent - w->phys_cursor_ascent);
+ PostMessage (hwnd, WM_IME_STARTCOMPOSITION, 0, 0);
+
/* If the size of the active cursor changed, destroy the old
system caret. */
if (w32_system_caret_hwnd
if (FRAME_FONT (f) == font)
/* This font is already set in frame F. There's nothing more to
do. */
- return fontset_name (fontset);
-
- BLOCK_INPUT;
+ return font_object;
FRAME_FONT (f) = font;
FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
}
-#ifdef HAVE_X_I18N
- if (FRAME_XIC (f)
- && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
- xic_set_xfontset (f, SDATA (fontset_ascii (fontset)));
-#endif
-
- UNBLOCK_INPUT;
+ /* X version sets font of input methods here also. */
- return fontset_name (fontset);
+ return font_object;
}
\f
/* Treat negative positions as relative to the rightmost bottommost
position that fits on the screen. */
if (flags & XNegative)
- f->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
+ f->left_pos = (x_display_pixel_width (FRAME_W32_DISPLAY_INFO (f))
- FRAME_PIXEL_WIDTH (f)
+ f->left_pos
- (left_right_borders_width - 1));
if (flags & YNegative)
- f->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height
+ f->top_pos = (x_display_pixel_height (FRAME_W32_DISPLAY_INFO (f))
- FRAME_PIXEL_HEIGHT (f)
+ f->top_pos
- (top_bottom_borders_height - 1));
with values obtained from system metrics. */
dpyinfo->resx = 1;
dpyinfo->resy = 1;
- dpyinfo->height_in = 1;
- dpyinfo->width_in = 1;
dpyinfo->n_planes = 1;
dpyinfo->n_cbits = 4;
dpyinfo->n_fonts = 0;
struct w32_display_info *dpyinfo = terminal->display_info.w32;
int i;
- /* Protect against recursive calls. Fdelete_frame in
+ /* Protect against recursive calls. delete_frame in
delete_terminal calls us back when it deletes our last frame. */
if (!terminal->name)
return;
dpyinfo->next = x_display_list;
x_display_list = dpyinfo;
- hdc = GetDC (GetDesktopWindow ());
+ hdc = GetDC (NULL);
- dpyinfo->height = GetDeviceCaps (hdc, VERTRES);
- dpyinfo->width = GetDeviceCaps (hdc, HORZRES);
dpyinfo->root_window = GetDesktopWindow ();
dpyinfo->n_planes = GetDeviceCaps (hdc, PLANES);
dpyinfo->n_cbits = GetDeviceCaps (hdc, BITSPIXEL);
dpyinfo->resx = GetDeviceCaps (hdc, LOGPIXELSX);
dpyinfo->resy = GetDeviceCaps (hdc, LOGPIXELSY);
dpyinfo->has_palette = GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE;
- dpyinfo->terminal->image_cache = make_image_cache ();
- dpyinfo->height_in = dpyinfo->height / dpyinfo->resx;
- dpyinfo->width_in = dpyinfo->width / dpyinfo->resy;
- ReleaseDC (GetDesktopWindow (), hdc);
+ ReleaseDC (NULL, hdc);
/* initialise palette with white and black */
{
static void
w32_initialize ()
{
+ HANDLE shell;
+ HRESULT (WINAPI * set_user_model) (wchar_t * id);
+
baud_rate = 19200;
w32_system_caret_hwnd = NULL;
w32_system_caret_x = 0;
w32_system_caret_y = 0;
+ /* On Windows 7 and later, we need to set the user model ID
+ to associate emacsclient launched files with Emacs frames
+ in the UI. */
+ shell = GetModuleHandle ("shell32.dll");
+ if (shell)
+ {
+ set_user_model
+ = (void *) GetProcAddress (shell,
+ "SetCurrentProcessExplicitAppUserModelID");
+
+ /* If the function is defined, then we are running on Windows 7
+ or newer, and the UI uses this to group related windows
+ together. Since emacs, runemacs, emacsclient are related, we
+ want them grouped even though the executables are different,
+ so we need to set a consistent ID between them. */
+ if (set_user_model)
+ set_user_model (L"GNU.Emacs");
+ }
+
/* Initialize w32_use_visible_system_caret based on whether a screen
reader is in use. */
if (!SystemParametersInfo (SPI_GETSCREENREADER, 0,
8 bit character input, standard quit char. */
Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
- /* Create the window thread - it will terminate itself or when the app terminates */
+ {
+ DWORD input_locale_id = (DWORD) GetKeyboardLayout (0);
+ keyboard_codepage = codepage_for_locale ((LCID) (input_locale_id & 0xffff));
+ }
+ /* Create the window thread - it will terminate itself when the app
+ terminates */
init_crit ();
dwMainThreadId = GetCurrentThreadId ();
GetCurrentProcess (), &hMainThread, 0, TRUE, DUPLICATE_SAME_ACCESS);
/* Wait for thread to start */
-
{
MSG msg;
/* Dynamically link to optional system components. */
{
- HANDLE user_lib = LoadLibrary ("user32.dll");
+ HMODULE user_lib = GetModuleHandle ("user32.dll");
#define LOAD_PROC(lib, fn) pfn##fn = (void *) GetProcAddress (lib, #fn)
#undef LOAD_PROC
- FreeLibrary (user_lib);
-
/* Ensure scrollbar handle is at least 5 pixels. */
vertical_scroll_bar_min_handle = 5;
doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
A value of 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.
-
-NOTE: Not supported on MS-Windows yet. */);
+to 4.1, set this to nil. */);
x_use_underline_position_properties = 0;
DEFVAR_BOOL ("x-underline-at-descent-line",