window.c 89 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468
  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=%ld lfWidth=%ld lfEscapement=%ld "
  101. "lfOrientation=%ld lfWeight=%ld 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=%ld tmAscent=%ld tmDescent=%ld "
  114. "tmAveCharWidth=%ld tmMaxCharWidth=%ld tmWeight=%ld "
  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 *face_name, size_t face_name_size,
  556. unsigned int height, unsigned int weight )
  557. {
  558. lf->lfHeight = height;
  559. lf->lfWidth = 0;
  560. lf->lfEscapement = 0;
  561. lf->lfOrientation = 0;
  562. lf->lfWeight = weight;
  563. lf->lfItalic = FALSE;
  564. lf->lfUnderline = FALSE;
  565. lf->lfStrikeOut = FALSE;
  566. lf->lfCharSet = DEFAULT_CHARSET;
  567. lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
  568. lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
  569. lf->lfQuality = DEFAULT_QUALITY;
  570. lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
  571. face_name_size = min( face_name_size, sizeof(lf->lfFaceName) - sizeof(WCHAR) );
  572. memcpy( lf->lfFaceName, face_name, face_name_size );
  573. lf->lfFaceName[face_name_size / sizeof(WCHAR)] = 0;
  574. }
  575. static BOOL set_console_font( struct console *console, const LOGFONTW *logfont )
  576. {
  577. struct font_info *font_info = &console->active->font;
  578. HFONT font, old_font;
  579. TEXTMETRICW tm;
  580. CPINFO cpinfo;
  581. HDC dc;
  582. TRACE( "%s\n", debugstr_logfont( logfont, 0 ));
  583. if (console->window->font && logfont->lfHeight == console->active->font.height &&
  584. logfont->lfWeight == console->active->font.weight &&
  585. !logfont->lfItalic && !logfont->lfUnderline && !logfont->lfStrikeOut &&
  586. console->active->font.face_len == wcslen( logfont->lfFaceName ) &&
  587. !memcmp( logfont->lfFaceName, console->active->font.face_name,
  588. console->active->font.face_len * sizeof(WCHAR) ))
  589. {
  590. TRACE( "equal to current\n" );
  591. return TRUE;
  592. }
  593. if (!(dc = GetDC( console->win ))) return FALSE;
  594. if (!(font = CreateFontIndirectW( logfont )))
  595. {
  596. ReleaseDC( console->win, dc );
  597. return FALSE;
  598. }
  599. old_font = SelectObject( dc, font );
  600. GetTextMetricsW( dc, &tm );
  601. SelectObject( dc, old_font );
  602. ReleaseDC( console->win, dc );
  603. font_info->width = tm.tmAveCharWidth;
  604. font_info->height = tm.tmHeight + tm.tmExternalLeading;
  605. font_info->pitch_family = tm.tmPitchAndFamily;
  606. font_info->weight = tm.tmWeight;
  607. free( font_info->face_name );
  608. font_info->face_len = wcslen( logfont->lfFaceName );
  609. font_info->face_name = malloc( font_info->face_len * sizeof(WCHAR) );
  610. memcpy( font_info->face_name, logfont->lfFaceName, font_info->face_len * sizeof(WCHAR) );
  611. /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
  612. if (GetCPInfo( console->output_cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
  613. font_info->width = tm.tmMaxCharWidth;
  614. if (console->window->font) DeleteObject( console->window->font );
  615. console->window->font = font;
  616. console->window->ext_leading = tm.tmExternalLeading;
  617. if (console->window->bitmap)
  618. {
  619. DeleteObject(console->window->bitmap);
  620. console->window->bitmap = NULL;
  621. }
  622. return TRUE;
  623. }
  624. struct font_chooser
  625. {
  626. struct console *console;
  627. int pass;
  628. BOOL done;
  629. };
  630. /* check if the font described in tm is usable as a font for the renderer */
  631. static BOOL validate_font_metric( struct console *console, const TEXTMETRICW *tm,
  632. DWORD type, int pass )
  633. {
  634. switch (pass) /* we get increasingly lenient in later passes */
  635. {
  636. case 0:
  637. if (type & RASTER_FONTTYPE) return FALSE;
  638. /* fall through */
  639. case 1:
  640. if (type & RASTER_FONTTYPE)
  641. {
  642. if (tm->tmMaxCharWidth * (console->active->win.right - console->active->win.left + 1)
  643. >= GetSystemMetrics(SM_CXSCREEN))
  644. return FALSE;
  645. if (tm->tmHeight * (console->active->win.bottom - console->active->win.top + 1)
  646. >= GetSystemMetrics(SM_CYSCREEN))
  647. return FALSE;
  648. }
  649. /* fall through */
  650. case 2:
  651. if (tm->tmCharSet != DEFAULT_CHARSET && tm->tmCharSet != console->window->ui_charset)
  652. return FALSE;
  653. /* fall through */
  654. case 3:
  655. if (tm->tmItalic || tm->tmUnderlined || tm->tmStruckOut) return FALSE;
  656. break;
  657. }
  658. return TRUE;
  659. }
  660. /* check if the font family described in lf is usable as a font for the renderer */
  661. static BOOL validate_font( struct console *console, const LOGFONTW *lf, int pass )
  662. {
  663. switch (pass) /* we get increasingly lenient in later passes */
  664. {
  665. case 0:
  666. case 1:
  667. case 2:
  668. if (lf->lfCharSet != DEFAULT_CHARSET && lf->lfCharSet != console->window->ui_charset)
  669. return FALSE;
  670. /* fall through */
  671. case 3:
  672. if ((lf->lfPitchAndFamily & 3) != FIXED_PITCH) return FALSE;
  673. /* fall through */
  674. case 4:
  675. if (lf->lfFaceName[0] == '@') return FALSE;
  676. break;
  677. }
  678. return TRUE;
  679. }
  680. /* helper functions to get a decent font for the renderer */
  681. static int WINAPI get_first_font_sub_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
  682. DWORD font_type, LPARAM lparam)
  683. {
  684. struct font_chooser *fc = (struct font_chooser *)lparam;
  685. TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
  686. if (validate_font_metric( fc->console, tm, font_type, fc->pass ))
  687. {
  688. LOGFONTW mlf = *lf;
  689. /* Use the default sizes for the font (this is needed, especially for
  690. * TrueType fonts, so that we get a decent size, not the max size)
  691. */
  692. mlf.lfWidth = fc->console->active->font.width;
  693. mlf.lfHeight = fc->console->active->font.height;
  694. if (!mlf.lfHeight)
  695. mlf.lfHeight = MulDiv( 16, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
  696. if (set_console_font( fc->console, &mlf ))
  697. {
  698. struct console_config config;
  699. fc->done = 1;
  700. /* since we've modified the current config with new font information,
  701. * set this information as the new default.
  702. */
  703. load_config( fc->console->window->config_key, &config );
  704. config.cell_width = fc->console->active->font.width;
  705. config.cell_height = fc->console->active->font.height;
  706. config.font_pitch_family = fc->console->active->font.pitch_family;
  707. memcpy( config.face_name, fc->console->active->font.face_name,
  708. fc->console->active->font.face_len * sizeof(WCHAR) );
  709. config.face_name[fc->console->active->font.face_len] = 0;
  710. /* Force also its writing back to the registry so that we can get it
  711. * the next time.
  712. */
  713. save_config( fc->console->window->config_key, &config );
  714. return 0;
  715. }
  716. }
  717. return 1;
  718. }
  719. static int WINAPI get_first_font_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
  720. DWORD font_type, LPARAM lparam )
  721. {
  722. struct font_chooser *fc = (struct font_chooser *)lparam;
  723. TRACE("%s\n", debugstr_logfont( lf, font_type ));
  724. if (validate_font( fc->console, lf, fc->pass ))
  725. {
  726. EnumFontFamiliesW( fc->console->window->mem_dc, lf->lfFaceName,
  727. get_first_font_sub_enum, lparam );
  728. return !fc->done; /* we just need the first matching one... */
  729. }
  730. return 1;
  731. }
  732. /* sets logfont as the new font for the console */
  733. void update_console_font( struct console *console, const WCHAR *face_name, size_t face_name_size,
  734. unsigned int height, unsigned int weight )
  735. {
  736. struct font_chooser fc;
  737. LOGFONTW lf;
  738. if (face_name[0] && height && weight)
  739. {
  740. fill_logfont( &lf, face_name, face_name_size, height, weight );
  741. if (set_console_font( console, &lf )) return;
  742. }
  743. /* try to find an acceptable font */
  744. WARN( "Couldn't match the font from registry, trying to find one\n" );
  745. fc.console = console;
  746. fc.done = FALSE;
  747. for (fc.pass = 0; fc.pass <= 5; fc.pass++)
  748. {
  749. EnumFontFamiliesW( console->window->mem_dc, NULL, get_first_font_enum, (LPARAM)&fc );
  750. if (fc.done) return;
  751. }
  752. ERR( "Couldn't find a decent font\n" );
  753. }
  754. /* get a cell from a relative coordinate in window (takes into account the scrolling) */
  755. static COORD get_cell( struct console *console, LPARAM lparam )
  756. {
  757. COORD c;
  758. c.X = console->active->win.left + (short)LOWORD(lparam) / console->active->font.width;
  759. c.Y = console->active->win.top + (short)HIWORD(lparam) / console->active->font.height;
  760. return c;
  761. }
  762. /* get the console bit mask equivalent to the VK_ status in key state */
  763. static DWORD get_ctrl_state( BYTE *key_state)
  764. {
  765. unsigned int ret = 0;
  766. GetKeyboardState(key_state);
  767. if (key_state[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED;
  768. if (key_state[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED;
  769. if (key_state[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED;
  770. if (key_state[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED;
  771. if (key_state[VK_RMENU] & 0x80) ret |= RIGHT_ALT_PRESSED;
  772. if (key_state[VK_CAPITAL] & 0x01) ret |= CAPSLOCK_ON;
  773. if (key_state[VK_NUMLOCK] & 0x01) ret |= NUMLOCK_ON;
  774. if (key_state[VK_SCROLL] & 0x01) ret |= SCROLLLOCK_ON;
  775. return ret;
  776. }
  777. /* get the selection rectangle */
  778. static void get_selection_rect( struct console *console, RECT *r )
  779. {
  780. r->left = (min(console->window->selection_start.X, console->window->selection_end.X) -
  781. console->active->win.left) * console->active->font.width;
  782. r->top = (min(console->window->selection_start.Y, console->window->selection_end.Y) -
  783. console->active->win.top) * console->active->font.height;
  784. r->right = (max(console->window->selection_start.X, console->window->selection_end.X) + 1 -
  785. console->active->win.left) * console->active->font.width;
  786. r->bottom = (max(console->window->selection_start.Y, console->window->selection_end.Y) + 1 -
  787. console->active->win.top) * console->active->font.height;
  788. }
  789. static void update_selection( struct console *console, HDC ref_dc )
  790. {
  791. HDC dc;
  792. RECT r;
  793. get_selection_rect( console, &r );
  794. dc = ref_dc ? ref_dc : GetDC( console->win );
  795. if (!dc) return;
  796. if (console->win == GetFocus() && console->active->cursor_visible)
  797. HideCaret( console->win );
  798. InvertRect( dc, &r );
  799. if (dc != ref_dc)
  800. ReleaseDC( console->win, dc );
  801. if (console->win == GetFocus() && console->active->cursor_visible)
  802. ShowCaret( console->win );
  803. }
  804. static void move_selection( struct console *console, COORD c1, COORD c2 )
  805. {
  806. RECT r;
  807. HDC dc;
  808. if (c1.X < 0 || c1.X >= console->active->width ||
  809. c2.X < 0 || c2.X >= console->active->width ||
  810. c1.Y < 0 || c1.Y >= console->active->height ||
  811. c2.Y < 0 || c2.Y >= console->active->height)
  812. return;
  813. get_selection_rect( console, &r );
  814. dc = GetDC( console->win );
  815. if (dc)
  816. {
  817. if (console->win == GetFocus() && console->active->cursor_visible)
  818. HideCaret( console->win );
  819. InvertRect( dc, &r );
  820. }
  821. console->window->selection_start = c1;
  822. console->window->selection_end = c2;
  823. if (dc)
  824. {
  825. get_selection_rect( console, &r );
  826. InvertRect( dc, &r );
  827. ReleaseDC( console->win, dc );
  828. if (console->win == GetFocus() && console->active->cursor_visible)
  829. ShowCaret( console->win );
  830. }
  831. }
  832. /* copies the current selection into the clipboard */
  833. static void copy_selection( struct console *console )
  834. {
  835. unsigned int w, h;
  836. WCHAR *p, *buf;
  837. HANDLE mem;
  838. w = abs( console->window->selection_start.X - console->window->selection_end.X ) + 1;
  839. h = abs( console->window->selection_start.Y - console->window->selection_end.Y ) + 1;
  840. if (!OpenClipboard( console->win )) return;
  841. EmptyClipboard();
  842. mem = GlobalAlloc( GMEM_MOVEABLE, (w + 1) * h * sizeof(WCHAR) );
  843. if (mem && (p = buf = GlobalLock( mem )))
  844. {
  845. int x, y;
  846. COORD c;
  847. c.X = min( console->window->selection_start.X, console->window->selection_end.X );
  848. c.Y = min( console->window->selection_start.Y, console->window->selection_end.Y );
  849. for (y = c.Y; y < c.Y + h; y++)
  850. {
  851. WCHAR *end;
  852. for (x = c.X; x < c.X + w; x++)
  853. p[x - c.X] = console->active->data[y * console->active->width + x].ch;
  854. /* strip spaces from the end of the line */
  855. end = p + w;
  856. while (end > p && *(end - 1) == ' ')
  857. end--;
  858. *end = (y < c.Y + h - 1) ? '\n' : '\0';
  859. p = end + 1;
  860. }
  861. TRACE( "%s\n", debugstr_w( buf ));
  862. if (p - buf != (w + 1) * h)
  863. {
  864. HANDLE new_mem;
  865. new_mem = GlobalReAlloc( mem, (p - buf) * sizeof(WCHAR), GMEM_MOVEABLE );
  866. if (new_mem) mem = new_mem;
  867. }
  868. GlobalUnlock( mem );
  869. SetClipboardData( CF_UNICODETEXT, mem );
  870. }
  871. CloseClipboard();
  872. }
  873. static void paste_clipboard( struct console *console )
  874. {
  875. WCHAR *ptr;
  876. HANDLE h;
  877. if (!OpenClipboard( console->win )) return;
  878. h = GetClipboardData( CF_UNICODETEXT );
  879. if (h && (ptr = GlobalLock( h )))
  880. {
  881. unsigned int i, len = GlobalSize(h) / sizeof(WCHAR);
  882. INPUT_RECORD ir[2];
  883. SHORT sh;
  884. ir[0].EventType = KEY_EVENT;
  885. ir[0].Event.KeyEvent.wRepeatCount = 0;
  886. ir[0].Event.KeyEvent.dwControlKeyState = 0;
  887. ir[0].Event.KeyEvent.bKeyDown = TRUE;
  888. /* generate the corresponding input records */
  889. for (i = 0; i < len; i++)
  890. {
  891. /* FIXME: the modifying keys are not generated (shift, ctrl...) */
  892. sh = VkKeyScanW( ptr[i] );
  893. ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
  894. ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
  895. ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
  896. ir[1] = ir[0];
  897. ir[1].Event.KeyEvent.bKeyDown = FALSE;
  898. write_console_input( console, ir, 2, i == len - 1 );
  899. }
  900. GlobalUnlock( h );
  901. }
  902. CloseClipboard();
  903. }
  904. /* handle keys while selecting an area */
  905. static void handle_selection_key( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
  906. {
  907. BYTE key_state[256];
  908. COORD c1, c2;
  909. DWORD state;
  910. if (!down) return;
  911. state = get_ctrl_state( key_state ) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
  912. switch (state)
  913. {
  914. case 0:
  915. switch (wparam)
  916. {
  917. case VK_RETURN:
  918. console->window->in_selection = FALSE;
  919. update_selection( console, 0 );
  920. copy_selection( console );
  921. return;
  922. case VK_RIGHT:
  923. c1 = console->window->selection_start;
  924. c2 = console->window->selection_end;
  925. c1.X++; c2.X++;
  926. move_selection( console, c1, c2 );
  927. return;
  928. case VK_LEFT:
  929. c1 = console->window->selection_start;
  930. c2 = console->window->selection_end;
  931. c1.X--; c2.X--;
  932. move_selection( console, c1, c2 );
  933. return;
  934. case VK_UP:
  935. c1 = console->window->selection_start;
  936. c2 = console->window->selection_end;
  937. c1.Y--; c2.Y--;
  938. move_selection( console, c1, c2 );
  939. return;
  940. case VK_DOWN:
  941. c1 = console->window->selection_start;
  942. c2 = console->window->selection_end;
  943. c1.Y++; c2.Y++;
  944. move_selection( console, c1, c2 );
  945. return;
  946. }
  947. break;
  948. case SHIFT_PRESSED:
  949. switch (wparam)
  950. {
  951. case VK_RIGHT:
  952. c1 = console->window->selection_start;
  953. c2 = console->window->selection_end;
  954. c2.X++;
  955. move_selection( console, c1, c2 );
  956. return;
  957. case VK_LEFT:
  958. c1 = console->window->selection_start;
  959. c2 = console->window->selection_end;
  960. c2.X--;
  961. move_selection( console, c1, c2 );
  962. return;
  963. case VK_UP:
  964. c1 = console->window->selection_start;
  965. c2 = console->window->selection_end;
  966. c2.Y--;
  967. move_selection( console, c1, c2 );
  968. return;
  969. case VK_DOWN:
  970. c1 = console->window->selection_start;
  971. c2 = console->window->selection_end;
  972. c2.Y++;
  973. move_selection( console, c1, c2 );
  974. return;
  975. }
  976. break;
  977. }
  978. if (wparam < VK_SPACE) /* Shift, Alt, Ctrl, Num Lock etc. */
  979. return;
  980. update_selection( console, 0 );
  981. console->window->in_selection = FALSE;
  982. }
  983. /* generate input_record from windows WM_KEYUP/WM_KEYDOWN messages */
  984. static void record_key_input( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
  985. {
  986. static WCHAR last; /* keep last char seen as feed for key up message */
  987. BYTE key_state[256];
  988. INPUT_RECORD ir;
  989. WCHAR buf[2];
  990. ir.EventType = KEY_EVENT;
  991. ir.Event.KeyEvent.bKeyDown = down;
  992. ir.Event.KeyEvent.wRepeatCount = LOWORD(lparam);
  993. ir.Event.KeyEvent.wVirtualKeyCode = wparam;
  994. ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lparam) & 0xFF;
  995. ir.Event.KeyEvent.uChar.UnicodeChar = 0;
  996. ir.Event.KeyEvent.dwControlKeyState = get_ctrl_state( key_state );
  997. if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
  998. if (down)
  999. {
  1000. switch (ToUnicode(wparam, HIWORD(lparam), key_state, buf, 2, 0))
  1001. {
  1002. case 2:
  1003. /* FIXME: should generate two events */
  1004. /* fall through */
  1005. case 1:
  1006. last = buf[0];
  1007. break;
  1008. default:
  1009. last = 0;
  1010. break;
  1011. }
  1012. }
  1013. ir.Event.KeyEvent.uChar.UnicodeChar = last;
  1014. if (!down) last = 0; /* FIXME: buggy HACK */
  1015. write_console_input( console, &ir, 1, TRUE );
  1016. }
  1017. static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
  1018. {
  1019. BYTE key_state[256];
  1020. INPUT_RECORD ir;
  1021. /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
  1022. if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
  1023. ir.EventType = MOUSE_EVENT;
  1024. ir.Event.MouseEvent.dwMousePosition = c;
  1025. ir.Event.MouseEvent.dwButtonState = 0;
  1026. if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
  1027. if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
  1028. if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
  1029. if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
  1030. if (wparam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
  1031. if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
  1032. ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
  1033. ir.Event.MouseEvent.dwEventFlags = event;
  1034. write_console_input( console, &ir, 1, TRUE );
  1035. }
  1036. struct dialog_info
  1037. {
  1038. struct console *console;
  1039. struct console_config config;
  1040. HWND dialog; /* handle to active propsheet */
  1041. };
  1042. /* dialog proc for the option property sheet */
  1043. static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
  1044. {
  1045. struct dialog_info *di;
  1046. unsigned int idc;
  1047. switch (msg)
  1048. {
  1049. case WM_INITDIALOG:
  1050. di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
  1051. di->dialog = dialog;
  1052. SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
  1053. SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
  1054. if (di->config.cursor_size <= 25) idc = IDC_OPT_CURSOR_SMALL;
  1055. else if (di->config.cursor_size <= 50) idc = IDC_OPT_CURSOR_MEDIUM;
  1056. else idc = IDC_OPT_CURSOR_LARGE;
  1057. SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
  1058. SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
  1059. SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
  1060. (di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
  1061. SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
  1062. (di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
  1063. SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
  1064. (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
  1065. SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
  1066. (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
  1067. SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
  1068. (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
  1069. return FALSE; /* because we set the focus */
  1070. case WM_COMMAND:
  1071. break;
  1072. case WM_NOTIFY:
  1073. {
  1074. NMHDR *nmhdr = (NMHDR*)lparam;
  1075. DWORD val;
  1076. BOOL done;
  1077. di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
  1078. switch (nmhdr->code)
  1079. {
  1080. case PSN_SETACTIVE:
  1081. /* needed in propsheet to keep properly the selected radio button
  1082. * otherwise, the focus would be set to the first tab stop in the
  1083. * propsheet, which would always activate the first radio button
  1084. */
  1085. if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
  1086. idc = IDC_OPT_CURSOR_SMALL;
  1087. else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
  1088. idc = IDC_OPT_CURSOR_MEDIUM;
  1089. else
  1090. idc = IDC_OPT_CURSOR_LARGE;
  1091. PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
  1092. di->dialog = dialog;
  1093. break;
  1094. case PSN_APPLY:
  1095. if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
  1096. else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
  1097. else val = 100;
  1098. di->config.cursor_size = val;
  1099. val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
  1100. if (done) di->config.history_size = val;
  1101. val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
  1102. di->config.history_mode = val;
  1103. val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
  1104. di->config.insert_mode = val;
  1105. val = 0;
  1106. if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED) val |= MK_CONTROL;
  1107. if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
  1108. di->config.menu_mask = val;
  1109. val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
  1110. di->config.quick_edit = val;
  1111. SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
  1112. return TRUE;
  1113. default:
  1114. return FALSE;
  1115. }
  1116. break;
  1117. }
  1118. default:
  1119. return FALSE;
  1120. }
  1121. return TRUE;
  1122. }
  1123. static COLORREF get_color( struct dialog_info *di, unsigned int idc )
  1124. {
  1125. LONG_PTR index;
  1126. index = GetWindowLongPtrW(GetDlgItem( di->dialog, idc ), 0);
  1127. return di->config.color_map[index];
  1128. }
  1129. /* window proc for font previewer in font property sheet */
  1130. static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
  1131. {
  1132. switch (msg)
  1133. {
  1134. case WM_CREATE:
  1135. SetWindowLongPtrW( hwnd, 0, 0 );
  1136. break;
  1137. case WM_GETFONT:
  1138. return GetWindowLongPtrW( hwnd, 0 );
  1139. case WM_SETFONT:
  1140. SetWindowLongPtrW( hwnd, 0, wparam );
  1141. if (LOWORD(lparam))
  1142. {
  1143. InvalidateRect( hwnd, NULL, TRUE );
  1144. UpdateWindow( hwnd );
  1145. }
  1146. break;
  1147. case WM_DESTROY:
  1148. {
  1149. HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
  1150. if (font) DeleteObject( font );
  1151. break;
  1152. }
  1153. case WM_PAINT:
  1154. {
  1155. struct dialog_info *di;
  1156. HFONT font, old_font;
  1157. PAINTSTRUCT ps;
  1158. di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
  1159. BeginPaint( hwnd, &ps );
  1160. font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
  1161. if (font)
  1162. {
  1163. static const WCHAR ascii[] = L"ASCII: abcXYZ";
  1164. COLORREF bkcolor;
  1165. WCHAR buf[256];
  1166. int len;
  1167. old_font = SelectObject( ps.hdc, font );
  1168. bkcolor = get_color( di, IDC_FNT_COLOR_BK );
  1169. FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
  1170. SetBkColor( ps.hdc, bkcolor );
  1171. SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
  1172. len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
  1173. if (len) TextOutW( ps.hdc, 0, 0, buf, len );
  1174. TextOutW( ps.hdc, 0, di->config.cell_height, ascii, ARRAY_SIZE(ascii) - 1 );
  1175. SelectObject( ps.hdc, old_font );
  1176. }
  1177. EndPaint( hwnd, &ps );
  1178. break;
  1179. }
  1180. default:
  1181. return DefWindowProcW( hwnd, msg, wparam, lparam );
  1182. }
  1183. return 0;
  1184. }
  1185. /* window proc for color previewer */
  1186. static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
  1187. {
  1188. switch (msg)
  1189. {
  1190. case WM_PAINT:
  1191. {
  1192. struct dialog_info *di;
  1193. PAINTSTRUCT ps;
  1194. RECT client, r;
  1195. int i, step;
  1196. HBRUSH brush;
  1197. BeginPaint( hwnd, &ps );
  1198. GetClientRect( hwnd, &client );
  1199. step = client.right / 8;
  1200. di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
  1201. for (i = 0; i < 16; i++)
  1202. {
  1203. r.top = (i / 8) * (client.bottom / 2);
  1204. r.bottom = r.top + client.bottom / 2;
  1205. r.left = (i & 7) * step;
  1206. r.right = r.left + step;
  1207. brush = CreateSolidBrush( di->config.color_map[i] );
  1208. FillRect( ps.hdc, &r, brush );
  1209. DeleteObject( brush );
  1210. if (GetWindowLongW( hwnd, 0 ) == i)
  1211. {
  1212. HPEN old_pen;
  1213. int i = 2;
  1214. old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
  1215. r.right--; r.bottom--;
  1216. for (;;)
  1217. {
  1218. MoveToEx( ps.hdc, r.left, r.bottom, NULL );
  1219. LineTo( ps.hdc, r.left, r.top );
  1220. LineTo( ps.hdc, r.right, r.top );
  1221. SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
  1222. LineTo( ps.hdc, r.right, r.bottom );
  1223. LineTo( ps.hdc, r.left, r.bottom );
  1224. if (--i == 0) break;
  1225. r.left++; r.top++; r.right--; r.bottom--;
  1226. SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
  1227. }
  1228. SelectObject( ps.hdc, old_pen );
  1229. }
  1230. }
  1231. EndPaint( hwnd, &ps );
  1232. break;
  1233. }
  1234. case WM_LBUTTONDOWN:
  1235. {
  1236. int i, step;
  1237. RECT client;
  1238. GetClientRect( hwnd, &client );
  1239. step = client.right / 8;
  1240. i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
  1241. i += LOWORD(lparam) / step;
  1242. SetWindowLongW( hwnd, 0, i );
  1243. InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
  1244. InvalidateRect( hwnd, NULL, FALSE );
  1245. break;
  1246. }
  1247. default:
  1248. return DefWindowProcW( hwnd, msg, wparam, lparam );
  1249. }
  1250. return 0;
  1251. }
  1252. static BOOL select_font( struct dialog_info *di )
  1253. {
  1254. int font_idx, size_idx;
  1255. WCHAR face_name[LF_FACESIZE], height_buf[4];
  1256. size_t len;
  1257. unsigned int font_height;
  1258. LOGFONTW lf;
  1259. HFONT font, old_font;
  1260. DWORD_PTR args[2];
  1261. WCHAR buf[256];
  1262. WCHAR fmt[128];
  1263. font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
  1264. size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
  1265. if (font_idx < 0 || size_idx < 0)
  1266. return FALSE;
  1267. len = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, font_idx, (LPARAM)&face_name );
  1268. SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETTEXT, size_idx, (LPARAM)&height_buf );
  1269. font_height = _wtoi( height_buf );
  1270. fill_logfont( &lf, face_name, len * sizeof(WCHAR), font_height, FW_NORMAL );
  1271. font = select_font_config( &di->config, di->console->output_cp, di->console->win, &lf );
  1272. if (!font) return FALSE;
  1273. if (di->config.cell_height != font_height)
  1274. TRACE( "mismatched heights (%u<>%u)\n", di->config.cell_height, font_height );
  1275. old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
  1276. SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
  1277. if (old_font) DeleteObject( old_font );
  1278. LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
  1279. args[0] = di->config.cell_width;
  1280. args[1] = di->config.cell_height;
  1281. FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1282. fmt, 0, 0, buf, ARRAY_SIZE(buf), (__ms_va_list*)args );
  1283. SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
  1284. return TRUE;
  1285. }
  1286. static BOOL fill_list_size( struct dialog_info *di, BOOL init )
  1287. {
  1288. if (init)
  1289. {
  1290. static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
  1291. unsigned int i, idx = 4;
  1292. WCHAR buf[4];
  1293. for (i = 0; i < ARRAY_SIZE(sizes); i++)
  1294. {
  1295. wsprintfW( buf, L"%u", sizes[i] );
  1296. SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, -1, (LPARAM)buf );
  1297. if (di->config.cell_height == sizes[i]) idx = i;
  1298. }
  1299. SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
  1300. }
  1301. select_font( di );
  1302. return TRUE;
  1303. }
  1304. static int CALLBACK enum_list_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
  1305. DWORD font_type, LPARAM lparam )
  1306. {
  1307. struct dialog_info *di = (struct dialog_info *)lparam;
  1308. if (font_type != TRUETYPE_FONTTYPE) return 1;
  1309. TRACE( "%s\n", debugstr_logfont( lf, font_type ));
  1310. if (validate_font( di->console, lf, 0 ))
  1311. SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING, 0, (LPARAM)lf->lfFaceName );
  1312. return 1;
  1313. }
  1314. static BOOL fill_list_font( struct dialog_info *di )
  1315. {
  1316. LOGFONTW lf;
  1317. memset( &lf, 0, sizeof(lf) );
  1318. lf.lfCharSet = DEFAULT_CHARSET;
  1319. lf.lfFaceName[0] = 0;
  1320. lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
  1321. EnumFontFamiliesExW( di->console->window->mem_dc, &lf, enum_list_font_proc, (LPARAM)di, 0 );
  1322. if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
  1323. -1, (LPARAM)di->config.face_name ) == LB_ERR)
  1324. SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
  1325. fill_list_size( di, TRUE );
  1326. return TRUE;
  1327. }
  1328. /* dialog proc for the font property sheet */
  1329. static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
  1330. {
  1331. struct dialog_info *di;
  1332. switch (msg)
  1333. {
  1334. case WM_INITDIALOG:
  1335. di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
  1336. di->dialog = dialog;
  1337. SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
  1338. /* use default system font until user-selected font is applied */
  1339. SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
  1340. fill_list_font( di );
  1341. SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
  1342. SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
  1343. break;
  1344. case WM_COMMAND:
  1345. di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
  1346. switch (LOWORD(wparam))
  1347. {
  1348. case IDC_FNT_LIST_FONT:
  1349. if (HIWORD(wparam) == LBN_SELCHANGE)
  1350. fill_list_size( di, FALSE );
  1351. break;
  1352. case IDC_FNT_LIST_SIZE:
  1353. if (HIWORD(wparam) == LBN_SELCHANGE)
  1354. select_font( di );
  1355. break;
  1356. }
  1357. break;
  1358. case WM_NOTIFY:
  1359. {
  1360. NMHDR *nmhdr = (NMHDR*)lparam;
  1361. DWORD val;
  1362. di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
  1363. switch (nmhdr->code)
  1364. {
  1365. case PSN_SETACTIVE:
  1366. di->dialog = dialog;
  1367. break;
  1368. case PSN_APPLY:
  1369. val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
  1370. GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
  1371. di->config.attr = val;
  1372. SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
  1373. return TRUE;
  1374. default:
  1375. return FALSE;
  1376. }
  1377. break;
  1378. }
  1379. default:
  1380. return FALSE;
  1381. }
  1382. return TRUE;
  1383. }
  1384. /* dialog proc for the config property sheet */
  1385. static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
  1386. {
  1387. struct dialog_info *di;
  1388. int max_ud = 2000;
  1389. switch (msg)
  1390. {
  1391. case WM_INITDIALOG:
  1392. di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
  1393. di->dialog = dialog;
  1394. SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
  1395. SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, di->config.sb_width, FALSE );
  1396. SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, di->config.sb_height, FALSE );
  1397. SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, di->config.win_width, FALSE );
  1398. SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
  1399. SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
  1400. SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
  1401. SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
  1402. SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
  1403. SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, BST_CHECKED, 0 );
  1404. SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
  1405. SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
  1406. SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
  1407. break;
  1408. case WM_NOTIFY:
  1409. {
  1410. NMHDR *nmhdr = (NMHDR*)lparam;
  1411. int win_w, win_h, sb_w, sb_h;
  1412. BOOL st1, st2;
  1413. di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
  1414. switch (nmhdr->code)
  1415. {
  1416. case PSN_SETACTIVE:
  1417. di->dialog = dialog;
  1418. break;
  1419. case PSN_APPLY:
  1420. sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, &st1, FALSE );
  1421. sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
  1422. if (!st1 || ! st2)
  1423. {
  1424. SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
  1425. return TRUE;
  1426. }
  1427. win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, &st1, FALSE );
  1428. win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
  1429. if (!st1 || !st2)
  1430. {
  1431. SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
  1432. return TRUE;
  1433. }
  1434. if (win_w > sb_w || win_h > sb_h)
  1435. {
  1436. WCHAR cap[256];
  1437. WCHAR txt[256];
  1438. LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
  1439. LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
  1440. MessageBoxW( dialog, txt, cap, MB_OK );
  1441. SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
  1442. return TRUE;
  1443. }
  1444. di->config.win_width = win_w;
  1445. di->config.win_height = win_h;
  1446. di->config.sb_width = sb_w;
  1447. di->config.sb_height = sb_h;
  1448. di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
  1449. CB_GETCURSEL, 0, 0 );
  1450. SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
  1451. return TRUE;
  1452. default:
  1453. return FALSE;
  1454. }
  1455. break;
  1456. }
  1457. default:
  1458. return FALSE;
  1459. }
  1460. return TRUE;
  1461. }
  1462. /* dialog proc for choosing how to handle modification to the console settings */
  1463. static INT_PTR WINAPI save_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
  1464. {
  1465. switch (msg)
  1466. {
  1467. case WM_INITDIALOG:
  1468. SendMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, IDC_SAV_SESSION ), TRUE );
  1469. SendDlgItemMessageW( dialog, IDC_SAV_SESSION, BM_SETCHECK, BST_CHECKED, 0 );
  1470. return FALSE;
  1471. case WM_COMMAND:
  1472. switch (LOWORD(wparam))
  1473. {
  1474. case IDOK:
  1475. EndDialog( dialog,
  1476. (IsDlgButtonChecked(dialog, IDC_SAV_SAVE) == BST_CHECKED) ?
  1477. IDC_SAV_SAVE : IDC_SAV_SESSION );
  1478. break;
  1479. case IDCANCEL:
  1480. EndDialog( dialog, IDCANCEL ); break;
  1481. }
  1482. break;
  1483. default:
  1484. return FALSE;
  1485. }
  1486. return TRUE;
  1487. }
  1488. static void apply_config( struct console *console, const struct console_config *config )
  1489. {
  1490. if (console->active->width != config->sb_width || console->active->height != config->sb_height)
  1491. change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
  1492. console->window->menu_mask = config->menu_mask;
  1493. console->window->quick_edit = config->quick_edit;
  1494. console->edition_mode = config->edition_mode;
  1495. console->history_mode = config->history_mode;
  1496. if (console->history_size != config->history_size)
  1497. {
  1498. struct history_line **mem = NULL;
  1499. int i, delta;
  1500. if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
  1501. {
  1502. memset( mem, 0, config->history_size * sizeof(*mem) );
  1503. delta = (console->history_index > config->history_size)
  1504. ? (console->history_index - config->history_size) : 0;
  1505. for (i = delta; i < console->history_index; i++)
  1506. {
  1507. mem[i - delta] = console->history[i];
  1508. console->history[i] = NULL;
  1509. }
  1510. console->history_index -= delta;
  1511. for (i = 0; i < console->history_size; i++)
  1512. free( console->history[i] );
  1513. free( console->history );
  1514. console->history = mem;
  1515. console->history_size = config->history_size;
  1516. }
  1517. }
  1518. if (config->insert_mode)
  1519. console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
  1520. else
  1521. console->mode &= ~ENABLE_INSERT_MODE;
  1522. console->active->cursor_size = config->cursor_size;
  1523. console->active->cursor_visible = config->cursor_visible;
  1524. console->active->attr = config->attr;
  1525. console->active->popup_attr = config->popup_attr;
  1526. console->active->win.left = config->win_pos.X;
  1527. console->active->win.top = config->win_pos.Y;
  1528. console->active->win.right = config->win_pos.X + config->win_width - 1;
  1529. console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
  1530. memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
  1531. if (console->active->font.width != config->cell_width ||
  1532. console->active->font.height != config->cell_height ||
  1533. console->active->font.weight != config->font_weight ||
  1534. console->active->font.pitch_family != config->font_pitch_family ||
  1535. console->active->font.face_len != wcslen( config->face_name ) ||
  1536. memcmp( console->active->font.face_name, config->face_name,
  1537. console->active->font.face_len * sizeof(WCHAR) ))
  1538. {
  1539. update_console_font( console, config->face_name, wcslen(config->face_name) * sizeof(WCHAR),
  1540. config->cell_height, config->font_weight );
  1541. }
  1542. update_window( console );
  1543. notify_screen_buffer_size( console->active );
  1544. }
  1545. static void current_config( struct console *console, struct console_config *config )
  1546. {
  1547. size_t len;
  1548. config->menu_mask = console->window->menu_mask;
  1549. config->quick_edit = console->window->quick_edit;
  1550. config->edition_mode = console->edition_mode;
  1551. config->history_mode = console->history_mode;
  1552. config->history_size = console->history_size;
  1553. config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
  1554. (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
  1555. config->cursor_size = console->active->cursor_size;
  1556. config->cursor_visible = console->active->cursor_visible;
  1557. config->attr = console->active->attr;
  1558. config->popup_attr = console->active->popup_attr;
  1559. memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
  1560. config->cell_width = console->active->font.width;
  1561. config->cell_height = console->active->font.height;
  1562. config->font_weight = console->active->font.weight;
  1563. config->font_pitch_family = console->active->font.pitch_family;
  1564. len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len );
  1565. if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
  1566. config->face_name[len] = 0;
  1567. config->sb_width = console->active->width;
  1568. config->sb_height = console->active->height;
  1569. config->win_width = console->active->win.right - console->active->win.left + 1;
  1570. config->win_height = console->active->win.bottom - console->active->win.top + 1;
  1571. config->win_pos.X = console->active->win.left;
  1572. config->win_pos.Y = console->active->win.top;
  1573. }
  1574. /* run the dialog box to set up the console options */
  1575. static BOOL config_dialog( struct console *console, BOOL current )
  1576. {
  1577. struct console_config prev_config;
  1578. struct dialog_info di;
  1579. PROPSHEETHEADERW header;
  1580. HPROPSHEETPAGE pages[3];
  1581. PROPSHEETPAGEW psp;
  1582. WNDCLASSW wndclass;
  1583. WCHAR buff[256];
  1584. BOOL modify_session = FALSE;
  1585. BOOL save = FALSE;
  1586. InitCommonControls();
  1587. memset( &di, 0, sizeof(di) );
  1588. di.console = console;
  1589. if (!current)
  1590. {
  1591. load_config( NULL, &di.config );
  1592. save = TRUE;
  1593. }
  1594. else current_config( console, &di.config );
  1595. prev_config = di.config;
  1596. wndclass.style = 0;
  1597. wndclass.lpfnWndProc = font_preview_proc;
  1598. wndclass.cbClsExtra = 0;
  1599. wndclass.cbWndExtra = sizeof(HFONT);
  1600. wndclass.hInstance = GetModuleHandleW( NULL );
  1601. wndclass.hIcon = 0;
  1602. wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
  1603. wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
  1604. wndclass.lpszMenuName = NULL;
  1605. wndclass.lpszClassName = L"WineConFontPreview";
  1606. RegisterClassW( &wndclass );
  1607. wndclass.style = 0;
  1608. wndclass.lpfnWndProc = color_preview_proc;
  1609. wndclass.cbClsExtra = 0;
  1610. wndclass.cbWndExtra = sizeof(DWORD);
  1611. wndclass.hInstance = GetModuleHandleW( NULL );
  1612. wndclass.hIcon = 0;
  1613. wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
  1614. wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
  1615. wndclass.lpszMenuName = NULL;
  1616. wndclass.lpszClassName = L"WineConColorPreview";
  1617. RegisterClassW( &wndclass );
  1618. memset( &psp, 0, sizeof(psp) );
  1619. psp.dwSize = sizeof(psp);
  1620. psp.dwFlags = 0;
  1621. psp.hInstance = wndclass.hInstance;
  1622. psp.lParam = (LPARAM)&di;
  1623. psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
  1624. psp.pfnDlgProc = option_dialog_proc;
  1625. pages[0] = CreatePropertySheetPageW( &psp );
  1626. psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
  1627. psp.pfnDlgProc = font_dialog_proc;
  1628. pages[1] = CreatePropertySheetPageW( &psp );
  1629. psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
  1630. psp.pfnDlgProc = config_dialog_proc;
  1631. pages[2] = CreatePropertySheetPageW( &psp );
  1632. memset( &header, 0, sizeof(header) );
  1633. header.dwSize = sizeof(header);
  1634. if (!LoadStringW( GetModuleHandleW( NULL ),
  1635. current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
  1636. buff, ARRAY_SIZE(buff) ))
  1637. wcscpy( buff, L"Setup" );
  1638. header.pszCaption = buff;
  1639. header.nPages = 3;
  1640. header.hwndParent = console->win;
  1641. header.u3.phpage = pages;
  1642. header.dwFlags = PSH_NOAPPLYNOW;
  1643. if (PropertySheetW( &header ) < 1)
  1644. return TRUE;
  1645. if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
  1646. return TRUE;
  1647. TRACE( "%s\n", debugstr_config(&di.config) );
  1648. if (!save)
  1649. {
  1650. switch (DialogBoxW( GetModuleHandleW( NULL ), MAKEINTRESOURCEW(IDD_SAVE_SETTINGS),
  1651. console->win, save_dialog_proc ))
  1652. {
  1653. case IDC_SAV_SAVE:
  1654. save = TRUE;
  1655. modify_session = TRUE;
  1656. break;
  1657. case IDC_SAV_SESSION:
  1658. modify_session = TRUE;
  1659. break;
  1660. default:
  1661. ERR( "dialog failed\n" );
  1662. /* fall through */
  1663. case IDCANCEL:
  1664. modify_session = FALSE;
  1665. save = FALSE;
  1666. break;
  1667. }
  1668. }
  1669. if (modify_session)
  1670. {
  1671. apply_config( console, &di.config );
  1672. update_window( di.console );
  1673. }
  1674. if (save)
  1675. save_config( current ? console->window->config_key : NULL, &di.config );
  1676. return TRUE;
  1677. }
  1678. static void resize_window( struct console *console, int width, int height )
  1679. {
  1680. struct console_config config;
  1681. current_config( console, &config );
  1682. config.win_width = width;
  1683. config.win_height = height;
  1684. /* auto size screen-buffer if it's now smaller than window */
  1685. if (config.sb_width < config.win_width)
  1686. config.sb_width = config.win_width;
  1687. if (config.sb_height < config.win_height)
  1688. config.sb_height = config.win_height;
  1689. /* and reset window pos so that we don't display outside of the screen-buffer */
  1690. if (config.win_pos.X + config.win_width > config.sb_width)
  1691. config.win_pos.X = config.sb_width - config.win_width;
  1692. if (config.win_pos.Y + config.win_height > config.sb_height)
  1693. config.win_pos.Y = config.sb_height - config.win_height;
  1694. apply_config( console, &config );
  1695. }
  1696. /* grays / ungrays the menu items according to their state */
  1697. static void set_menu_details( struct console *console, HMENU menu )
  1698. {
  1699. EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
  1700. (console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
  1701. EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
  1702. (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
  1703. EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
  1704. EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
  1705. }
  1706. static BOOL fill_menu( HMENU menu, BOOL sep )
  1707. {
  1708. HINSTANCE module = GetModuleHandleW( NULL );
  1709. HMENU sub_menu;
  1710. WCHAR buff[256];
  1711. if (!menu) return FALSE;
  1712. sub_menu = CreateMenu();
  1713. if (!sub_menu) return FALSE;
  1714. LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
  1715. InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
  1716. LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
  1717. InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
  1718. LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
  1719. InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
  1720. LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
  1721. InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
  1722. LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
  1723. InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
  1724. LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
  1725. InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
  1726. if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
  1727. LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
  1728. InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
  1729. LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
  1730. InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
  1731. LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
  1732. InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
  1733. return TRUE;
  1734. }
  1735. static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
  1736. {
  1737. struct console *console = create->lpCreateParams;
  1738. HMENU sys_menu;
  1739. TRACE( "%p\n", hwnd );
  1740. SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
  1741. console->win = hwnd;
  1742. if (console->window)
  1743. {
  1744. sys_menu = GetSystemMenu( hwnd, FALSE );
  1745. if (!sys_menu) return 0;
  1746. console->window->popup_menu = CreatePopupMenu();
  1747. if (!console->window->popup_menu) return 0;
  1748. fill_menu( sys_menu, TRUE );
  1749. fill_menu( console->window->popup_menu, FALSE );
  1750. console->window->mem_dc = CreateCompatibleDC( 0 );
  1751. }
  1752. return 0;
  1753. }
  1754. static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
  1755. {
  1756. struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
  1757. switch (msg)
  1758. {
  1759. case WM_CREATE:
  1760. return window_create( hwnd, (const CREATESTRUCTW *)lparam );
  1761. case WM_DESTROY:
  1762. console->win = NULL;
  1763. PostQuitMessage( 0 );
  1764. break;
  1765. case WM_TIMER:
  1766. case WM_UPDATE_CONFIG:
  1767. if (console->window && console->window->update_state == UPDATE_PENDING)
  1768. update_window( console );
  1769. break;
  1770. case WM_PAINT:
  1771. {
  1772. PAINTSTRUCT ps;
  1773. if (!console->window) break;
  1774. BeginPaint( console->win, &ps );
  1775. BitBlt( ps.hdc, 0, 0,
  1776. (console->active->win.right - console->active->win.left + 1) * console->active->font.width,
  1777. (console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
  1778. console->window->mem_dc,
  1779. console->active->win.left * console->active->font.width,
  1780. console->active->win.top * console->active->font.height,
  1781. SRCCOPY );
  1782. if (console->window->in_selection) update_selection( console, ps.hdc );
  1783. EndPaint( console->win, &ps );
  1784. break;
  1785. }
  1786. case WM_SHOWWINDOW:
  1787. if (!console->window) break;
  1788. if (wparam)
  1789. update_window( console );
  1790. else
  1791. {
  1792. if (console->window->bitmap) DeleteObject( console->window->bitmap );
  1793. console->window->bitmap = NULL;
  1794. }
  1795. break;
  1796. case WM_KEYDOWN:
  1797. case WM_KEYUP:
  1798. if (console->window && console->window->in_selection)
  1799. handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
  1800. else
  1801. record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
  1802. break;
  1803. case WM_SYSKEYDOWN:
  1804. case WM_SYSKEYUP:
  1805. record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
  1806. break;
  1807. case WM_LBUTTONDOWN:
  1808. if (console->window && (console->window->quick_edit || console->window->in_selection))
  1809. {
  1810. if (console->window->in_selection)
  1811. update_selection( console, 0 );
  1812. if (console->window->quick_edit && console->window->in_selection)
  1813. {
  1814. console->window->in_selection = FALSE;
  1815. }
  1816. else
  1817. {
  1818. console->window->selection_end = get_cell( console, lparam );
  1819. console->window->selection_start = console->window->selection_end;
  1820. SetCapture( console->win );
  1821. update_selection( console, 0 );
  1822. console->window->in_selection = TRUE;
  1823. }
  1824. }
  1825. else
  1826. {
  1827. record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
  1828. }
  1829. break;
  1830. case WM_MOUSEMOVE:
  1831. if (console->window && (console->window->quick_edit || console->window->in_selection))
  1832. {
  1833. if (GetCapture() == console->win && console->window->in_selection &&
  1834. (wparam & MK_LBUTTON))
  1835. {
  1836. move_selection( console, console->window->selection_start,
  1837. get_cell(console, lparam) );
  1838. }
  1839. }
  1840. else
  1841. {
  1842. record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
  1843. }
  1844. break;
  1845. case WM_LBUTTONUP:
  1846. if (console->window && (console->window->quick_edit || console->window->in_selection))
  1847. {
  1848. if (GetCapture() == console->win && console->window->in_selection)
  1849. {
  1850. move_selection( console, console->window->selection_start,
  1851. get_cell(console, lparam) );
  1852. ReleaseCapture();
  1853. }
  1854. }
  1855. else
  1856. {
  1857. record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
  1858. }
  1859. break;
  1860. case WM_RBUTTONDOWN:
  1861. if (console->window && (wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
  1862. {
  1863. POINT pt;
  1864. pt.x = (short)LOWORD(lparam);
  1865. pt.y = (short)HIWORD(lparam);
  1866. ClientToScreen( hwnd, &pt );
  1867. set_menu_details( console, console->window->popup_menu );
  1868. TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
  1869. pt.x, pt.y, 0, hwnd, NULL );
  1870. }
  1871. else
  1872. {
  1873. record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
  1874. }
  1875. break;
  1876. case WM_RBUTTONUP:
  1877. /* no need to track for rbutton up when opening the popup... the event will be
  1878. * swallowed by TrackPopupMenu */
  1879. case WM_MBUTTONDOWN:
  1880. case WM_MBUTTONUP:
  1881. record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
  1882. break;
  1883. case WM_LBUTTONDBLCLK:
  1884. case WM_MBUTTONDBLCLK:
  1885. case WM_RBUTTONDBLCLK:
  1886. record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
  1887. break;
  1888. case WM_SETFOCUS:
  1889. if (console->window && console->active->cursor_visible)
  1890. {
  1891. CreateCaret( console->win, console->window->cursor_bitmap,
  1892. console->active->font.width, console->active->font.height );
  1893. update_window_cursor( console );
  1894. }
  1895. break;
  1896. case WM_KILLFOCUS:
  1897. if (console->window && console->active->cursor_visible)
  1898. DestroyCaret();
  1899. break;
  1900. case WM_SIZE:
  1901. if (console->window && console->window->update_state != UPDATE_BUSY)
  1902. resize_window( console,
  1903. max( LOWORD(lparam) / console->active->font.width, 20 ),
  1904. max( HIWORD(lparam) / console->active->font.height, 20 ));
  1905. break;
  1906. case WM_HSCROLL:
  1907. {
  1908. int win_width = console->active->win.right - console->active->win.left + 1;
  1909. int x = console->active->win.left;
  1910. if (!console->window) break;
  1911. switch (LOWORD(wparam))
  1912. {
  1913. case SB_PAGEUP: x -= 8; break;
  1914. case SB_PAGEDOWN: x += 8; break;
  1915. case SB_LINEUP: x--; break;
  1916. case SB_LINEDOWN: x++; break;
  1917. case SB_THUMBTRACK: x = HIWORD(wparam); break;
  1918. default: break;
  1919. }
  1920. x = min( max( x, 0 ), console->active->width - win_width );
  1921. if (x != console->active->win.left)
  1922. {
  1923. console->active->win.left = x;
  1924. console->active->win.right = x + win_width - 1;
  1925. update_window( console );
  1926. }
  1927. break;
  1928. }
  1929. case WM_MOUSEWHEEL:
  1930. if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
  1931. {
  1932. record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
  1933. break;
  1934. }
  1935. /* else fallthrough */
  1936. case WM_VSCROLL:
  1937. {
  1938. int win_height = console->active->win.bottom - console->active->win.top + 1;
  1939. int y = console->active->win.top;
  1940. if (!console->window) break;
  1941. if (msg == WM_MOUSEWHEEL)
  1942. {
  1943. UINT scroll_lines = 3;
  1944. SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
  1945. scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
  1946. y += scroll_lines;
  1947. }
  1948. else
  1949. {
  1950. switch (LOWORD(wparam))
  1951. {
  1952. case SB_PAGEUP: y -= 8; break;
  1953. case SB_PAGEDOWN: y += 8; break;
  1954. case SB_LINEUP: y--; break;
  1955. case SB_LINEDOWN: y++; break;
  1956. case SB_THUMBTRACK: y = HIWORD(wparam); break;
  1957. default: break;
  1958. }
  1959. }
  1960. y = min( max( y, 0 ), console->active->height - win_height );
  1961. if (y != console->active->win.top)
  1962. {
  1963. console->active->win.top = y;
  1964. console->active->win.bottom = y + win_height - 1;
  1965. update_window( console );
  1966. }
  1967. break;
  1968. }
  1969. case WM_SYSCOMMAND:
  1970. if (!console->window) break;
  1971. switch (wparam)
  1972. {
  1973. case IDS_DEFAULT:
  1974. config_dialog( console, FALSE );
  1975. break;
  1976. case IDS_PROPERTIES:
  1977. config_dialog( console, TRUE );
  1978. break;
  1979. default:
  1980. return DefWindowProcW( hwnd, msg, wparam, lparam );
  1981. }
  1982. break;
  1983. case WM_COMMAND:
  1984. if (!console->window) break;
  1985. switch (wparam)
  1986. {
  1987. case IDS_DEFAULT:
  1988. config_dialog( console, FALSE );
  1989. break;
  1990. case IDS_PROPERTIES:
  1991. config_dialog( console, TRUE );
  1992. break;
  1993. case IDS_MARK:
  1994. console->window->selection_start.X = console->window->selection_start.Y = 0;
  1995. console->window->selection_end.X = console->window->selection_end.Y = 0;
  1996. update_selection( console, 0 );
  1997. console->window->in_selection = TRUE;
  1998. break;
  1999. case IDS_COPY:
  2000. if (console->window->in_selection)
  2001. {
  2002. console->window->in_selection = FALSE;
  2003. update_selection( console, 0 );
  2004. copy_selection( console );
  2005. }
  2006. break;
  2007. case IDS_PASTE:
  2008. paste_clipboard( console );
  2009. break;
  2010. case IDS_SELECTALL:
  2011. console->window->selection_start.X = console->window->selection_start.Y = 0;
  2012. console->window->selection_end.X = console->active->width - 1;
  2013. console->window->selection_end.Y = console->active->height - 1;
  2014. update_selection( console, 0 );
  2015. console->window->in_selection = TRUE;
  2016. break;
  2017. case IDS_SCROLL:
  2018. case IDS_SEARCH:
  2019. FIXME( "Unhandled yet command: %Ix\n", wparam );
  2020. break;
  2021. default:
  2022. return DefWindowProcW( hwnd, msg, wparam, lparam );
  2023. }
  2024. break;
  2025. case WM_INITMENUPOPUP:
  2026. if (!console->window || !HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
  2027. set_menu_details( console, GetSystemMenu(console->win, FALSE) );
  2028. break;
  2029. default:
  2030. return DefWindowProcW( hwnd, msg, wparam, lparam );
  2031. }
  2032. return 0;
  2033. }
  2034. void update_window_config( struct console *console, BOOL delay )
  2035. {
  2036. const int delay_timeout = 50;
  2037. if (!console->window || console->window->update_state != UPDATE_NONE) return;
  2038. console->window->update_state = UPDATE_PENDING;
  2039. if (delay)
  2040. SetTimer( console->win, 1, delay_timeout, NULL );
  2041. else
  2042. PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
  2043. }
  2044. void update_window_region( struct console *console, const RECT *update )
  2045. {
  2046. RECT *window_rect = &console->window->update;
  2047. window_rect->left = min( window_rect->left, update->left );
  2048. window_rect->top = min( window_rect->top, update->top );
  2049. window_rect->right = max( window_rect->right, update->right );
  2050. window_rect->bottom = max( window_rect->bottom, update->bottom );
  2051. update_window_config( console, TRUE );
  2052. }
  2053. BOOL init_window( struct console *console )
  2054. {
  2055. struct console_config config;
  2056. WNDCLASSW wndclass;
  2057. STARTUPINFOW si;
  2058. CHARSETINFO ci;
  2059. static struct console_window console_window;
  2060. console->window = &console_window;
  2061. if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
  2062. return FALSE;
  2063. console->window->ui_charset = ci.ciCharset;
  2064. GetStartupInfoW(&si);
  2065. if (si.lpTitle)
  2066. {
  2067. size_t i, title_len = wcslen( si.lpTitle );
  2068. if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
  2069. return FALSE;
  2070. for (i = 0; i < title_len; i++)
  2071. console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
  2072. console->window->config_key[title_len] = 0;
  2073. }
  2074. load_config( console->window->config_key, &config );
  2075. if (si.dwFlags & STARTF_USECOUNTCHARS)
  2076. {
  2077. config.sb_width = si.dwXCountChars;
  2078. config.sb_height = si.dwYCountChars;
  2079. }
  2080. if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
  2081. config.attr = si.dwFillAttribute;
  2082. wndclass.style = CS_DBLCLKS;
  2083. wndclass.lpfnWndProc = window_proc;
  2084. wndclass.cbClsExtra = 0;
  2085. wndclass.cbWndExtra = sizeof(DWORD_PTR);
  2086. wndclass.hInstance = GetModuleHandleW(NULL);
  2087. wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
  2088. wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
  2089. wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
  2090. wndclass.lpszMenuName = NULL;
  2091. wndclass.lpszClassName = L"WineConsoleClass";
  2092. RegisterClassW(&wndclass);
  2093. if (!CreateWindowW( wndclass.lpszClassName, NULL,
  2094. WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
  2095. WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
  2096. 0, 0, 0, 0, wndclass.hInstance, console ))
  2097. return FALSE;
  2098. apply_config( console, &config );
  2099. return TRUE;
  2100. }
  2101. void init_message_window( struct console *console )
  2102. {
  2103. WNDCLASSW wndclass;
  2104. wndclass.style = CS_DBLCLKS;
  2105. wndclass.lpfnWndProc = window_proc;
  2106. wndclass.cbClsExtra = 0;
  2107. wndclass.cbWndExtra = sizeof(DWORD_PTR);
  2108. wndclass.hInstance = GetModuleHandleW( NULL );
  2109. wndclass.hIcon = 0;
  2110. wndclass.hCursor = 0;
  2111. wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
  2112. wndclass.lpszMenuName = NULL;
  2113. wndclass.lpszClassName = L"WineConsoleClass";
  2114. RegisterClassW(&wndclass);
  2115. CreateWindowW( wndclass.lpszClassName, NULL,
  2116. WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
  2117. WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
  2118. 0, 0, HWND_MESSAGE, 0, wndclass.hInstance, console );
  2119. }