📄 window.c
字号:
HMENU saved_menu = NULL;
int nesting = 1;
new_menu = CreatePopupMenu();
for (i = 0; nesting > 0; i++) {
assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX);
switch (specials[i].code) {
case TS_SEP:
AppendMenu(new_menu, MF_SEPARATOR, 0, 0);
break;
case TS_SUBMENU:
assert(nesting < 2);
nesting++;
saved_menu = new_menu; /* XXX lame stacking */
new_menu = CreatePopupMenu();
AppendMenu(saved_menu, MF_POPUP | MF_ENABLED,
(UINT) new_menu, specials[i].name);
break;
case TS_EXITMENU:
nesting--;
if (nesting) {
new_menu = saved_menu; /* XXX lame stacking */
saved_menu = NULL;
}
break;
default:
AppendMenu(new_menu, MF_ENABLED, IDM_SPECIAL_MIN + 0x10 * i,
specials[i].name);
break;
}
}
/* Squirrel the highest special. */
n_specials = i - 1;
} else {
new_menu = NULL;
n_specials = 0;
}
for (j = 0; j < lenof(popup_menus); j++) {
if (specials_menu) {
/* XXX does this free up all submenus? */
DeleteMenu(popup_menus[j].menu, (UINT)specials_menu, MF_BYCOMMAND);
DeleteMenu(popup_menus[j].menu, IDM_SPECIALSEP, MF_BYCOMMAND);
}
if (new_menu) {
InsertMenu(popup_menus[j].menu, IDM_SHOWLOG,
MF_BYCOMMAND | MF_POPUP | MF_ENABLED,
(UINT) new_menu, "S&pecial Command");
InsertMenu(popup_menus[j].menu, IDM_SHOWLOG,
MF_BYCOMMAND | MF_SEPARATOR, IDM_SPECIALSEP, 0);
}
}
specials_menu = new_menu;
}
static void update_mouse_pointer(void)
{
LPTSTR curstype;
int force_visible = FALSE;
static int forced_visible = FALSE;
switch (busy_status) {
case BUSY_NOT:
if (send_raw_mouse)
curstype = IDC_ARROW;
else
curstype = IDC_IBEAM;
break;
case BUSY_WAITING:
curstype = IDC_APPSTARTING; /* this may be an abuse */
force_visible = TRUE;
break;
case BUSY_CPU:
curstype = IDC_WAIT;
force_visible = TRUE;
break;
default:
assert(0);
}
{
HCURSOR cursor = LoadCursor(NULL, curstype);
SetClassLongPtr(hwnd, GCLP_HCURSOR, (LONG_PTR)cursor);
SetCursor(cursor); /* force redraw of cursor at current posn */
}
if (force_visible != forced_visible) {
/* We want some cursor shapes to be visible always.
* Along with show_mouseptr(), this manages the ShowCursor()
* counter such that if we switch back to a non-force_visible
* cursor, the previous visibility state is restored. */
ShowCursor(force_visible);
forced_visible = force_visible;
}
}
void set_busy_status(void *frontend, int status)
{
busy_status = status;
update_mouse_pointer();
}
/*
* set or clear the "raw mouse message" mode
*/
void set_raw_mouse_mode(void *frontend, int activate)
{
activate = activate && !cfg.no_mouse_rep;
send_raw_mouse = activate;
update_mouse_pointer();
}
/*
* Print a message box and close the connection.
*/
void connection_fatal(void *frontend, char *fmt, ...)
{
va_list ap;
char *stuff, morestuff[100];
va_start(ap, fmt);
stuff = dupvprintf(fmt, ap);
va_end(ap);
sprintf(morestuff, "%.70s Fatal Error", appname);
MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK);
sfree(stuff);
if (cfg.close_on_exit == FORCE_ON)
PostQuitMessage(1);
else {
must_close_session = TRUE;
}
}
/*
* Report an error at the command-line parsing stage.
*/
void cmdline_error(char *fmt, ...)
{
va_list ap;
char *stuff, morestuff[100];
va_start(ap, fmt);
stuff = dupvprintf(fmt, ap);
va_end(ap);
sprintf(morestuff, "%.70s Command Line Error", appname);
MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK);
sfree(stuff);
exit(1);
}
/*
* Actually do the job requested by a WM_NETEVENT
*/
static void enact_pending_netevent(void)
{
static int reentering = 0;
extern int select_result(WPARAM, LPARAM);
if (reentering)
return; /* don't unpend the pending */
pending_netevent = FALSE;
reentering = 1;
select_result(pend_netevent_wParam, pend_netevent_lParam);
reentering = 0;
}
/*
* Copy the colour palette from the configuration data into defpal.
* This is non-trivial because the colour indices are different.
*/
static void cfgtopalette(void)
{
int i;
static const int ww[] = {
256, 257, 258, 259, 260, 261,
0, 8, 1, 9, 2, 10, 3, 11,
4, 12, 5, 13, 6, 14, 7, 15
};
for (i = 0; i < 22; i++) {
int w = ww[i];
defpal[w].rgbtRed = cfg.colours[i][0];
defpal[w].rgbtGreen = cfg.colours[i][1];
defpal[w].rgbtBlue = cfg.colours[i][2];
}
for (i = 0; i < NEXTCOLOURS; i++) {
if (i < 216) {
int r = i / 36, g = (i / 6) % 6, b = i % 6;
defpal[i+16].rgbtRed = r ? r * 40 + 55 : 0;
defpal[i+16].rgbtGreen = g ? g * 40 + 55 : 0;
defpal[i+16].rgbtBlue = b ? b * 40 + 55 : 0;
} else {
int shade = i - 216;
shade = shade * 10 + 8;
defpal[i+16].rgbtRed = defpal[i+16].rgbtGreen =
defpal[i+16].rgbtBlue = shade;
}
}
/* Override with system colours if appropriate */
if (cfg.system_colour)
systopalette();
}
/*
* Override bit of defpal with colours from the system.
* (NB that this takes a copy the system colours at the time this is called,
* so subsequent colour scheme changes don't take effect. To fix that we'd
* probably want to be using GetSysColorBrush() and the like.)
*/
static void systopalette(void)
{
int i;
static const struct { int nIndex; int norm; int bold; } or[] =
{
{ COLOR_WINDOWTEXT, 256, 257 }, /* Default Foreground */
{ COLOR_WINDOW, 258, 259 }, /* Default Background */
{ COLOR_HIGHLIGHTTEXT, 260, 260 }, /* Cursor Text */
{ COLOR_HIGHLIGHT, 261, 261 }, /* Cursor Colour */
};
for (i = 0; i < (sizeof(or)/sizeof(or[0])); i++) {
COLORREF colour = GetSysColor(or[i].nIndex);
defpal[or[i].norm].rgbtRed =
defpal[or[i].bold].rgbtRed = GetRValue(colour);
defpal[or[i].norm].rgbtGreen =
defpal[or[i].bold].rgbtGreen = GetGValue(colour);
defpal[or[i].norm].rgbtBlue =
defpal[or[i].bold].rgbtBlue = GetBValue(colour);
}
}
/*
* Set up the colour palette.
*/
static void init_palette(void)
{
int i;
HDC hdc = GetDC(hwnd);
if (hdc) {
if (cfg.try_palette && GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) {
/*
* This is a genuine case where we must use smalloc
* because the snew macros can't cope.
*/
logpal = smalloc(sizeof(*logpal)
- sizeof(logpal->palPalEntry)
+ NALLCOLOURS * sizeof(PALETTEENTRY));
logpal->palVersion = 0x300;
logpal->palNumEntries = NALLCOLOURS;
for (i = 0; i < NALLCOLOURS; i++) {
logpal->palPalEntry[i].peRed = defpal[i].rgbtRed;
logpal->palPalEntry[i].peGreen = defpal[i].rgbtGreen;
logpal->palPalEntry[i].peBlue = defpal[i].rgbtBlue;
logpal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
}
pal = CreatePalette(logpal);
if (pal) {
SelectPalette(hdc, pal, FALSE);
RealizePalette(hdc);
SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
}
}
ReleaseDC(hwnd, hdc);
}
if (pal)
for (i = 0; i < NALLCOLOURS; i++)
colours[i] = PALETTERGB(defpal[i].rgbtRed,
defpal[i].rgbtGreen,
defpal[i].rgbtBlue);
else
for (i = 0; i < NALLCOLOURS; i++)
colours[i] = RGB(defpal[i].rgbtRed,
defpal[i].rgbtGreen, defpal[i].rgbtBlue);
}
/*
* This is a wrapper to ExtTextOut() to force Windows to display
* the precise glyphs we give it. Otherwise it would do its own
* bidi and Arabic shaping, and we would end up uncertain which
* characters it had put where.
*/
static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc,
unsigned short *lpString, UINT cbCount,
CONST INT *lpDx, int opaque)
{
#ifdef __LCC__
/*
* The LCC include files apparently don't supply the
* GCP_RESULTSW type, but we can make do with GCP_RESULTS
* proper: the differences aren't important to us (the only
* variable-width string parameter is one we don't use anyway).
*/
GCP_RESULTS gcpr;
#else
GCP_RESULTSW gcpr;
#endif
char *buffer = snewn(cbCount*2+2, char);
char *classbuffer = snewn(cbCount, char);
memset(&gcpr, 0, sizeof(gcpr));
memset(buffer, 0, cbCount*2+2);
memset(classbuffer, GCPCLASS_NEUTRAL, cbCount);
gcpr.lStructSize = sizeof(gcpr);
gcpr.lpGlyphs = (void *)buffer;
gcpr.lpClass = (void *)classbuffer;
gcpr.nGlyphs = cbCount;
GetCharacterPlacementW(hdc, lpString, cbCount, 0, &gcpr,
FLI_MASK | GCP_CLASSIN | GCP_DIACRITIC);
ExtTextOut(hdc, x, y,
ETO_GLYPH_INDEX | ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0),
lprc, buffer, cbCount, lpDx);
}
/*
* The exact_textout() wrapper, unfortunately, destroys the useful
* Windows `font linking' behaviour: automatic handling of Unicode
* code points not supported in this font by falling back to a font
* which does contain them. Therefore, we adopt a multi-layered
* approach: for any potentially-bidi text, we use exact_textout(),
* and for everything else we use a simple ExtTextOut as we did
* before exact_textout() was introduced.
*/
static void general_textout(HDC hdc, int x, int y, CONST RECT *lprc,
unsigned short *lpString, UINT cbCount,
CONST INT *lpDx, int opaque)
{
int i, j, xp, xn;
RECT newrc;
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
int k;
debug(("general_textout: %d,%d", x, y));
for(k=0;k<cbCount;k++)debug((" U+%04X", lpString[k]));
debug(("\n rect: [%d,%d %d,%d]", lprc->left, lprc->top, lprc->right, lprc->bottom));
debug(("\n"));
#endif
xp = xn = x;
for (i = 0; i < (int)cbCount ;) {
int rtl = is_rtl(lpString[i]);
xn += lpDx[i];
for (j = i+1; j < (int)cbCount; j++) {
if (rtl != is_rtl(lpString[j]))
break;
xn += lpDx[j];
}
/*
* Now [i,j) indicates a maximal substring of lpString
* which should be displayed using the same textout
* function.
*/
if (rtl) {
newrc.left = lprc->left + xp - x;
newrc.right = lprc->left + xn - x;
newrc.top = lprc->top;
newrc.bottom = lprc->bottom;
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
{
int k;
debug((" exact_textout: %d,%d", xp, y));
for(k=0;k<j-i;k++)debug((" U+%04X", lpString[i+k]));
debug(("\n rect: [%d,%d %d,%d]\n", newrc.left, newrc.top, newrc.right, newrc.bottom));
}
#endif
exact_textout(hdc, xp, y, &newrc, lpString+i, j-i, lpDx+i, opaque);
} else {
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
{
int k;
debug((" ExtTextOut : %d,%d", xp, y));
for(k=0;k<j-i;k++)debug((" U+%04X", lpString[i+k]));
debug(("\n rect: [%d,%d %d,%d]\n", newrc.left, newrc.top, newrc.right, newrc.bottom));
}
#endif
newrc.left = lprc->left + xp - x;
newrc.right = lprc->left + xn - x;
newrc.top = lprc->top;
newrc.bottom = lprc->bottom;
ExtTextOutW(hdc, xp, y, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0),
&newrc, lpString+i, j-i, lpDx+i);
}
i = j;
xp = xn;
}
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
debug(("general_textout: done, xn=%d\n", xn));
#endif
assert(xn - x == lprc->right - lprc->left);
}
/*
* Initialise all the fonts we will need initially. There may be as many as
* three or as few as one. The other (poentially) twentyone fonts are done
* if/when they are needed.
*
* We also:
*
* - check the font width and height, correcting our guesses if
* necessary.
*
* - verify that the bold font is the same width as the ordinary
* one, and engage shadow bolding if not.
*
* - verify that the underlined font is the same width as the
* ordinary one (manual underlining by means of line drawing can
* be done in a pinch).
*/
static void init_fonts(int pick_width, int pick_height)
{
TEXTMETRIC tm;
CPINFO cpinfo;
int fontsize[3];
int i;
HDC hdc;
int fw_dontcare, fw_bold;
for (i = 0; i < FONT_MAXNO; i++)
fonts[i] = NULL;
bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;
und_mode = UND_FONT;
if (cfg.font.isbold) {
fw_dontcare = FW_BOLD;
fw_bold = FW_HEAVY;
} else {
fw_dontcare = FW_DONTCARE;
fw_bold = FW_BOLD;
}
hdc = GetDC(hwnd);
if (pick_height)
font_height = pick_height;
else {
font_height = cfg.font.height;
if (font_height > 0) {
font_height =
-MulDiv(font_height, GetDeviceCaps(hdc, LOGPIXELSY), 72);
}
}
font_width = pick_width;
#define f(i,c,w,u) \
fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \
c, OUT_DEFAULT_PRECIS, \
CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg.font_quality), \
FIXED_PITCH | FF_DONTCARE, cfg.font.name)
f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE);
SelectObject(hdc, fonts[FONT_NORMAL]);
GetTextMetrics(hdc, &tm);
GetObject(fonts[FONT_NORMAL], sizeof(LOGFONT), &lfont);
if (pick_width == 0 || pick_height == 0) {
font_height = tm.tmHeight;
font_width = tm.tmAveCharWidth;
}
font_dualwidth = (tm.tmAveCharWidth != tm.tmMaxCharWidth);
#ifdef RDB_DEBUG_PATCH
debug(23, "Primary font H=%d, AW=%d, MW=%d",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -