window.c 93 KB

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