"Fossies" - the Fresh Open Source Software Archive

Member "wine-6.0.1/programs/conhost/window.c" (7 Jun 2021, 94030 Bytes) of package /linux/misc/wine-6.0.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "window.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.0_vs_6.0.1.

    1 /*
    2  * Copyright 2001 Eric Pouech
    3  * Copyright 2020 Jacek Caban for CodeWeavers
    4  *
    5  * This library is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU Lesser General Public
    7  * License as published by the Free Software Foundation; either
    8  * version 2.1 of the License, or (at your option) any later version.
    9  *
   10  * This library is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13  * Lesser General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU Lesser General Public
   16  * License along with this library; if not, write to the Free Software
   17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   18  */
   19 
   20 #define NONAMELESSUNION
   21 #include <stdlib.h>
   22 
   23 #include "conhost.h"
   24 
   25 #include <commctrl.h>
   26 #include <winreg.h>
   27 
   28 #include "wine/debug.h"
   29 
   30 WINE_DEFAULT_DEBUG_CHANNEL(console);
   31 
   32 #define WM_UPDATE_CONFIG  (WM_USER + 1)
   33 
   34 enum update_state
   35 {
   36     UPDATE_NONE,
   37     UPDATE_PENDING,
   38     UPDATE_BUSY
   39 };
   40 
   41 struct console_window
   42 {
   43     HDC               mem_dc;          /* memory DC holding the bitmap below */
   44     HBITMAP           bitmap;          /* bitmap of display window content */
   45     HFONT             font;            /* font used for rendering, usually fixed */
   46     HMENU             popup_menu;      /* popup menu triggered by right mouse click */
   47     HBITMAP           cursor_bitmap;   /* bitmap used for the caret */
   48     BOOL              in_selection;    /* an area is being selected */
   49     COORD             selection_start; /* selection coordinates */
   50     COORD             selection_end;
   51     unsigned int      ui_charset;      /* default UI charset */
   52     WCHAR            *config_key;      /* config registry key name */
   53     LONG              ext_leading;     /* external leading for font */
   54 
   55     BOOL              quick_edit;      /* whether mouse ops are sent to app or used for content selection */
   56     unsigned int      menu_mask;       /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
   57     COORD             win_pos;         /* position (in cells) of visible part of screen buffer in window */
   58     unsigned int      win_width;       /* size (in cells) of visible part of window (width & height) */
   59     unsigned int      win_height;
   60     unsigned int      cursor_size;     /* in % of cell height */
   61     int               cursor_visible;  /* cursor visibility */
   62     unsigned int      sb_width;        /* active screen buffer width */
   63     unsigned int      sb_height;       /* active screen buffer height */
   64     COORD             cursor_pos;      /* cursor position */
   65 
   66     RECT              update;          /* screen buffer update rect */
   67     enum update_state update_state;    /* update state */
   68 };
   69 
   70 struct console_config
   71 {
   72     DWORD         color_map[16];  /* console color table */
   73     unsigned int  cell_width;     /* width in pixels of a character */
   74     unsigned int  cell_height;    /* height in pixels of a character */
   75     unsigned int  cursor_size;    /* in % of cell height */
   76     int           cursor_visible; /* cursor visibility */
   77     unsigned int  attr;           /* default fill attributes (screen colors) */
   78     unsigned int  popup_attr ;    /* pop-up color attributes */
   79     unsigned int  history_size;   /* number of commands in history buffer */
   80     unsigned int  history_mode;   /* flag if commands are not stored twice in buffer */
   81     unsigned int  insert_mode;    /* TRUE to insert text at the cursor location; FALSE to overwrite it */
   82     unsigned int  menu_mask;      /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
   83     unsigned int  quick_edit;     /* whether mouse ops are sent to app or used for content selection */
   84     unsigned int  sb_width;       /* active screen buffer width */
   85     unsigned int  sb_height;      /* active screen buffer height */
   86     unsigned int  win_width;      /* size (in cells) of visible part of window (width & height) */
   87     unsigned int  win_height;
   88     COORD         win_pos;        /* position (in cells) of visible part of screen buffer in window */
   89     unsigned int  edition_mode;   /* edition mode flavor while line editing */
   90     unsigned int  font_pitch_family;
   91     unsigned int  font_weight;
   92     WCHAR         face_name[LF_FACESIZE];
   93 };
   94 
   95 static const char *debugstr_config( const struct console_config *config )
   96 {
   97     return wine_dbg_sprintf( "cell=(%u,%u) cursor=(%d,%d) attr=%02x pop-up=%02x font=%s/%u/%u "
   98                              "hist=%u/%d flags=%c%c msk=%08x sb=(%u,%u) win=(%u,%u)x(%u,%u) edit=%u",
   99                              config->cell_width, config->cell_height, config->cursor_size,
  100                              config->cursor_visible, config->attr, config->popup_attr,
  101                              wine_dbgstr_w(config->face_name), config->font_pitch_family,
  102                              config->font_weight, config->history_size,
  103                              config->history_mode ? 1 : 2,
  104                              config->insert_mode ? 'I' : 'i',
  105                              config->quick_edit ? 'Q' : 'q',
  106                              config->menu_mask, config->sb_width, config->sb_height,
  107                              config->win_pos.X, config->win_pos.Y, config->win_width,
  108                              config->win_height, config->edition_mode );
  109 }
  110 
  111 static const char *debugstr_logfont( const LOGFONTW *lf, unsigned int ft )
  112 {
  113     return wine_dbg_sprintf( "%s%s%s%s  lfHeight=%d lfWidth=%d lfEscapement=%d "
  114                              "lfOrientation=%d lfWeight=%d lfItalic=%u lfUnderline=%u "
  115                              "lfStrikeOut=%u lfCharSet=%u lfPitchAndFamily=%u lfFaceName=%s",
  116                              (ft & RASTER_FONTTYPE) ? "raster" : "",
  117                              (ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
  118                              ((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
  119                              (ft & DEVICE_FONTTYPE) ? "|device" : "",
  120                              lf->lfHeight, lf->lfWidth, lf->lfEscapement, lf->lfOrientation,
  121                              lf->lfWeight, lf->lfItalic, lf->lfUnderline, lf->lfStrikeOut,
  122                              lf->lfCharSet,  lf->lfPitchAndFamily, wine_dbgstr_w( lf->lfFaceName ));
  123 }
  124 
  125 static const char *debugstr_textmetric( const TEXTMETRICW *tm, unsigned int ft )
  126 {
  127         return wine_dbg_sprintf( "%s%s%s%s tmHeight=%d tmAscent=%d tmDescent=%d "
  128                                  "tmAveCharWidth=%d tmMaxCharWidth=%d tmWeight=%d "
  129                                  "tmPitchAndFamily=%u tmCharSet=%u",
  130                                  (ft & RASTER_FONTTYPE) ? "raster" : "",
  131                                  (ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
  132                                  ((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
  133                                  (ft & DEVICE_FONTTYPE) ? "|device" : "",
  134                                  tm->tmHeight, tm->tmAscent, tm->tmDescent, tm->tmAveCharWidth,
  135                                  tm->tmMaxCharWidth, tm->tmWeight, tm->tmPitchAndFamily,
  136                                  tm->tmCharSet );
  137 }
  138 
  139 /* read the basic configuration from any console key or subkey */
  140 static void load_registry_key( HKEY key, struct console_config *config )
  141 {
  142     DWORD type, count, val, i;
  143     WCHAR color_name[13];
  144 
  145     for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
  146     {
  147         wsprintfW( color_name, L"ColorTable%02d", i );
  148         count = sizeof(val);
  149         if (!RegQueryValueExW( key, color_name, 0, &type, (BYTE *)&val, &count ))
  150             config->color_map[i] = val;
  151     }
  152 
  153     count = sizeof(val);
  154     if (!RegQueryValueExW( key, L"CursorSize", 0, &type, (BYTE *)&val, &count ))
  155         config->cursor_size = val;
  156 
  157     count = sizeof(val);
  158     if (!RegQueryValueExW( key, L"CursorVisible", 0, &type, (BYTE *)&val, &count ))
  159         config->cursor_visible = val;
  160 
  161     count = sizeof(val);
  162     if (!RegQueryValueExW( key, L"EditionMode", 0, &type, (BYTE *)&val, &count ))
  163         config->edition_mode = val;
  164 
  165     count = sizeof(config->face_name);
  166     RegQueryValueExW( key, L"FaceName", 0, &type, (BYTE *)&config->face_name, &count );
  167 
  168     count = sizeof(val);
  169     if (!RegQueryValueExW( key, L"FontPitchFamily", 0, &type, (BYTE *)&val, &count ))
  170         config->font_pitch_family = val;
  171 
  172     count = sizeof(val);
  173     if (!RegQueryValueExW( key, L"FontSize", 0, &type, (BYTE *)&val, &count ))
  174     {
  175         int height = HIWORD(val);
  176         int width  = LOWORD(val);
  177         /* A value of zero reflects the default settings */
  178         if (height) config->cell_height = MulDiv( height, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
  179         if (width)  config->cell_width  = MulDiv( width,  GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
  180     }
  181 
  182     count = sizeof(val);
  183     if (!RegQueryValueExW( key, L"FontWeight", 0, &type, (BYTE *)&val, &count ))
  184         config->font_weight = val;
  185 
  186     count = sizeof(val);
  187     if (!RegQueryValueExW( key, L"HistoryBufferSize", 0, &type, (BYTE *)&val, &count ))
  188         config->history_size = val;
  189 
  190     count = sizeof(val);
  191     if (!RegQueryValueExW( key, L"HistoryNoDup", 0, &type, (BYTE *)&val, &count ))
  192         config->history_mode = val;
  193 
  194     count = sizeof(val);
  195     if (!RegQueryValueExW( key, L"wszInsertMode", 0, &type, (BYTE *)&val, &count ))
  196         config->insert_mode = val;
  197 
  198     count = sizeof(val);
  199     if (!RegQueryValueExW( key, L"MenuMask", 0, &type, (BYTE *)&val, &count ))
  200         config->menu_mask = val;
  201 
  202     count = sizeof(val);
  203     if (!RegQueryValueExW( key, L"PopupColors", 0, &type, (BYTE *)&val, &count ))
  204         config->popup_attr = val;
  205 
  206     count = sizeof(val);
  207     if (!RegQueryValueExW( key, L"QuickEdit", 0, &type, (BYTE *)&val, &count ))
  208         config->quick_edit = val;
  209 
  210     count = sizeof(val);
  211     if (!RegQueryValueExW( key, L"ScreenBufferSize", 0, &type, (BYTE *)&val, &count ))
  212     {
  213         config->sb_height = HIWORD(val);
  214         config->sb_width  = LOWORD(val);
  215     }
  216 
  217     count = sizeof(val);
  218     if (!RegQueryValueExW( key, L"ScreenColors", 0, &type, (BYTE *)&val, &count ))
  219         config->attr = val;
  220 
  221     count = sizeof(val);
  222     if (!RegQueryValueExW( key, L"WindowSize", 0, &type, (BYTE *)&val, &count ))
  223     {
  224         config->win_height = HIWORD(val);
  225         config->win_width  = LOWORD(val);
  226     }
  227 }
  228 
  229 /* load config from registry */
  230 static void load_config( const WCHAR *key_name, struct console_config *config )
  231 {
  232     static const COLORREF color_map[] =
  233     {
  234         RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
  235         RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0xC0, 0xC0, 0xC0),
  236         RGB(0x80, 0x80, 0x80), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
  237         RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF)
  238     };
  239 
  240     HKEY key, app_key;
  241 
  242     TRACE("loading %s registry settings.\n", wine_dbgstr_w( key_name ));
  243 
  244     memcpy( config->color_map, color_map, sizeof(color_map) );
  245     memset( config->face_name, 0, sizeof(config->face_name) );
  246     config->cursor_size       = 25;
  247     config->cursor_visible    = 1;
  248     config->font_pitch_family = FIXED_PITCH | FF_DONTCARE;
  249     config->cell_height       = MulDiv( 16, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
  250     config->cell_width        = MulDiv( 8,  GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
  251     config->font_weight       = FW_NORMAL;
  252 
  253     config->history_size = 50;
  254     config->history_mode = 0;
  255     config->insert_mode  = 1;
  256     config->menu_mask    = 0;
  257     config->popup_attr   = 0xF5;
  258     config->quick_edit   = 0;
  259     config->sb_height    = 25;
  260     config->sb_width     = 80;
  261     config->attr         = 0x000F;
  262     config->win_height   = 25;
  263     config->win_width    = 80;
  264     config->win_pos.X    = 0;
  265     config->win_pos.Y    = 0;
  266     config->edition_mode = 0;
  267 
  268     /* read global settings */
  269     if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Console", &key ))
  270     {
  271         load_registry_key( key, config );
  272         /* if requested, load part related to console title */
  273         if (key_name && !RegOpenKeyW( key, key_name, &app_key ))
  274         {
  275             load_registry_key( app_key, config );
  276             RegCloseKey( app_key );
  277         }
  278         RegCloseKey( key );
  279     }
  280     TRACE( "%s\n", debugstr_config( config ));
  281 }
  282 
  283 static void save_registry_key( HKEY key, const struct console_config *config )
  284 {
  285     DWORD val, width, height, i;
  286     WCHAR color_name[13];
  287 
  288     TRACE( "%s", debugstr_config( config ));
  289 
  290     for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
  291     {
  292         wsprintfW( color_name, L"ColorTable%02d", i );
  293         val = config->color_map[i];
  294         RegSetValueExW( key, color_name, 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  295     }
  296 
  297     val = config->cursor_size;
  298     RegSetValueExW( key, L"CursorSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  299 
  300     val = config->cursor_visible;
  301     RegSetValueExW( key, L"CursorVisible", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  302 
  303     val = config->edition_mode;
  304     RegSetValueExW( key, L"EditionMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  305 
  306     RegSetValueExW( key, L"FaceName", 0, REG_SZ, (BYTE *)&config->face_name, sizeof(config->face_name) );
  307 
  308     val = config->font_pitch_family;
  309     RegSetValueExW( key, L"FontPitchFamily", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  310 
  311     width  = MulDiv( config->cell_width,  USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
  312     height = MulDiv( config->cell_height, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
  313     val = MAKELONG( width, height );
  314     RegSetValueExW( key, L"FontSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  315 
  316     val = config->font_weight;
  317     RegSetValueExW( key, L"FontWeight", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  318 
  319     val = config->history_size;
  320     RegSetValueExW( key, L"HistoryBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  321 
  322     val = config->history_mode;
  323     RegSetValueExW( key, L"HistoryNoDup", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  324 
  325     val = config->insert_mode;
  326     RegSetValueExW( key, L"InsertMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  327 
  328     val = config->menu_mask;
  329     RegSetValueExW( key, L"MenuMask", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  330 
  331     val = config->popup_attr;
  332     RegSetValueExW( key, L"PopupColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  333 
  334     val = config->quick_edit;
  335     RegSetValueExW( key, L"QuickEdit", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  336 
  337     val = MAKELONG(config->sb_width, config->sb_height);
  338     RegSetValueExW( key, L"ScreenBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  339 
  340     val = config->attr;
  341     RegSetValueExW( key, L"ScreenColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  342 
  343     val = MAKELONG( config->win_width, config->win_height );
  344     RegSetValueExW( key, L"WindowSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
  345 }
  346 
  347 static void save_config( const WCHAR *key_name, const struct console_config *config )
  348 {
  349     HKEY key, app_key;
  350 
  351     TRACE( "%s %s\n", debugstr_w( key_name ), debugstr_config( config ));
  352 
  353     if (RegCreateKeyW( HKEY_CURRENT_USER, L"Console", &key ))
  354     {
  355         ERR("Can't open registry for saving\n");
  356         return;
  357     }
  358 
  359     if (key_name)
  360     {
  361         if (RegCreateKeyW( key, key_name, &app_key ))
  362         {
  363             ERR("Can't open registry for saving\n");
  364         }
  365         else
  366         {
  367             /* FIXME: maybe only save the values different from the default value ? */
  368             save_registry_key( app_key, config );
  369             RegCloseKey( app_key );
  370         }
  371     }
  372     else save_registry_key( key, config );
  373     RegCloseKey(key);
  374 }
  375 
  376 /* fill memory DC with current cells values */
  377 static void fill_mem_dc( struct console *console, const RECT *update )
  378 {
  379     unsigned int i, j, k;
  380     unsigned int attr;
  381     char_info_t *cell;
  382     HFONT old_font;
  383     HBRUSH brush;
  384     WCHAR *line;
  385     INT *dx;
  386     RECT r;
  387 
  388     if (!console->window->font || !console->window->bitmap)
  389         return;
  390 
  391     if (!(line = malloc( (update->right - update->left + 1) * sizeof(WCHAR))) ) return;
  392     dx = malloc( (update->right - update->left + 1) * sizeof(*dx) );
  393 
  394     old_font = SelectObject( console->window->mem_dc, console->window->font );
  395     for (j = update->top; j <= update->bottom; j++)
  396     {
  397         cell = &console->active->data[j * console->active->width];
  398         for (i = update->left; i <= update->right; i++)
  399         {
  400             attr = cell[i].attr;
  401             SetBkColor( console->window->mem_dc, console->active->color_map[(attr >> 4) & 0x0F] );
  402             SetTextColor( console->window->mem_dc, console->active->color_map[attr & 0x0F] );
  403             for (k = i; k <= update->right && cell[k].attr == attr; k++)
  404             {
  405                 line[k - i] = cell[k].ch;
  406                 dx[k - i] = console->active->font.width;
  407             }
  408             ExtTextOutW( console->window->mem_dc, i * console->active->font.width,
  409                          j * console->active->font.height, 0, NULL, line, k - i, dx );
  410             if (console->window->ext_leading &&
  411                 (brush = CreateSolidBrush( console->active->color_map[(attr >> 4) & 0x0F] )))
  412             {
  413                 r.left   = i * console->active->font.width;
  414                 r.top    = (j + 1) * console->active->font.height - console->window->ext_leading;
  415                 r.right  = k * console->active->font.width;
  416                 r.bottom = (j + 1) * console->active->font.height;
  417                 FillRect( console->window->mem_dc, &r, brush );
  418                 DeleteObject( brush );
  419             }
  420             i = k - 1;
  421         }
  422     }
  423     SelectObject( console->window->mem_dc, old_font );
  424     free( dx );
  425     free( line );
  426 }
  427 
  428 /* set a new position for the cursor */
  429 static void update_window_cursor( struct console *console )
  430 {
  431     if (console->win != GetFocus() || !console->active->cursor_visible) return;
  432 
  433     SetCaretPos( (console->active->cursor_x - console->active->win.left) * console->active->font.width,
  434                  (console->active->cursor_y - console->active->win.top)  * console->active->font.height );
  435     ShowCaret( console->win );
  436 }
  437 
  438 /* sets a new shape for the cursor */
  439 static void shape_cursor( struct console *console )
  440 {
  441     int size = console->active->cursor_size;
  442 
  443     if (console->active->cursor_visible && console->win == GetFocus()) DestroyCaret();
  444     if (console->window->cursor_bitmap) DeleteObject( console->window->cursor_bitmap );
  445     console->window->cursor_bitmap = NULL;
  446     console->window->cursor_visible = FALSE;
  447 
  448     if (size != 100)
  449     {
  450         int w16b; /* number of bytes per row, aligned on word size */
  451         int i, j, nbl;
  452         BYTE *ptr;
  453 
  454         w16b = ((console->active->font.width + 15) & ~15) / 8;
  455         ptr = calloc( w16b, console->active->font.height );
  456         if (!ptr) return;
  457         nbl = max( (console->active->font.height * size) / 100, 1 );
  458         for (j = console->active->font.height - nbl; j < console->active->font.height; j++)
  459         {
  460             for (i = 0; i < console->active->font.width; i++)
  461             {
  462                 ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
  463             }
  464         }
  465         console->window->cursor_bitmap = CreateBitmap( console->active->font.width,
  466                                                        console->active->font.height, 1, 1, ptr );
  467         free(ptr);
  468     }
  469 }
  470 
  471 static void update_window( struct console *console )
  472 {
  473     unsigned int win_width, win_height;
  474     BOOL update_all = FALSE;
  475     int dx, dy;
  476     RECT r;
  477 
  478     console->window->update_state = UPDATE_BUSY;
  479 
  480     if (console->window->sb_width != console->active->width ||
  481         console->window->sb_height != console->active->height ||
  482         (!console->window->bitmap && IsWindowVisible( console->win )))
  483     {
  484         console->window->sb_width  = console->active->width;
  485         console->window->sb_height = console->active->height;
  486 
  487         if (console->active->width && console->active->height && console->window->font)
  488         {
  489             HBITMAP bitmap;
  490             HDC dc;
  491             RECT r;
  492 
  493             if (!(dc = GetDC( console->win ))) return;
  494 
  495             bitmap = CreateCompatibleBitmap( dc,
  496                                              console->active->width  * console->active->font.width,
  497                                              console->active->height * console->active->font.height );
  498             ReleaseDC( console->win, dc );
  499             SelectObject( console->window->mem_dc, bitmap );
  500 
  501             if (console->window->bitmap) DeleteObject( console->window->bitmap );
  502             console->window->bitmap = bitmap;
  503             SetRect( &r, 0, 0, console->active->width - 1, console->active->height - 1 );
  504             fill_mem_dc( console, &r );
  505         }
  506 
  507         empty_update_rect( console->active, &console->window->update );
  508         update_all = TRUE;
  509     }
  510 
  511     /* compute window size from desired client size */
  512     win_width  = console->active->win.right - console->active->win.left + 1;
  513     win_height = console->active->win.bottom - console->active->win.top + 1;
  514 
  515     if (update_all || win_width != console->window->win_width ||
  516         win_height != console->window->win_height)
  517     {
  518         console->window->win_width  = win_width;
  519         console->window->win_height = win_height;
  520 
  521         r.left   = r.top = 0;
  522         r.right  = win_width  * console->active->font.width;
  523         r.bottom = win_height * console->active->font.height;
  524         AdjustWindowRect( &r, GetWindowLongW( console->win, GWL_STYLE ), FALSE );
  525 
  526         dx = dy = 0;
  527         if (console->active->width > win_width)
  528         {
  529             dy = GetSystemMetrics( SM_CYHSCROLL );
  530             SetScrollRange( console->win, SB_HORZ, 0, console->active->width - win_width, FALSE );
  531             SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
  532             ShowScrollBar( console->win, SB_HORZ, TRUE );
  533         }
  534         else
  535         {
  536             ShowScrollBar( console->win, SB_HORZ, FALSE );
  537         }
  538 
  539         if (console->active->height > win_height)
  540         {
  541             dx = GetSystemMetrics( SM_CXVSCROLL );
  542             SetScrollRange( console->win, SB_VERT, 0, console->active->height - win_height, FALSE );
  543             SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
  544             ShowScrollBar( console->win, SB_VERT, TRUE );
  545         }
  546         else
  547             ShowScrollBar( console->win, SB_VERT, FALSE );
  548 
  549         dx += r.right - r.left;
  550         dy += r.bottom - r.top;
  551         SetWindowPos( console->win, 0, 0, 0, dx, dy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
  552 
  553         SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0 );
  554         console->active->max_width  = (r.right - r.left) / console->active->font.width;
  555         console->active->max_height = (r.bottom - r.top - GetSystemMetrics( SM_CYCAPTION )) /
  556             console->active->font.height;
  557 
  558         InvalidateRect( console->win, NULL, FALSE );
  559         UpdateWindow( console->win );
  560         update_all = TRUE;
  561     }
  562     else if (console->active->win.left != console->window->win_pos.X ||
  563              console->active->win.top  != console->window->win_pos.Y)
  564     {
  565         ScrollWindow( console->win,
  566                       (console->window->win_pos.X - console->active->win.left) * console->active->font.width,
  567                       (console->window->win_pos.Y - console->active->win.top)  * console->active->font.height,
  568                       NULL, NULL );
  569         SetScrollPos( console->win, SB_HORZ, console->active->win.left, TRUE );
  570         SetScrollPos( console->win, SB_VERT, console->active->win.top, TRUE );
  571         InvalidateRect( console->win, NULL, FALSE );
  572     }
  573 
  574     console->window->win_pos.X = console->active->win.left;
  575     console->window->win_pos.Y = console->active->win.top;
  576 
  577     if (console->window->update.top  <= console->window->update.bottom &&
  578         console->window->update.left <= console->window->update.right)
  579     {
  580         RECT *update = &console->window->update;
  581         r.left   = (update->left   - console->active->win.left)     * console->active->font.width;
  582         r.right  = (update->right  - console->active->win.left + 1) * console->active->font.width;
  583         r.top    = (update->top    - console->active->win.top)      * console->active->font.height;
  584         r.bottom = (update->bottom - console->active->win.top + 1)  * console->active->font.height;
  585         fill_mem_dc( console, update );
  586         empty_update_rect( console->active, &console->window->update );
  587         InvalidateRect( console->win, &r, FALSE );
  588         UpdateWindow( console->win );
  589     }
  590 
  591     if (update_all || console->active->cursor_size != console->window->cursor_size)
  592     {
  593         console->window->cursor_size = console->active->cursor_size;
  594         shape_cursor( console );
  595     }
  596 
  597     if (console->active->cursor_visible != console->window->cursor_visible)
  598     {
  599         console->window->cursor_visible = console->active->cursor_visible;
  600         if (console->win == GetFocus())
  601         {
  602             if (console->window->cursor_visible)
  603                 CreateCaret( console->win, console->window->cursor_bitmap,
  604                              console->active->font.width, console->active->font.height );
  605             else
  606                 DestroyCaret();
  607         }
  608     }
  609 
  610     if (update_all || console->active->cursor_x != console->window->cursor_pos.X ||
  611         console->active->cursor_y != console->window->cursor_pos.Y)
  612     {
  613         console->window->cursor_pos.X = console->active->cursor_x;
  614         console->window->cursor_pos.Y = console->active->cursor_y;
  615         update_window_cursor( console );
  616     }
  617 
  618     console->window->update_state = UPDATE_NONE;
  619 }
  620 
  621 /* get the relevant information from the font described in lf and store them in config */
  622 static HFONT select_font_config( struct console_config *config, unsigned int cp, HWND hwnd,
  623                                  const LOGFONTW *lf )
  624 {
  625     HFONT font, old_font;
  626     TEXTMETRICW tm;
  627     CPINFO cpinfo;
  628     HDC dc;
  629 
  630     if (!(dc = GetDC( hwnd ))) return NULL;
  631     if (!(font = CreateFontIndirectW( lf )))
  632     {
  633         ReleaseDC( hwnd, dc );
  634         return NULL;
  635     }
  636 
  637     old_font = SelectObject( dc, font );
  638     GetTextMetricsW( dc, &tm );
  639     SelectObject( dc, old_font );
  640     ReleaseDC( hwnd, dc );
  641 
  642     config->cell_width  = tm.tmAveCharWidth;
  643     config->cell_height = tm.tmHeight + tm.tmExternalLeading;
  644     config->font_weight = tm.tmWeight;
  645     lstrcpyW( config->face_name, lf->lfFaceName );
  646 
  647     /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
  648     if (GetCPInfo( cp, &cpinfo ) && cpinfo.MaxCharSize > 1)
  649         config->cell_width  = tm.tmMaxCharWidth;
  650 
  651     return font;
  652 }
  653 
  654 static void fill_logfont( LOGFONTW *lf, const WCHAR *name, unsigned int height, unsigned int weight )
  655 {
  656     lf->lfHeight         = height;
  657     lf->lfWidth          = 0;
  658     lf->lfEscapement     = 0;
  659     lf->lfOrientation    = 0;
  660     lf->lfWeight         = weight;
  661     lf->lfItalic         = FALSE;
  662     lf->lfUnderline      = FALSE;
  663     lf->lfStrikeOut      = FALSE;
  664     lf->lfCharSet        = DEFAULT_CHARSET;
  665     lf->lfOutPrecision   = OUT_DEFAULT_PRECIS;
  666     lf->lfClipPrecision  = CLIP_DEFAULT_PRECIS;
  667     lf->lfQuality        = DEFAULT_QUALITY;
  668     lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
  669     lstrcpyW( lf->lfFaceName, name );
  670 }
  671 
  672 static BOOL set_console_font( struct console *console, const LOGFONTW *logfont )
  673 {
  674     struct font_info *font_info = &console->active->font;
  675     HFONT font, old_font;
  676     TEXTMETRICW tm;
  677     CPINFO cpinfo;
  678     HDC dc;
  679 
  680     TRACE( "%s\n", debugstr_logfont( logfont, 0 ));
  681 
  682     if (console->window->font && logfont->lfHeight == console->active->font.height &&
  683         logfont->lfWeight == console->active->font.weight &&
  684         !logfont->lfItalic && !logfont->lfUnderline && !logfont->lfStrikeOut &&
  685         console->active->font.face_len == wcslen( logfont->lfFaceName ) * sizeof(WCHAR) &&
  686         !memcmp( logfont->lfFaceName, console->active->font.face_name,
  687                  console->active->font.face_len ))
  688     {
  689         TRACE( "equal to current\n" );
  690         return TRUE;
  691     }
  692 
  693     if (!(dc = GetDC( console->win ))) return FALSE;
  694     if (!(font = CreateFontIndirectW( logfont )))
  695     {
  696         ReleaseDC( console->win, dc );
  697         return FALSE;
  698     }
  699 
  700     old_font = SelectObject( dc, font );
  701     GetTextMetricsW( dc, &tm );
  702     SelectObject( dc, old_font );
  703     ReleaseDC( console->win, dc );
  704 
  705     font_info->width  = tm.tmAveCharWidth;
  706     font_info->height = tm.tmHeight + tm.tmExternalLeading;
  707     font_info->weight = tm.tmWeight;
  708 
  709     free( font_info->face_name );
  710     font_info->face_len = wcslen( logfont->lfFaceName ) * sizeof(WCHAR);
  711     font_info->face_name = malloc( font_info->face_len );
  712     memcpy( font_info->face_name, logfont->lfFaceName, font_info->face_len );
  713 
  714     /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
  715     if (GetCPInfo( console->output_cp, &cpinfo ) && cpinfo.MaxCharSize > 1)
  716         font_info->width  = tm.tmMaxCharWidth;
  717 
  718     if (console->window->font) DeleteObject( console->window->font );
  719     console->window->font = font;
  720     console->window->ext_leading = tm.tmExternalLeading;
  721 
  722     if (console->window->bitmap)
  723     {
  724         DeleteObject(console->window->bitmap);
  725         console->window->bitmap = NULL;
  726     }
  727     return TRUE;
  728 }
  729 
  730 struct font_chooser
  731 {
  732     struct console *console;
  733     int             pass;
  734     BOOL            done;
  735 };
  736 
  737 /* check if the font described in tm is usable as a font for the renderer */
  738 static BOOL validate_font_metric( struct console *console, const TEXTMETRICW *tm,
  739                                   DWORD type, int pass )
  740 {
  741     switch (pass) /* we get increasingly lenient in later passes */
  742     {
  743     case 0:
  744         if (type & RASTER_FONTTYPE) return FALSE;
  745         /* fall through */
  746     case 1:
  747         if (type & RASTER_FONTTYPE)
  748         {
  749             if (tm->tmMaxCharWidth * (console->active->win.right - console->active->win.left + 1)
  750                 >= GetSystemMetrics(SM_CXSCREEN))
  751                 return FALSE;
  752             if (tm->tmHeight * (console->active->win.bottom - console->active->win.top + 1)
  753                 >= GetSystemMetrics(SM_CYSCREEN))
  754                 return FALSE;
  755         }
  756         /* fall through */
  757     case 2:
  758         if (tm->tmCharSet != DEFAULT_CHARSET && tm->tmCharSet != console->window->ui_charset)
  759             return FALSE;
  760         /* fall through */
  761     case 3:
  762         if (tm->tmItalic || tm->tmUnderlined || tm->tmStruckOut) return FALSE;
  763         break;
  764     }
  765     return TRUE;
  766 }
  767 
  768 /* check if the font family described in lf is usable as a font for the renderer */
  769 static BOOL validate_font( struct console *console, const LOGFONTW *lf, int pass )
  770 {
  771     switch (pass) /* we get increasingly lenient in later passes */
  772     {
  773     case 0:
  774     case 1:
  775     case 2:
  776         if (lf->lfCharSet != DEFAULT_CHARSET && lf->lfCharSet != console->window->ui_charset)
  777             return FALSE;
  778         /* fall through */
  779     case 3:
  780         if ((lf->lfPitchAndFamily & 3) != FIXED_PITCH) return FALSE;
  781         /* fall through */
  782     case 4:
  783         if (lf->lfFaceName[0] == '@') return FALSE;
  784         break;
  785     }
  786     return TRUE;
  787 }
  788 
  789 /* helper functions to get a decent font for the renderer */
  790 static int WINAPI get_first_font_sub_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
  791                                            DWORD font_type, LPARAM lparam)
  792 {
  793     struct font_chooser *fc = (struct font_chooser *)lparam;
  794 
  795     TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
  796 
  797     if (validate_font_metric( fc->console, tm, font_type, fc->pass ))
  798     {
  799         LOGFONTW mlf = *lf;
  800 
  801         /* Use the default sizes for the font (this is needed, especially for
  802          * TrueType fonts, so that we get a decent size, not the max size)
  803          */
  804         mlf.lfWidth  = fc->console->active->font.width;
  805         mlf.lfHeight = fc->console->active->font.height;
  806         if (!mlf.lfHeight)
  807             mlf.lfHeight = MulDiv( 16, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
  808 
  809         if (set_console_font( fc->console, &mlf ))
  810         {
  811             struct console_config config;
  812 
  813             fc->done = 1;
  814 
  815             /* since we've modified the current config with new font information,
  816              * set this information as the new default.
  817              */
  818             load_config( fc->console->window->config_key, &config );
  819             config.cell_width  = fc->console->active->font.width;
  820             config.cell_height = fc->console->active->font.height;
  821             fc->console->active->font.face_len = wcslen( config.face_name ) * sizeof(WCHAR);
  822             memcpy( fc->console->active->font.face_name, config.face_name,
  823                     fc->console->active->font.face_len );
  824             /* Force also its writing back to the registry so that we can get it
  825              * the next time.
  826              */
  827             save_config( fc->console->window->config_key, &config );
  828             return 0;
  829         }
  830     }
  831     return 1;
  832 }
  833 
  834 static int WINAPI get_first_font_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
  835                                        DWORD font_type, LPARAM lparam )
  836 {
  837     struct font_chooser *fc = (struct font_chooser *)lparam;
  838 
  839     TRACE("%s\n", debugstr_logfont( lf, font_type ));
  840 
  841     if (validate_font( fc->console, lf, fc->pass ))
  842     {
  843         EnumFontFamiliesW( fc->console->window->mem_dc, lf->lfFaceName,
  844                            get_first_font_sub_enum, lparam );
  845         return !fc->done; /* we just need the first matching one... */
  846     }
  847     return 1;
  848 }
  849 
  850 
  851 /* sets logfont as the new font for the console */
  852 static void update_console_font( struct console *console, const WCHAR *font,
  853                                  unsigned int height, unsigned int weight )
  854 {
  855     struct font_chooser fc;
  856     LOGFONTW lf;
  857 
  858     if (font[0] && height && weight)
  859     {
  860         fill_logfont( &lf, font, height, weight );
  861         if (set_console_font( console, &lf )) return;
  862     }
  863 
  864     /* try to find an acceptable font */
  865     WARN( "Couldn't match the font from registry, trying to find one\n" );
  866     fc.console = console;
  867     fc.done = FALSE;
  868     for (fc.pass = 0; fc.pass <= 5; fc.pass++)
  869     {
  870         EnumFontFamiliesW( console->window->mem_dc, NULL, get_first_font_enum, (LPARAM)&fc );
  871         if (fc.done) return;
  872     }
  873     ERR( "Couldn't find a decent font" );
  874 }
  875 
  876 /* get a cell from a relative coordinate in window (takes into account the scrolling) */
  877 static COORD get_cell( struct console *console, LPARAM lparam )
  878 {
  879     COORD c;
  880     c.X = console->active->win.left + (short)LOWORD(lparam) / console->active->font.width;
  881     c.Y = console->active->win.top + (short)HIWORD(lparam) / console->active->font.height;
  882     return c;
  883 }
  884 
  885 /* get the console bit mask equivalent to the VK_ status in key state */
  886 static DWORD get_ctrl_state( BYTE *key_state)
  887 {
  888     unsigned int ret = 0;
  889 
  890     GetKeyboardState(key_state);
  891     if (key_state[VK_SHIFT]    & 0x80)  ret |= SHIFT_PRESSED;
  892     if (key_state[VK_LCONTROL] & 0x80)  ret |= LEFT_CTRL_PRESSED;
  893     if (key_state[VK_RCONTROL] & 0x80)  ret |= RIGHT_CTRL_PRESSED;
  894     if (key_state[VK_LMENU]    & 0x80)  ret |= LEFT_ALT_PRESSED;
  895     if (key_state[VK_RMENU]    & 0x80)  ret |= RIGHT_ALT_PRESSED;
  896     if (key_state[VK_CAPITAL]  & 0x01)  ret |= CAPSLOCK_ON;
  897     if (key_state[VK_NUMLOCK]  & 0x01)  ret |= NUMLOCK_ON;
  898     if (key_state[VK_SCROLL]   & 0x01)  ret |= SCROLLLOCK_ON;
  899 
  900     return ret;
  901 }
  902 
  903 /* get the selection rectangle */
  904 static void get_selection_rect( struct console *console, RECT *r )
  905 {
  906     r->left   = (min(console->window->selection_start.X, console->window->selection_end.X) -
  907                  console->active->win.left) * console->active->font.width;
  908     r->top    = (min(console->window->selection_start.Y, console->window->selection_end.Y) -
  909                  console->active->win.top) * console->active->font.height;
  910     r->right  = (max(console->window->selection_start.X, console->window->selection_end.X) + 1 -
  911                  console->active->win.left) * console->active->font.width;
  912     r->bottom = (max(console->window->selection_start.Y, console->window->selection_end.Y) + 1 -
  913                  console->active->win.top) * console->active->font.height;
  914 }
  915 
  916 static void update_selection( struct console *console, HDC ref_dc )
  917 {
  918     HDC dc;
  919     RECT r;
  920 
  921     get_selection_rect( console, &r );
  922     dc = ref_dc ? ref_dc : GetDC( console->win );
  923     if (!dc) return;
  924 
  925     if (console->win == GetFocus() && console->active->cursor_visible)
  926         HideCaret( console->win );
  927     InvertRect( dc, &r );
  928     if (dc != ref_dc)
  929         ReleaseDC( console->win, dc );
  930     if (console->win == GetFocus() && console->active->cursor_visible)
  931         ShowCaret( console->win );
  932 }
  933 
  934 static void move_selection( struct console *console, COORD c1, COORD c2 )
  935 {
  936     RECT r;
  937     HDC dc;
  938 
  939     if (c1.X < 0 || c1.X >= console->active->width ||
  940         c2.X < 0 || c2.X >= console->active->width ||
  941         c1.Y < 0 || c1.Y >= console->active->height ||
  942         c2.Y < 0 || c2.Y >= console->active->height)
  943         return;
  944 
  945     get_selection_rect( console, &r );
  946     dc = GetDC( console->win );
  947     if (dc)
  948     {
  949         if (console->win == GetFocus() && console->active->cursor_visible)
  950             HideCaret( console->win );
  951         InvertRect( dc, &r );
  952     }
  953     console->window->selection_start = c1;
  954     console->window->selection_end   = c2;
  955     if (dc)
  956     {
  957         get_selection_rect( console, &r );
  958         InvertRect( dc, &r );
  959         ReleaseDC( console->win, dc );
  960         if (console->win == GetFocus() && console->active->cursor_visible)
  961             ShowCaret( console->win );
  962     }
  963 }
  964 
  965 /* copies the current selection into the clipboard */
  966 static void copy_selection( struct console *console )
  967 {
  968     unsigned int w, h;
  969     WCHAR *p, *buf;
  970     HANDLE mem;
  971 
  972     w = abs( console->window->selection_start.X - console->window->selection_end.X ) + 1;
  973     h = abs( console->window->selection_start.Y - console->window->selection_end.Y ) + 1;
  974 
  975     if (!OpenClipboard( console->win )) return;
  976     EmptyClipboard();
  977 
  978     mem = GlobalAlloc( GMEM_MOVEABLE, (w + 1) * h * sizeof(WCHAR) );
  979     if (mem && (p = buf = GlobalLock( mem )))
  980     {
  981         int x, y;
  982         COORD c;
  983 
  984         c.X = min( console->window->selection_start.X, console->window->selection_end.X );
  985         c.Y = min( console->window->selection_start.Y, console->window->selection_end.Y );
  986 
  987         for (y = c.Y; y < c.Y + h; y++)
  988         {
  989             WCHAR *end;
  990 
  991             for (x = c.X; x < c.X + w; x++)
  992                 p[x - c.X] = console->active->data[y * console->active->width + x].ch;
  993 
  994             /* strip spaces from the end of the line */
  995             end = p + w;
  996             while (end > p && *(end - 1) == ' ')
  997                 end--;
  998             *end = (y < c.Y + h - 1) ? '\n' : '\0';
  999             p = end + 1;
 1000         }
 1001 
 1002         TRACE( "%s\n", debugstr_w( buf ));
 1003         if (p - buf != (w + 1) * h)
 1004         {
 1005             HANDLE new_mem;
 1006             new_mem = GlobalReAlloc( mem, (p - buf) * sizeof(WCHAR), GMEM_MOVEABLE );
 1007             if (new_mem) mem = new_mem;
 1008         }
 1009         GlobalUnlock( mem );
 1010         SetClipboardData( CF_UNICODETEXT, mem );
 1011     }
 1012     CloseClipboard();
 1013 }
 1014 
 1015 static void paste_clipboard( struct console *console )
 1016 {
 1017     WCHAR *ptr;
 1018     HANDLE h;
 1019 
 1020     if (!OpenClipboard( console->win )) return;
 1021     h = GetClipboardData( CF_UNICODETEXT );
 1022     if (h && (ptr = GlobalLock( h )))
 1023     {
 1024         unsigned int i, len = GlobalSize(h) / sizeof(WCHAR);
 1025         INPUT_RECORD ir[2];
 1026         SHORT sh;
 1027 
 1028         ir[0].EventType = KEY_EVENT;
 1029         ir[0].Event.KeyEvent.wRepeatCount = 0;
 1030         ir[0].Event.KeyEvent.dwControlKeyState = 0;
 1031         ir[0].Event.KeyEvent.bKeyDown = TRUE;
 1032 
 1033         /* generate the corresponding input records */
 1034         for (i = 0; i < len; i++)
 1035         {
 1036             /* FIXME: the modifying keys are not generated (shift, ctrl...) */
 1037             sh = VkKeyScanW( ptr[i] );
 1038             ir[0].Event.KeyEvent.wVirtualKeyCode   = LOBYTE(sh);
 1039             ir[0].Event.KeyEvent.wVirtualScanCode  = MapVirtualKeyW( LOBYTE(sh), 0 );
 1040             ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
 1041 
 1042             ir[1] = ir[0];
 1043             ir[1].Event.KeyEvent.bKeyDown = FALSE;
 1044 
 1045             write_console_input( console, ir, 2, i == len - 1 );
 1046         }
 1047         GlobalUnlock( h );
 1048     }
 1049 
 1050     CloseClipboard();
 1051 }
 1052 
 1053 /* handle keys while selecting an area */
 1054 static void handle_selection_key( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
 1055 {
 1056     BYTE key_state[256];
 1057     COORD c1, c2;
 1058     DWORD state;
 1059 
 1060     if (!down) return;
 1061     state = get_ctrl_state( key_state ) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
 1062 
 1063     switch (state)
 1064     {
 1065     case 0:
 1066         switch (wparam)
 1067         {
 1068         case VK_RETURN:
 1069             console->window->in_selection = FALSE;
 1070             update_selection( console, 0 );
 1071             copy_selection( console );
 1072             return;
 1073         case VK_RIGHT:
 1074             c1 = console->window->selection_start;
 1075             c2 = console->window->selection_end;
 1076             c1.X++; c2.X++;
 1077             move_selection( console, c1, c2 );
 1078             return;
 1079         case VK_LEFT:
 1080             c1 = console->window->selection_start;
 1081             c2 = console->window->selection_end;
 1082             c1.X--; c2.X--;
 1083             move_selection( console, c1, c2 );
 1084             return;
 1085         case VK_UP:
 1086             c1 = console->window->selection_start;
 1087             c2 = console->window->selection_end;
 1088             c1.Y--; c2.Y--;
 1089             move_selection( console, c1, c2 );
 1090             return;
 1091         case VK_DOWN:
 1092             c1 = console->window->selection_start;
 1093             c2 = console->window->selection_end;
 1094             c1.Y++; c2.Y++;
 1095             move_selection( console, c1, c2 );
 1096             return;
 1097         }
 1098         break;
 1099     case SHIFT_PRESSED:
 1100         switch (wparam)
 1101         {
 1102         case VK_RIGHT:
 1103             c1 = console->window->selection_start;
 1104             c2 = console->window->selection_end;
 1105             c2.X++;
 1106             move_selection( console, c1, c2 );
 1107             return;
 1108         case VK_LEFT:
 1109             c1 = console->window->selection_start;
 1110             c2 = console->window->selection_end;
 1111             c2.X--;
 1112             move_selection( console, c1, c2 );
 1113             return;
 1114         case VK_UP:
 1115             c1 = console->window->selection_start;
 1116             c2 = console->window->selection_end;
 1117             c2.Y--;
 1118             move_selection( console, c1, c2 );
 1119             return;
 1120         case VK_DOWN:
 1121             c1 = console->window->selection_start;
 1122             c2 = console->window->selection_end;
 1123             c2.Y++;
 1124             move_selection( console, c1, c2 );
 1125             return;
 1126         }
 1127         break;
 1128     }
 1129 
 1130     if (wparam < VK_SPACE)  /* Shift, Alt, Ctrl, Num Lock etc. */
 1131         return;
 1132 
 1133     update_selection( console, 0 );
 1134     console->window->in_selection = FALSE;
 1135 }
 1136 
 1137 /* generate input_record from windows WM_KEYUP/WM_KEYDOWN messages */
 1138 static void record_key_input( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
 1139 {
 1140     static WCHAR last; /* keep last char seen as feed for key up message */
 1141     BYTE key_state[256];
 1142     INPUT_RECORD ir;
 1143     WCHAR buf[2];
 1144 
 1145     ir.EventType = KEY_EVENT;
 1146     ir.Event.KeyEvent.bKeyDown          = down;
 1147     ir.Event.KeyEvent.wRepeatCount      = LOWORD(lparam);
 1148     ir.Event.KeyEvent.wVirtualKeyCode   = wparam;
 1149     ir.Event.KeyEvent.wVirtualScanCode  = HIWORD(lparam) & 0xFF;
 1150     ir.Event.KeyEvent.uChar.UnicodeChar = 0;
 1151     ir.Event.KeyEvent.dwControlKeyState = get_ctrl_state( key_state );
 1152     if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
 1153 
 1154     if (down)
 1155     {
 1156         switch (ToUnicode(wparam, HIWORD(lparam), key_state, buf, 2, 0))
 1157         {
 1158         case 2:
 1159             /* FIXME: should generate two events */
 1160             /* fall through */
 1161         case 1:
 1162             last = buf[0];
 1163             break;
 1164         default:
 1165             last = 0;
 1166             break;
 1167         }
 1168     }
 1169     ir.Event.KeyEvent.uChar.UnicodeChar = last;
 1170     if (!down) last = 0; /* FIXME: buggy HACK  */
 1171 
 1172     write_console_input( console, &ir, 1, TRUE );
 1173 }
 1174 
 1175 static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
 1176 {
 1177     BYTE key_state[256];
 1178     INPUT_RECORD ir;
 1179 
 1180     /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
 1181     if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
 1182 
 1183     ir.EventType = MOUSE_EVENT;
 1184     ir.Event.MouseEvent.dwMousePosition = c;
 1185     ir.Event.MouseEvent.dwButtonState   = 0;
 1186     if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
 1187     if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
 1188     if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
 1189     if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
 1190     if (wparam & MK_SHIFT)   ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
 1191     if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
 1192     ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
 1193     ir.Event.MouseEvent.dwEventFlags = event;
 1194 
 1195     write_console_input( console, &ir, 1, TRUE );
 1196 }
 1197 
 1198 struct dialog_info
 1199 {
 1200     struct console        *console;
 1201     struct console_config  config;
 1202     HWND                   dialog;      /* handle to active propsheet */
 1203     int                    font_count;  /* number of fonts */
 1204     struct dialog_font_info
 1205     {
 1206         unsigned int  height;
 1207         unsigned int  weight;
 1208         WCHAR         faceName[LF_FACESIZE];
 1209     } *font;  /* array of fonts */
 1210 };
 1211 
 1212 /* dialog proc for the option property sheet */
 1213 static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
 1214 {
 1215     struct dialog_info *di;
 1216     unsigned int idc;
 1217 
 1218     switch (msg)
 1219     {
 1220     case WM_INITDIALOG:
 1221         di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
 1222         di->dialog = dialog;
 1223         SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
 1224 
 1225         SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
 1226 
 1227         if (di->config.cursor_size <= 25)       idc = IDC_OPT_CURSOR_SMALL;
 1228         else if (di->config.cursor_size <= 50)  idc = IDC_OPT_CURSOR_MEDIUM;
 1229         else                                    idc = IDC_OPT_CURSOR_LARGE;
 1230 
 1231         SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
 1232         SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
 1233         SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
 1234                              (di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
 1235         SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
 1236                              (di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
 1237         SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
 1238                              (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
 1239         SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
 1240                              (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
 1241         SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
 1242                              (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
 1243         return FALSE; /* because we set the focus */
 1244 
 1245     case WM_COMMAND:
 1246         break;
 1247 
 1248     case WM_NOTIFY:
 1249     {
 1250         NMHDR *nmhdr = (NMHDR*)lparam;
 1251         DWORD val;
 1252         BOOL done;
 1253 
 1254         di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
 1255 
 1256         switch (nmhdr->code)
 1257         {
 1258         case PSN_SETACTIVE:
 1259             /* needed in propsheet to keep properly the selected radio button
 1260              * otherwise, the focus would be set to the first tab stop in the
 1261              * propsheet, which would always activate the first radio button
 1262              */
 1263             if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
 1264                 idc = IDC_OPT_CURSOR_SMALL;
 1265             else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
 1266                 idc = IDC_OPT_CURSOR_MEDIUM;
 1267             else
 1268                 idc = IDC_OPT_CURSOR_LARGE;
 1269             PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
 1270             di->dialog = dialog;
 1271             break;
 1272         case PSN_APPLY:
 1273             if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
 1274             else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
 1275             else val = 100;
 1276             di->config.cursor_size = val;
 1277 
 1278             val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
 1279             if (done) di->config.history_size = val;
 1280 
 1281             val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
 1282             di->config.history_mode = val;
 1283 
 1284             val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
 1285             di->config.insert_mode = val;
 1286 
 1287             val = 0;
 1288             if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED)  val |= MK_CONTROL;
 1289             if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
 1290             di->config.menu_mask = val;
 1291 
 1292             val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
 1293             di->config.quick_edit = val;
 1294 
 1295             SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
 1296             return TRUE;
 1297         default:
 1298             return FALSE;
 1299         }
 1300         break;
 1301     }
 1302     default:
 1303         return FALSE;
 1304     }
 1305     return TRUE;
 1306 }
 1307 
 1308 static COLORREF get_color( struct dialog_info *di, unsigned int idc )
 1309 {
 1310     LONG_PTR index;
 1311 
 1312     index = GetWindowLongPtrW(GetDlgItem( di->dialog, idc ), 0);
 1313     return di->config.color_map[index];
 1314 }
 1315 
 1316 /* window proc for font previewer in font property sheet */
 1317 static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
 1318 {
 1319     switch (msg)
 1320     {
 1321     case WM_CREATE:
 1322         SetWindowLongPtrW( hwnd, 0, 0 );
 1323         break;
 1324 
 1325     case WM_GETFONT:
 1326         return GetWindowLongPtrW( hwnd, 0 );
 1327 
 1328     case WM_SETFONT:
 1329         SetWindowLongPtrW( hwnd, 0, wparam );
 1330         if (LOWORD(lparam))
 1331         {
 1332             InvalidateRect( hwnd, NULL, TRUE );
 1333             UpdateWindow( hwnd );
 1334         }
 1335         break;
 1336 
 1337     case WM_DESTROY:
 1338         {
 1339             HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
 1340             if (font) DeleteObject( font );
 1341             break;
 1342         }
 1343 
 1344     case WM_PAINT:
 1345         {
 1346             struct dialog_info *di;
 1347             HFONT font, old_font;
 1348             PAINTSTRUCT ps;
 1349             int size_idx;
 1350 
 1351             di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
 1352             BeginPaint( hwnd, &ps );
 1353 
 1354             size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
 1355             font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
 1356             if (font)
 1357             {
 1358                 static const WCHAR ascii[] = L"ASCII: abcXYZ";
 1359                 COLORREF bkcolor;
 1360                 WCHAR buf[256];
 1361                 int len;
 1362 
 1363                 old_font = SelectObject( ps.hdc, font );
 1364                 bkcolor = get_color( di, IDC_FNT_COLOR_BK );
 1365                 FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
 1366                 SetBkColor( ps.hdc, bkcolor );
 1367                 SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
 1368                 len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
 1369                 if (len) TextOutW( ps.hdc, 0, 0, buf, len );
 1370                 TextOutW( ps.hdc, 0, di->font[size_idx].height, ascii, ARRAY_SIZE(ascii) - 1 );
 1371                 SelectObject( ps.hdc, old_font );
 1372             }
 1373             EndPaint( hwnd, &ps );
 1374             break;
 1375         }
 1376 
 1377     default:
 1378         return DefWindowProcW( hwnd, msg, wparam, lparam );
 1379     }
 1380     return 0;
 1381 }
 1382 
 1383 /* window proc for color previewer */
 1384 static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
 1385 {
 1386     switch (msg)
 1387     {
 1388     case WM_PAINT:
 1389         {
 1390             struct dialog_info *di;
 1391             PAINTSTRUCT ps;
 1392             RECT client, r;
 1393             int i, step;
 1394             HBRUSH brush;
 1395 
 1396             BeginPaint( hwnd, &ps );
 1397             GetClientRect( hwnd, &client );
 1398             step = client.right / 8;
 1399 
 1400             di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
 1401 
 1402             for (i = 0; i < 16; i++)
 1403             {
 1404                 r.top = (i / 8) * (client.bottom / 2);
 1405                 r.bottom = r.top + client.bottom / 2;
 1406                 r.left = (i & 7) * step;
 1407                 r.right = r.left + step;
 1408                 brush = CreateSolidBrush( di->config.color_map[i] );
 1409                 FillRect( ps.hdc, &r, brush );
 1410                 DeleteObject( brush );
 1411                 if (GetWindowLongW( hwnd, 0 ) == i)
 1412                 {
 1413                     HPEN old_pen;
 1414                     int i = 2;
 1415 
 1416                     old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
 1417                     r.right--; r.bottom--;
 1418                     for (;;)
 1419                     {
 1420                         MoveToEx( ps.hdc, r.left, r.bottom, NULL );
 1421                         LineTo( ps.hdc, r.left, r.top );
 1422                         LineTo( ps.hdc, r.right, r.top );
 1423                         SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
 1424                         LineTo( ps.hdc, r.right, r.bottom );
 1425                         LineTo( ps.hdc, r.left, r.bottom );
 1426                         if (--i == 0) break;
 1427                         r.left++; r.top++; r.right--; r.bottom--;
 1428                         SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
 1429                     }
 1430                     SelectObject( ps.hdc, old_pen );
 1431                 }
 1432             }
 1433             EndPaint( hwnd, &ps );
 1434             break;
 1435         }
 1436 
 1437     case WM_LBUTTONDOWN:
 1438         {
 1439             int i, step;
 1440             RECT client;
 1441 
 1442             GetClientRect( hwnd, &client );
 1443             step = client.right / 8;
 1444             i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
 1445             i += LOWORD(lparam) / step;
 1446             SetWindowLongW( hwnd, 0, i );
 1447             InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
 1448             InvalidateRect( hwnd, NULL, FALSE );
 1449             break;
 1450         }
 1451 
 1452     default:
 1453         return DefWindowProcW( hwnd, msg, wparam, lparam );
 1454     }
 1455     return 0;
 1456 }
 1457 
 1458 /* enumerates all the font names with at least one valid font */
 1459 static int WINAPI font_enum_size2( const LOGFONTW *lf, const TEXTMETRICW *tm,
 1460                                    DWORD font_type, LPARAM lparam )
 1461 {
 1462     struct dialog_info *di = (struct dialog_info *)lparam;
 1463     TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
 1464     if (validate_font_metric( di->console, tm, font_type, 0 )) di->font_count++;
 1465     return 1;
 1466 }
 1467 
 1468 static int WINAPI font_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
 1469                              DWORD font_type, LPARAM lparam )
 1470 {
 1471     struct dialog_info *di = (struct dialog_info *)lparam;
 1472 
 1473     TRACE( "%s\n", debugstr_logfont( lf, font_type ));
 1474 
 1475     if (validate_font( di->console, lf, 0 ))
 1476     {
 1477         if (font_type & RASTER_FONTTYPE)
 1478         {
 1479             di->font_count = 0;
 1480             EnumFontFamiliesW( di->console->window->mem_dc, lf->lfFaceName,
 1481                                font_enum_size2, (LPARAM)di );
 1482         }
 1483         else
 1484             di->font_count = 1;
 1485 
 1486         if (di->font_count)
 1487             SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING,
 1488                                  0, (LPARAM)lf->lfFaceName );
 1489     }
 1490     return 1;
 1491 }
 1492 
 1493 static int WINAPI font_enum_size( const LOGFONTW *lf, const TEXTMETRICW *tm,
 1494                                   DWORD font_type, LPARAM lparam )
 1495 {
 1496     struct dialog_info *di = (struct dialog_info *)lparam;
 1497     WCHAR buf[32];
 1498 
 1499     TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
 1500 
 1501     if (di->font_count == 0 && !(font_type & RASTER_FONTTYPE))
 1502     {
 1503         static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
 1504         int i;
 1505 
 1506         di->font_count = ARRAY_SIZE(sizes);
 1507         di->font = malloc( di->font_count * sizeof(di->font[0]) );
 1508         for (i = 0; i < di->font_count; i++)
 1509         {
 1510             /* drop sizes where window size wouldn't fit on screen */
 1511             if (sizes[i] * di->config.win_height > GetSystemMetrics( SM_CYSCREEN ))
 1512             {
 1513                 di->font_count = i;
 1514                 break;
 1515             }
 1516             di->font[i].height = sizes[i];
 1517             di->font[i].weight = 400;
 1518             lstrcpyW( di->font[i].faceName, lf->lfFaceName );
 1519             wsprintfW( buf, L"%d", sizes[i] );
 1520             SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, i, (LPARAM)buf );
 1521         }
 1522         /* don't need to enumerate other */
 1523         return 0;
 1524     }
 1525 
 1526     if (validate_font_metric( di->console, tm, font_type, 0 ))
 1527     {
 1528         int idx = 0;
 1529 
 1530         /* we want the string to be sorted with a numeric order, not a lexicographic...
 1531          * do the job by hand... get where to insert the new string
 1532          */
 1533         while (idx < di->font_count && tm->tmHeight > di->font[idx].height)
 1534             idx++;
 1535         while (idx < di->font_count &&
 1536                tm->tmHeight == di->font[idx].height &&
 1537                tm->tmWeight > di->font[idx].weight)
 1538             idx++;
 1539         if (idx == di->font_count ||
 1540             tm->tmHeight != di->font[idx].height ||
 1541             tm->tmWeight < di->font[idx].weight)
 1542         {
 1543             /* here we need to add the new entry */
 1544             wsprintfW( buf, L"%d", tm->tmHeight );
 1545             SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, idx, (LPARAM)buf );
 1546 
 1547             /* now grow our arrays and insert the values at the same index than in the list box */
 1548             if (di->font_count)
 1549             {
 1550                 di->font = realloc( di->font, sizeof(*di->font) * (di->font_count + 1) );
 1551                 if (idx != di->font_count)
 1552                     memmove( &di->font[idx + 1], &di->font[idx],
 1553                              (di->font_count - idx) * sizeof(*di->font) );
 1554             }
 1555             else
 1556                 di->font = malloc( sizeof(*di->font) );
 1557             di->font[idx].height = tm->tmHeight;
 1558             di->font[idx].weight = tm->tmWeight;
 1559             lstrcpyW( di->font[idx].faceName, lf->lfFaceName );
 1560             di->font_count++;
 1561         }
 1562     }
 1563     return 1;
 1564 }
 1565 
 1566 static BOOL select_font( struct dialog_info *di )
 1567 {
 1568     struct console_config config;
 1569     int font_idx, size_idx;
 1570     HFONT font, old_font;
 1571     DWORD_PTR args[2];
 1572     WCHAR buf[256];
 1573     WCHAR fmt[128];
 1574     LOGFONTW lf;
 1575 
 1576     font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
 1577     size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
 1578 
 1579     if (font_idx < 0 || size_idx < 0 || size_idx >= di->font_count)
 1580         return FALSE;
 1581 
 1582     fill_logfont( &lf, di->font[size_idx].faceName, di->font[size_idx].height,
 1583                   di->font[size_idx].weight );
 1584     font = select_font_config( &config, di->console->output_cp, di->console->win, &lf );
 1585     if (!font) return FALSE;
 1586 
 1587     if (config.cell_height != di->font[size_idx].height)
 1588         TRACE( "mismatched heights (%u<>%u)\n", config.cell_height, di->font[size_idx].height );
 1589 
 1590     old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
 1591     SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
 1592     if (old_font) DeleteObject( old_font );
 1593 
 1594     LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
 1595     args[0] = config.cell_width;
 1596     args[1] = config.cell_height;
 1597     FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
 1598                     fmt, 0, 0, buf, ARRAY_SIZE(buf), (__ms_va_list*)args );
 1599 
 1600     SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
 1601     return TRUE;
 1602 }
 1603 
 1604 /* fills the size list box according to selected family in font LB */
 1605 static BOOL fill_list_size( struct dialog_info *di, BOOL init )
 1606 {
 1607     WCHAR face_name[LF_FACESIZE];
 1608     int idx = 0;
 1609 
 1610     idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
 1611     if (idx < 0) return FALSE;
 1612 
 1613     SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, idx, (LPARAM)face_name );
 1614     SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_RESETCONTENT, 0, 0 );
 1615     free( di->font );
 1616     di->font_count = 0;
 1617     di->font = NULL;
 1618 
 1619     EnumFontFamiliesW( di->console->window->mem_dc, face_name, font_enum_size, (LPARAM)di );
 1620 
 1621     if (init)
 1622     {
 1623         int ref = -1;
 1624         for (idx = 0; idx < di->font_count; idx++)
 1625         {
 1626             if (!lstrcmpW( di->font[idx].faceName, di->config.face_name ) &&
 1627                 di->font[idx].height == di->config.cell_height &&
 1628                 di->font[idx].weight == di->config.font_weight)
 1629             {
 1630                 if (ref == -1) ref = idx;
 1631                 else TRACE("Several matches found: ref=%d idx=%d\n", ref, idx);
 1632             }
 1633         }
 1634         idx = (ref == -1) ? 0 : ref;
 1635     }
 1636 
 1637     SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
 1638     select_font( di );
 1639     return TRUE;
 1640 }
 1641 
 1642 static BOOL fill_list_font( struct dialog_info *di )
 1643 {
 1644     SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_RESETCONTENT, 0, 0 );
 1645     EnumFontFamiliesW( di->console->window->mem_dc, NULL, font_enum, (LPARAM)di );
 1646     if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
 1647                              -1, (LPARAM)di->config.face_name ) == LB_ERR)
 1648         SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
 1649     fill_list_size( di, TRUE );
 1650     return TRUE;
 1651 }
 1652 
 1653 /* dialog proc for the font property sheet */
 1654 static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
 1655 {
 1656     struct dialog_info *di;
 1657 
 1658     switch (msg)
 1659     {
 1660     case WM_INITDIALOG:
 1661         di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
 1662         di->dialog = dialog;
 1663         SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
 1664         /* remove dialog from this control, font will be reset when listboxes are filled */
 1665         SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
 1666         fill_list_font( di );
 1667         SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
 1668         SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
 1669         break;
 1670 
 1671     case WM_COMMAND:
 1672         di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
 1673         switch (LOWORD(wparam))
 1674         {
 1675         case IDC_FNT_LIST_FONT:
 1676             if (HIWORD(wparam) == LBN_SELCHANGE)
 1677                 fill_list_size( di, FALSE );
 1678             break;
 1679         case IDC_FNT_LIST_SIZE:
 1680             if (HIWORD(wparam) == LBN_SELCHANGE)
 1681                 select_font( di );
 1682             break;
 1683         }
 1684         break;
 1685 
 1686     case WM_NOTIFY:
 1687         {
 1688             NMHDR *nmhdr = (NMHDR*)lparam;
 1689             DWORD val;
 1690 
 1691             di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
 1692             switch (nmhdr->code)
 1693             {
 1694             case PSN_SETACTIVE:
 1695                 di->dialog = dialog;
 1696                 break;
 1697             case PSN_APPLY:
 1698                 val = SendDlgItemMessageW( dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
 1699                 if (val < di->font_count)
 1700                 {
 1701                     LOGFONTW lf;
 1702 
 1703                     fill_logfont( &lf, di->font[val].faceName, di->font[val].height, di->font[val].weight );
 1704                     DeleteObject( select_font_config( &di->config, di->console->output_cp,
 1705                                                       di->console->win, &lf ));
 1706                 }
 1707 
 1708                 val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
 1709                     GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
 1710                 di->config.attr = val;
 1711                 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
 1712                 return TRUE;
 1713             default:
 1714                 return FALSE;
 1715             }
 1716             break;
 1717         }
 1718     default:
 1719         return FALSE;
 1720     }
 1721     return TRUE;
 1722 }
 1723 
 1724 /* dialog proc for the config property sheet */
 1725 static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
 1726 {
 1727     struct dialog_info *di;
 1728     int max_ud = 2000;
 1729 
 1730     switch (msg)
 1731     {
 1732     case WM_INITDIALOG:
 1733         di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
 1734         di->dialog = dialog;
 1735 
 1736         SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
 1737         SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH,   di->config.sb_width,   FALSE );
 1738         SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT,  di->config.sb_height,  FALSE );
 1739         SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH,  di->config.win_width,  FALSE );
 1740         SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
 1741 
 1742         SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
 1743         SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD),  UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
 1744         SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD),  UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
 1745         SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD),   UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
 1746 
 1747         SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, BST_CHECKED, 0 );
 1748 
 1749         SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
 1750         SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
 1751         SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
 1752         break;
 1753 
 1754     case WM_NOTIFY:
 1755         {
 1756             NMHDR *nmhdr = (NMHDR*)lparam;
 1757             int win_w, win_h, sb_w, sb_h;
 1758             BOOL st1, st2;
 1759 
 1760             di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
 1761             switch (nmhdr->code)
 1762             {
 1763             case PSN_SETACTIVE:
 1764                 di->dialog = dialog;
 1765                 break;
 1766             case PSN_APPLY:
 1767                 sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH,  &st1, FALSE );
 1768                 sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
 1769                 if (!st1 || ! st2)
 1770                 {
 1771                     SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
 1772                     return TRUE;
 1773                 }
 1774                 win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH,  &st1, FALSE );
 1775                 win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
 1776                 if (!st1 || !st2)
 1777                 {
 1778                     SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
 1779                     return TRUE;
 1780                 }
 1781                 if (win_w > sb_w || win_h > sb_h)
 1782                 {
 1783                     WCHAR cap[256];
 1784                     WCHAR txt[256];
 1785 
 1786                     LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
 1787                     LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
 1788 
 1789                     MessageBoxW( dialog, txt, cap, MB_OK );
 1790                     SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
 1791                     return TRUE;
 1792                 }
 1793                 di->config.win_width  = win_w;
 1794                 di->config.win_height = win_h;
 1795                 di->config.sb_width  = sb_w;
 1796                 di->config.sb_height = sb_h;
 1797 
 1798                 di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
 1799                                                                CB_GETCURSEL, 0, 0 );
 1800                 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
 1801                 return TRUE;
 1802             default:
 1803                 return FALSE;
 1804             }
 1805             break;
 1806         }
 1807     default:
 1808         return FALSE;
 1809     }
 1810     return TRUE;
 1811 }
 1812 
 1813 /* dialog proc for choosing how to handle modification to the console settings */
 1814 static INT_PTR WINAPI save_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
 1815 {
 1816     switch (msg)
 1817     {
 1818     case WM_INITDIALOG:
 1819         SendDlgItemMessageW( dialog, IDC_SAV_SESSION, BM_SETCHECK, BST_CHECKED, 0 );
 1820         break;
 1821 
 1822     case WM_COMMAND:
 1823         switch (LOWORD(wparam))
 1824         {
 1825         case IDOK:
 1826             EndDialog( dialog,
 1827                        (IsDlgButtonChecked(dialog, IDC_SAV_SAVE) == BST_CHECKED) ?
 1828                        IDC_SAV_SAVE : IDC_SAV_SESSION );
 1829             break;
 1830         case IDCANCEL:
 1831             EndDialog( dialog, IDCANCEL ); break;
 1832         }
 1833         break;
 1834     default:
 1835         return FALSE;
 1836     }
 1837     return TRUE;
 1838 }
 1839 
 1840 static void apply_config( struct console *console, const struct console_config *config )
 1841 {
 1842     if (console->active->width != config->sb_width || console->active->height != config->sb_height)
 1843         change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
 1844 
 1845     console->window->menu_mask  = config->menu_mask;
 1846     console->window->quick_edit = config->quick_edit;
 1847 
 1848     console->edition_mode = config->edition_mode;
 1849     console->history_mode = config->history_mode;
 1850 
 1851     if (console->history_size != config->history_size)
 1852     {
 1853         struct history_line **mem = NULL;
 1854         int i, delta;
 1855 
 1856         if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
 1857         {
 1858             memset( mem, 0, config->history_size * sizeof(*mem) );
 1859 
 1860             delta = (console->history_index > config->history_size)
 1861                 ? (console->history_index - config->history_size) : 0;
 1862 
 1863             for (i = delta; i < console->history_index; i++)
 1864             {
 1865                 mem[i - delta] = console->history[i];
 1866                 console->history[i] = NULL;
 1867             }
 1868             console->history_index -= delta;
 1869 
 1870             for (i = 0; i < console->history_size; i++)
 1871                 free( console->history[i] );
 1872             free( console->history );
 1873             console->history = mem;
 1874             console->history_size = config->history_size;
 1875         }
 1876     }
 1877 
 1878     if (config->insert_mode)
 1879         console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
 1880     else
 1881         console->mode &= ~ENABLE_INSERT_MODE;
 1882 
 1883     console->active->cursor_size = config->cursor_size;
 1884     console->active->cursor_visible = config->cursor_visible;
 1885     console->active->attr = config->attr;
 1886     console->active->popup_attr = config->popup_attr;
 1887     console->active->win.left   = config->win_pos.X;
 1888     console->active->win.top    = config->win_pos.Y;
 1889     console->active->win.right  = config->win_pos.X + config->win_width - 1;
 1890     console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
 1891     memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
 1892 
 1893     if (console->active->font.width != config->cell_width ||
 1894         console->active->font.height != config->cell_height ||
 1895         console->active->font.weight != config->font_weight ||
 1896         console->active->font.pitch_family != config->font_pitch_family ||
 1897         console->active->font.face_len != wcslen( config->face_name ) * sizeof(WCHAR) ||
 1898         memcmp( console->active->font.face_name, config->face_name, console->active->font.face_len ))
 1899     {
 1900         update_console_font( console, config->face_name, config->cell_height, config->font_weight );
 1901     }
 1902 
 1903     update_window( console );
 1904 
 1905     notify_screen_buffer_size( console->active );
 1906 }
 1907 
 1908 static void current_config( struct console *console, struct console_config *config )
 1909 {
 1910     size_t len;
 1911 
 1912     config->menu_mask  = console->window->menu_mask;
 1913     config->quick_edit = console->window->quick_edit;
 1914 
 1915     config->edition_mode = console->edition_mode;
 1916     config->history_mode = console->history_mode;
 1917     config->history_size = console->history_size;
 1918 
 1919     config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
 1920         (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
 1921 
 1922     config->cursor_size = console->active->cursor_size;
 1923     config->cursor_visible = console->active->cursor_visible;
 1924     config->attr = console->active->attr;
 1925     config->popup_attr = console->active->popup_attr;
 1926     memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
 1927 
 1928     config->win_height  = console->active->win.bottom - console->active->win.top + 1;
 1929     config->win_width   = console->active->win.right - console->active->win.left + 1;
 1930     config->cell_width  = console->active->font.width;
 1931     config->cell_height = console->active->font.height;
 1932     config->font_weight = console->active->font.weight;
 1933     config->font_pitch_family = console->active->font.pitch_family;
 1934     len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len / sizeof(WCHAR) );
 1935     if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
 1936     config->face_name[len] = 0;
 1937 
 1938     config->sb_width  = console->active->width;
 1939     config->sb_height = console->active->height;
 1940 
 1941     config->win_width  = console->active->win.right - console->active->win.left + 1;
 1942     config->win_height = console->active->win.bottom - console->active->win.top + 1;
 1943     config->win_pos.X  = console->active->win.left;
 1944     config->win_pos.Y  = console->active->win.top;
 1945 }
 1946 
 1947 /* run the dialog box to set up the console options */
 1948 static BOOL config_dialog( struct console *console, BOOL current )
 1949 {
 1950     struct console_config prev_config;
 1951     struct dialog_info di;
 1952     PROPSHEETHEADERW header;
 1953     HPROPSHEETPAGE pages[3];
 1954     PROPSHEETPAGEW psp;
 1955     WNDCLASSW wndclass;
 1956     WCHAR buff[256];
 1957     BOOL modify_session = FALSE;
 1958     BOOL save = FALSE;
 1959 
 1960     InitCommonControls();
 1961 
 1962     memset( &di, 0, sizeof(di) );
 1963     di.console = console;
 1964     if (!current)
 1965     {
 1966         load_config( NULL, &di.config );
 1967         save = TRUE;
 1968     }
 1969     else current_config( console, &di.config );
 1970     prev_config = di.config;
 1971     di.font_count = 0;
 1972     di.font = NULL;
 1973 
 1974     wndclass.style         = 0;
 1975     wndclass.lpfnWndProc   = font_preview_proc;
 1976     wndclass.cbClsExtra    = 0;
 1977     wndclass.cbWndExtra    = sizeof(HFONT);
 1978     wndclass.hInstance     = GetModuleHandleW( NULL );
 1979     wndclass.hIcon         = 0;
 1980     wndclass.hCursor       = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
 1981     wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
 1982     wndclass.lpszMenuName  = NULL;
 1983     wndclass.lpszClassName = L"WineConFontPreview";
 1984     RegisterClassW( &wndclass );
 1985 
 1986     wndclass.style         = 0;
 1987     wndclass.lpfnWndProc   = color_preview_proc;
 1988     wndclass.cbClsExtra    = 0;
 1989     wndclass.cbWndExtra    = sizeof(DWORD);
 1990     wndclass.hInstance     = GetModuleHandleW( NULL );
 1991     wndclass.hIcon         = 0;
 1992     wndclass.hCursor       = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
 1993     wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
 1994     wndclass.lpszMenuName  = NULL;
 1995     wndclass.lpszClassName = L"WineConColorPreview";
 1996     RegisterClassW( &wndclass );
 1997 
 1998     memset( &psp, 0, sizeof(psp) );
 1999     psp.dwSize = sizeof(psp);
 2000     psp.dwFlags = 0;
 2001     psp.hInstance = wndclass.hInstance;
 2002     psp.lParam = (LPARAM)&di;
 2003 
 2004     psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
 2005     psp.pfnDlgProc = option_dialog_proc;
 2006     pages[0] = CreatePropertySheetPageW( &psp );
 2007 
 2008     psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
 2009     psp.pfnDlgProc = font_dialog_proc;
 2010     pages[1] = CreatePropertySheetPageW( &psp );
 2011 
 2012     psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
 2013     psp.pfnDlgProc = config_dialog_proc;
 2014     pages[2] = CreatePropertySheetPageW( &psp );
 2015 
 2016     memset( &header, 0, sizeof(header) );
 2017     header.dwSize = sizeof(header);
 2018 
 2019     if (!LoadStringW( GetModuleHandleW( NULL ),
 2020                       current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
 2021                       buff, ARRAY_SIZE(buff) ))
 2022         wcscpy( buff, L"Setup" );
 2023 
 2024     header.pszCaption = buff;
 2025     header.nPages     = 3;
 2026     header.hwndParent = console->win;
 2027     header.u3.phpage  = pages;
 2028     header.dwFlags    = PSH_NOAPPLYNOW;
 2029     PropertySheetW( &header );
 2030 
 2031     if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
 2032         return TRUE;
 2033 
 2034     TRACE( "%s\n", debugstr_config(&di.config) );
 2035 
 2036     if (!save)
 2037     {
 2038         switch (DialogBoxW( GetModuleHandleW( NULL ), MAKEINTRESOURCEW(IDD_SAVE_SETTINGS),
 2039                             console->win, save_dialog_proc ))
 2040         {
 2041         case IDC_SAV_SAVE:
 2042             save = TRUE;
 2043             modify_session = TRUE;
 2044             break;
 2045         case IDC_SAV_SESSION:
 2046             modify_session = TRUE;
 2047             break;
 2048         default:
 2049             ERR( "dialog failed\n" );
 2050             /* fall through */
 2051         case IDCANCEL:
 2052             modify_session = FALSE;
 2053             save = FALSE;
 2054             break;
 2055         }
 2056     }
 2057 
 2058     if (modify_session)
 2059     {
 2060         apply_config( console, &di.config );
 2061         update_window( di.console );
 2062     }
 2063     if (save)
 2064         save_config( current ? console->window->config_key : NULL, &di.config );
 2065     return TRUE;
 2066 }
 2067 
 2068 static void resize_window( struct console *console, int width, int height )
 2069 {
 2070     struct console_config config;
 2071 
 2072     current_config( console, &config );
 2073     config.win_width  = width;
 2074     config.win_height = height;
 2075 
 2076     /* auto size screen-buffer if it's now smaller than window */
 2077     if (config.sb_width < config.win_width)
 2078         config.sb_width = config.win_width;
 2079     if (config.sb_height < config.win_height)
 2080         config.sb_height = config.win_height;
 2081 
 2082     /* and reset window pos so that we don't display outside of the screen-buffer */
 2083     if (config.win_pos.X + config.win_width > config.sb_width)
 2084         config.win_pos.X = config.sb_width - config.win_width;
 2085     if (config.win_pos.Y + config.win_height > config.sb_height)
 2086         config.win_pos.Y = config.sb_height - config.win_height;
 2087 
 2088     apply_config( console, &config );
 2089 }
 2090 
 2091 /* grays / ungrays the menu items according to their state */
 2092 static void set_menu_details( struct console *console, HMENU menu )
 2093 {
 2094     EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
 2095                     (console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
 2096     EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
 2097                     (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
 2098     EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
 2099     EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
 2100 }
 2101 
 2102 static BOOL fill_menu( HMENU menu, BOOL sep )
 2103 {
 2104     HINSTANCE module = GetModuleHandleW( NULL );
 2105     HMENU sub_menu;
 2106     WCHAR buff[256];
 2107 
 2108     if (!menu) return FALSE;
 2109 
 2110     sub_menu = CreateMenu();
 2111     if (!sub_menu) return FALSE;
 2112 
 2113     LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
 2114     InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
 2115     LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
 2116     InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
 2117     LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
 2118     InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
 2119     LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
 2120     InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
 2121     LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
 2122     InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
 2123     LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
 2124     InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
 2125 
 2126     if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
 2127     LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
 2128     InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
 2129     LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
 2130     InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
 2131     LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
 2132     InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
 2133 
 2134     return TRUE;
 2135 }
 2136 
 2137 static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
 2138 {
 2139     struct console *console = create->lpCreateParams;
 2140     HMENU sys_menu;
 2141 
 2142     TRACE( "%p\n", hwnd );
 2143 
 2144     SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
 2145     console->win = hwnd;
 2146 
 2147     sys_menu = GetSystemMenu( hwnd, FALSE );
 2148     if (!sys_menu) return 0;
 2149     console->window->popup_menu = CreatePopupMenu();
 2150     if (!console->window->popup_menu) return 0;
 2151 
 2152     fill_menu( sys_menu, TRUE );
 2153     fill_menu( console->window->popup_menu, FALSE );
 2154 
 2155     console->window->mem_dc = CreateCompatibleDC( 0 );
 2156     return 0;
 2157 }
 2158 
 2159 static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
 2160 {
 2161     struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
 2162 
 2163     switch (msg)
 2164     {
 2165     case WM_CREATE:
 2166         return window_create( hwnd, (const CREATESTRUCTW *)lparam );
 2167 
 2168     case WM_DESTROY:
 2169         console->win = NULL;
 2170         PostQuitMessage( 0 );
 2171         break;
 2172 
 2173     case WM_UPDATE_CONFIG:
 2174         update_window( console );
 2175         break;
 2176 
 2177     case WM_PAINT:
 2178         {
 2179             PAINTSTRUCT ps;
 2180 
 2181             BeginPaint( console->win, &ps );
 2182             BitBlt( ps.hdc, 0, 0,
 2183                     (console->active->win.right - console->active->win.left + 1) * console->active->font.width,
 2184                     (console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
 2185                     console->window->mem_dc,
 2186                     console->active->win.left * console->active->font.width,
 2187                     console->active->win.top  * console->active->font.height,
 2188                     SRCCOPY );
 2189             if (console->window->in_selection) update_selection( console, ps.hdc );
 2190             EndPaint( console->win, &ps );
 2191             break;
 2192         }
 2193 
 2194     case WM_SHOWWINDOW:
 2195         if (wparam)
 2196             update_window( console );
 2197         else
 2198         {
 2199             if (console->window->bitmap) DeleteObject( console->window->bitmap );
 2200             console->window->bitmap = NULL;
 2201         }
 2202         break;
 2203 
 2204     case WM_KEYDOWN:
 2205     case WM_KEYUP:
 2206         if (console->window->in_selection)
 2207             handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
 2208         else
 2209             record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
 2210         break;
 2211 
 2212     case WM_SYSKEYDOWN:
 2213     case WM_SYSKEYUP:
 2214         record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
 2215         break;
 2216 
 2217     case WM_LBUTTONDOWN:
 2218         if (console->window->quick_edit || console->window->in_selection)
 2219         {
 2220             if (console->window->in_selection)
 2221                 update_selection( console, 0 );
 2222 
 2223             if (console->window->quick_edit && console->window->in_selection)
 2224             {
 2225                 console->window->in_selection = FALSE;
 2226             }
 2227             else
 2228             {
 2229                 console->window->selection_end = get_cell( console, lparam );
 2230                 console->window->selection_start = console->window->selection_end;
 2231                 SetCapture( console->win );
 2232                 update_selection( console, 0 );
 2233                 console->window->in_selection = TRUE;
 2234             }
 2235         }
 2236         else
 2237         {
 2238             record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
 2239         }
 2240         break;
 2241 
 2242     case WM_MOUSEMOVE:
 2243         if (console->window->quick_edit || console->window->in_selection)
 2244         {
 2245             if (GetCapture() == console->win && console->window->in_selection &&
 2246                 (wparam & MK_LBUTTON))
 2247             {
 2248                 move_selection( console, console->window->selection_start,
 2249                                 get_cell(console, lparam) );
 2250             }
 2251         }
 2252         else
 2253         {
 2254             record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
 2255         }
 2256         break;
 2257 
 2258     case WM_LBUTTONUP:
 2259         if (console->window->quick_edit || console->window->in_selection)
 2260         {
 2261             if (GetCapture() == console->win && console->window->in_selection)
 2262             {
 2263                 move_selection( console, console->window->selection_start,
 2264                                 get_cell(console, lparam) );
 2265                 ReleaseCapture();
 2266             }
 2267         }
 2268         else
 2269         {
 2270             record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
 2271         }
 2272         break;
 2273 
 2274     case WM_RBUTTONDOWN:
 2275         if ((wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
 2276         {
 2277             POINT       pt;
 2278             pt.x = (short)LOWORD(lparam);
 2279             pt.y = (short)HIWORD(lparam);
 2280             ClientToScreen( hwnd, &pt );
 2281             set_menu_details( console, console->window->popup_menu );
 2282             TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
 2283                             pt.x, pt.y, 0, hwnd, NULL );
 2284         }
 2285         else
 2286         {
 2287             record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
 2288         }
 2289         break;
 2290 
 2291     case WM_RBUTTONUP:
 2292         /* no need to track for rbutton up when opening the popup... the event will be
 2293          * swallowed by TrackPopupMenu */
 2294     case WM_MBUTTONDOWN:
 2295     case WM_MBUTTONUP:
 2296         record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
 2297         break;
 2298 
 2299     case WM_LBUTTONDBLCLK:
 2300     case WM_MBUTTONDBLCLK:
 2301     case WM_RBUTTONDBLCLK:
 2302         record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
 2303         break;
 2304 
 2305     case WM_SETFOCUS:
 2306         if (console->active->cursor_visible)
 2307         {
 2308             CreateCaret( console->win, console->window->cursor_bitmap,
 2309                          console->active->font.width, console->active->font.height );
 2310             update_window_cursor( console );
 2311         }
 2312         break;
 2313 
 2314     case WM_KILLFOCUS:
 2315         if (console->active->cursor_visible)
 2316             DestroyCaret();
 2317         break;
 2318 
 2319     case WM_SIZE:
 2320         if (console->window->update_state != UPDATE_BUSY)
 2321             resize_window( console,
 2322                            max( LOWORD(lparam) / console->active->font.width, 20 ),
 2323                            max( HIWORD(lparam) / console->active->font.height, 20 ));
 2324         break;
 2325 
 2326     case WM_HSCROLL:
 2327         {
 2328             int win_width = console->active->win.right - console->active->win.left + 1;
 2329             int x = console->active->win.left;
 2330 
 2331             switch (LOWORD(wparam))
 2332             {
 2333             case SB_PAGEUP:     x -= 8;              break;
 2334             case SB_PAGEDOWN:   x += 8;              break;
 2335             case SB_LINEUP:     x--;                 break;
 2336             case SB_LINEDOWN:   x++;                 break;
 2337             case SB_THUMBTRACK: x = HIWORD(wparam);  break;
 2338             default:                                 break;
 2339             }
 2340             x = min( max( x, 0 ), console->active->width - win_width );
 2341             if (x != console->active->win.left)
 2342             {
 2343                 console->active->win.left  = x;
 2344                 console->active->win.right = x + win_width - 1;
 2345                 update_window( console );
 2346             }
 2347             break;
 2348         }
 2349 
 2350     case WM_MOUSEWHEEL:
 2351         if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
 2352         {
 2353             record_mouse_input(console,  get_cell(console, lparam), wparam, MOUSE_WHEELED);
 2354             break;
 2355         }
 2356         /* else fallthrough */
 2357     case WM_VSCROLL:
 2358         {
 2359             int win_height = console->active->win.bottom - console->active->win.top + 1;
 2360             int y = console->active->win.top;
 2361 
 2362             if (msg == WM_MOUSEWHEEL)
 2363             {
 2364                 UINT scroll_lines = 3;
 2365                 SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
 2366                 scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
 2367                 y += scroll_lines;
 2368             }
 2369             else
 2370             {
 2371                 switch (LOWORD(wparam))
 2372                 {
 2373                 case SB_PAGEUP:     y -= 8;              break;
 2374                 case SB_PAGEDOWN:   y += 8;              break;
 2375                 case SB_LINEUP:     y--;                 break;
 2376                 case SB_LINEDOWN:   y++;                 break;
 2377                 case SB_THUMBTRACK: y = HIWORD(wparam);  break;
 2378                 default:                                 break;
 2379                 }
 2380             }
 2381 
 2382             y = min( max( y, 0 ), console->active->height - win_height );
 2383             if (y != console->active->win.top)
 2384             {
 2385                 console->active->win.top    = y;
 2386                 console->active->win.bottom = y + win_height - 1;
 2387                 update_window( console );
 2388             }
 2389             break;
 2390         }
 2391 
 2392     case WM_SYSCOMMAND:
 2393         switch (wparam)
 2394         {
 2395         case IDS_DEFAULT:
 2396             config_dialog( console, FALSE );
 2397             break;
 2398         case IDS_PROPERTIES:
 2399             config_dialog( console, TRUE );
 2400             break;
 2401         default:
 2402             return DefWindowProcW( hwnd, msg, wparam, lparam );
 2403         }
 2404         break;
 2405 
 2406     case WM_COMMAND:
 2407         switch (wparam)
 2408         {
 2409         case IDS_DEFAULT:
 2410             config_dialog( console, FALSE );
 2411             break;
 2412         case IDS_PROPERTIES:
 2413             config_dialog( console, TRUE );
 2414             break;
 2415         case IDS_MARK:
 2416             console->window->selection_start.X = console->window->selection_start.Y = 0;
 2417             console->window->selection_end.X = console->window->selection_end.Y = 0;
 2418             update_selection( console, 0 );
 2419             console->window->in_selection = TRUE;
 2420             break;
 2421         case IDS_COPY:
 2422             if (console->window->in_selection)
 2423             {
 2424                 console->window->in_selection = FALSE;
 2425                 update_selection( console, 0 );
 2426                 copy_selection( console );
 2427             }
 2428             break;
 2429         case IDS_PASTE:
 2430             paste_clipboard( console );
 2431             break;
 2432         case IDS_SELECTALL:
 2433             console->window->selection_start.X = console->window->selection_start.Y = 0;
 2434             console->window->selection_end.X = console->active->width - 1;
 2435             console->window->selection_end.Y = console->active->height - 1;
 2436             update_selection( console, 0 );
 2437             console->window->in_selection = TRUE;
 2438             break;
 2439         case IDS_SCROLL:
 2440         case IDS_SEARCH:
 2441             FIXME( "Unhandled yet command: %lx\n", wparam );
 2442             break;
 2443         default:
 2444             return DefWindowProcW( hwnd, msg, wparam, lparam );
 2445         }
 2446         break;
 2447 
 2448     case WM_INITMENUPOPUP:
 2449         if (!HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
 2450         set_menu_details( console, GetSystemMenu(console->win, FALSE) );
 2451         break;
 2452 
 2453     default:
 2454         return DefWindowProcW( hwnd, msg, wparam, lparam );
 2455     }
 2456 
 2457     return 0;
 2458 }
 2459 
 2460 void update_window_config( struct console *console )
 2461 {
 2462     if (!console->win || console->window->update_state != UPDATE_NONE) return;
 2463     console->window->update_state = UPDATE_PENDING;
 2464     PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
 2465 }
 2466 
 2467 void update_window_region( struct console *console, const RECT *update )
 2468 {
 2469     RECT *window_rect = &console->window->update;
 2470     window_rect->left   = min( window_rect->left,   update->left );
 2471     window_rect->top    = min( window_rect->top,    update->top );
 2472     window_rect->right  = max( window_rect->right,  update->right );
 2473     window_rect->bottom = max( window_rect->bottom, update->bottom );
 2474     update_window_config( console );
 2475 }
 2476 
 2477 BOOL init_window( struct console *console )
 2478 {
 2479     struct console_config config;
 2480     WNDCLASSW wndclass;
 2481     STARTUPINFOW si;
 2482     CHARSETINFO ci;
 2483 
 2484     static struct console_window console_window;
 2485 
 2486     console->window = &console_window;
 2487     if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
 2488         return FALSE;
 2489 
 2490     console->window->ui_charset = ci.ciCharset;
 2491 
 2492     GetStartupInfoW(&si);
 2493     if (si.lpTitle)
 2494     {
 2495         size_t i, title_len = wcslen( si.lpTitle );
 2496         if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
 2497             return FALSE;
 2498         for (i = 0; i < title_len; i++)
 2499             console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
 2500         console->window->config_key[title_len] = 0;
 2501     }
 2502 
 2503     load_config( console->window->config_key, &config );
 2504     if (si.dwFlags & STARTF_USECOUNTCHARS)
 2505     {
 2506         config.sb_width  = si.dwXCountChars;
 2507         config.sb_height = si.dwYCountChars;
 2508     }
 2509     if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
 2510         config.attr = si.dwFillAttribute;
 2511 
 2512     wndclass.style         = CS_DBLCLKS;
 2513     wndclass.lpfnWndProc   = window_proc;
 2514     wndclass.cbClsExtra    = 0;
 2515     wndclass.cbWndExtra    = sizeof(DWORD_PTR);
 2516     wndclass.hInstance     = GetModuleHandleW(NULL);
 2517     wndclass.hIcon         = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
 2518     wndclass.hCursor       = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
 2519     wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
 2520     wndclass.lpszMenuName  = NULL;
 2521     wndclass.lpszClassName = L"WineConsoleClass";
 2522     RegisterClassW(&wndclass);
 2523 
 2524     if (!CreateWindowW( wndclass.lpszClassName, NULL,
 2525                         WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
 2526                         WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
 2527                         0, 0, 0, 0, wndclass.hInstance, console ))
 2528         return FALSE;
 2529 
 2530     apply_config( console, &config );
 2531     return TRUE;
 2532 }