From 6fa476d605a3c2ae1c66f04fd683fa0aa5577715 Mon Sep 17 00:00:00 2001 From: Hugh McMaster Date: Tue, 21 May 2013 12:14:14 +1000 Subject: wineconsole.c --- programs/wineconsole/wineconsole.c | 254 +++++++++++++++++++++--------------- 1 file changed, 149 insertions(+), 105 deletions(-) diff --git a/programs/wineconsole/wineconsole.c b/programs/wineconsole/wineconsole.c index d298705..5a354de 100644 --- a/programs/wineconsole/wineconsole.c +++ b/programs/wineconsole/wineconsole.c @@ -82,6 +82,55 @@ static void WINECON_FetchCells(struct inner_data* data, int upd_tp, int upd_bm) } /****************************************************************** + * WINECON_GetMaxWindowSize + * + * + */ +COORD WINECON_GetMaxWindowSize(enum init_return (*backend)(struct inner_data *data), + int font_width, int font_height) +{ + RECT workarea; + FILE *fp; + char buffer[32]; + int i = 0, arr[2]; + COORD c; + + if (backend == WCUSER_InitBackend) /* --backend=user or --backend not specified */ + { + SystemParametersInfoW(SPI_GETWORKAREA, 0, &workarea, 0); + + c.X = (workarea.right / font_width) - 6; + c.Y = (workarea.bottom / font_height) - 5; + } + else /* --backend=curses */ + { + fp = popen("tput cols; tput lines", "r"); + + if (fp != NULL) + { + while (fgets(buffer, sizeof(buffer), fp) != NULL) + { + arr[i] = atoi(buffer); + i++; + } + pclose(fp); + } + + c.X = arr[0]; + c.Y = arr[1]; + } + + /* check if default window size should be used */ + if (c.X <= 0 || c.Y <= 0) + { + c.X = 80; + c.Y = 25; + } + + return c; +} + +/****************************************************************** * WINECON_ResizeWithContainer * * For console embedded in a container (e.g. user in a win32 window, or (n)curses @@ -90,21 +139,11 @@ static void WINECON_FetchCells(struct inner_data* data, int upd_tp, int upd_bm) */ void WINECON_ResizeWithContainer(struct inner_data* data, int width, int height) { - struct config_data cfg; + struct config_data cfg; if (data->in_set_config) return; cfg = data->curcfg; - cfg.win_width = width; - cfg.win_height = height; - - /* auto size screen-buffer if it's now smaller than window */ - if (cfg.sb_width < cfg.win_width) cfg.sb_width = cfg.win_width; - if (cfg.sb_height < cfg.win_height) cfg.sb_height = cfg.win_height; - - /* and reset window pos so that we don't display outside of the screen-buffer */ - if (cfg.win_pos.X + cfg.win_width > cfg.sb_width) cfg.win_pos.X = cfg.sb_width - cfg.win_width; - if (cfg.win_pos.Y + cfg.win_height > cfg.sb_height) cfg.win_pos.Y = cfg.sb_height - cfg.win_height; WINECON_SetConfig(data, &cfg); } @@ -199,7 +238,7 @@ static BOOL WINECON_SetEditionMode(HANDLE hConIn, int edition_mode) * * A change occurs, try to figure out which */ -void WINECON_GrabChanges(struct inner_data* data) +void WINECON_GrabChanges(struct inner_data* data) { struct console_renderer_event evts[256]; int i, num, ev_found; @@ -247,13 +286,13 @@ void WINECON_GrabChanges(struct inner_data* data) } if (ev_found != -1 && /* Only 2 cases where they CANNOT merge */ - !(evts[i ].u.update.bottom + 1 < evts[ev_found].u.update.top || - evts[ev_found].u.update.bottom + 1 < evts[i ].u.update.top)) + !(evts[i].u.update.bottom + 1 < evts[ev_found].u.update.top || + evts[ev_found].u.update.bottom + 1 < evts[i].u.update.top)) { WINE_TRACE("%u/%u: update(%d,%d) merging with %u\n", ev_found+1, num, evts[i].u.update.top, evts[i].u.update.bottom, i+1); - evts[i].u.update.top = min(evts[i ].u.update.top, + evts[i].u.update.top = min(evts[i].u.update.top, evts[ev_found].u.update.top); - evts[i].u.update.bottom = max(evts[i ].u.update.bottom, + evts[i].u.update.bottom = max(evts[i].u.update.bottom, evts[ev_found].u.update.bottom); evts[ev_found].event = CONSOLE_RENDERER_NONE_EVENT; } @@ -294,6 +333,7 @@ void WINECON_GrabChanges(struct inner_data* data) data->curcfg.sb_height != evts[i].u.resize.height) { WINE_TRACE("%u/%u: resize(%d,%d)\n", i+1, num, evts[i].u.resize.width, evts[i].u.resize.height); + data->curcfg.sb_width = evts[i].u.resize.width; data->curcfg.sb_height = evts[i].u.resize.height; @@ -368,8 +408,11 @@ void WINECON_GrabChanges(struct inner_data* data) * of server side equivalent and visual parts. * If force is FALSE, only the changed items are modified. */ -void WINECON_SetConfig(struct inner_data* data, const struct config_data* cfg) +void WINECON_SetConfig(struct inner_data* data, const struct config_data* cfg) { + COORD max_console, sb; + SMALL_RECT pos; + if (data->in_set_config) return; data->in_set_config = TRUE; if (data->curcfg.cursor_size != cfg->cursor_size || @@ -399,109 +442,95 @@ void WINECON_SetConfig(struct inner_data* data, const struct config_data* cf } data->curcfg.menu_mask = cfg->menu_mask; data->curcfg.quick_edit = cfg->quick_edit; - if (1 /* FIXME: font info has changed */) - { - data->fnSetFont(data, cfg->face_name, cfg->cell_height, cfg->font_weight); - } + if (data->curcfg.def_attr != cfg->def_attr) { data->curcfg.def_attr = cfg->def_attr; SetConsoleTextAttribute(data->hConOut, cfg->def_attr); } - /* now let's look at the window / sb size changes... - * since the server checks that sb is always bigger than window, - * we have to take care of doing the operations in the right order - */ - /* a set of macros to make things easier to read - * The Test macros test if the (width/height) needs to be changed - * for (window / ScreenBuffer) - * The Change actually modify the dimension of . - */ -#define TstSBfWidth() (data->curcfg.sb_width != cfg->sb_width) -#define TstWinHPos() (data->curcfg.win_width != cfg->win_width || data->curcfg.win_pos.X != cfg->win_pos.X) - -#define ChgSBfWidth() do {c.X = cfg->sb_width; \ - c.Y = data->curcfg.sb_height;\ - SetConsoleScreenBufferSize(data->hConOut, c);\ - } while (0) -#define ChgWinHPos() do {pos.Left = cfg->win_pos.X - data->curcfg.win_pos.X; \ - pos.Top = 0; \ - pos.Right = pos.Left + cfg->win_width - data->curcfg.win_width; \ - pos.Bottom = 0; \ - SetConsoleWindowInfo(data->hConOut, FALSE, &pos);\ - } while (0) -#define TstSBfHeight() (data->curcfg.sb_height != cfg->sb_height) -#define TstWinVPos() (data->curcfg.win_height != cfg->win_height || data->curcfg.win_pos.Y != cfg->win_pos.Y) - -/* since we're going to apply height after width is done, we use width as defined - * in cfg, and not in data->curcfg because if won't be updated yet */ -#define ChgSBfHeight() do {c.X = cfg->sb_width; c.Y = cfg->sb_height; \ - SetConsoleScreenBufferSize(data->hConOut, c); \ - } while (0) -#define ChgWinVPos() do {pos.Left = 0; \ - pos.Top = cfg->win_pos.Y - data->curcfg.win_pos.Y; \ - pos.Right = 0; \ - pos.Bottom = pos.Top + cfg->win_height - data->curcfg.win_height; \ - SetConsoleWindowInfo(data->hConOut, FALSE, &pos);\ - } while (0) - - do + + #define ChgSBfWidth() do {sb.X = cfg->sb_width; sb.Y = data->curcfg.sb_height;\ + SetConsoleScreenBufferSize(data->hConOut, sb);\ + } while (0) + #define ChgWinWidth() do {pos.Left = cfg->win_pos.X - data->curcfg.win_pos.X;\ + pos.Top = 0;\ + if (cfg->sb_width > max_console.X)\ + { pos.Right = pos.Left + max_console.X - data->curcfg.win_width; }\ + else { pos.Right = pos.Left + cfg->win_width - data->curcfg.win_width; }\ + pos.Bottom = 0;\ + SetConsoleWindowInfo(data->hConOut, FALSE, &pos);\ + } while (0) + #define ChgSBfHeight() do {sb.X = cfg->sb_width; sb.Y = cfg->sb_height;\ + SetConsoleScreenBufferSize(data->hConOut, sb);\ + } while (0) + #define ChgWinHeight() do {pos.Left = 0;\ + pos.Top = cfg->win_pos.Y - data->curcfg.win_pos.Y;\ + pos.Right = 0;\ + if (cfg->sb_height > max_console.Y)\ + { pos.Bottom = pos.Top + max_console.Y - data->curcfg.win_height; }\ + else { pos.Bottom = pos.Top + cfg->win_height - data->curcfg.win_height; }\ + SetConsoleWindowInfo(data->hConOut, FALSE, &pos);\ + } while (0) + + /* set minimum screen buffer */ + if (cfg->sb_width < 80) sb.X = 80; + if (cfg->sb_height < 25) sb.Y = 25; + + /* get maximum console window size from server */ + SERVER_START_REQ(get_console_output_info) { - COORD c; - SMALL_RECT pos; + req->handle = wine_server_obj_handle(data->hConOut); + wine_server_call(req); + max_console.X = reply->max_width; + max_console.Y = reply->max_height; + } + SERVER_END_REQ; - if (TstSBfWidth()) + /* set console font size */ + if (data->curcfg.cell_width != cfg->cell_width || data->curcfg.cell_height != cfg->cell_height) + { + data->fnSetFont(data, cfg->face_name, cfg->cell_height, cfg->font_weight); + } + + /* set the dimensions of the screen buffer and the console window */ + do { + if (data->curcfg.sb_width != cfg->sb_width) { - if (TstWinHPos()) + if (data->curcfg.win_width != cfg->win_width) { - /* we're changing both at the same time, do it in the right order */ - if (cfg->sb_width >= data->curcfg.win_width) - { - ChgSBfWidth(); ChgWinHPos(); - } - else - { - ChgWinHPos(); ChgSBfWidth(); - } + if (cfg->sb_width >= data->curcfg.win_width) { ChgSBfWidth(); ChgWinWidth(); } + else { ChgWinWidth(); ChgSBfWidth(); } } - else ChgSBfWidth(); + else { ChgSBfWidth(); } } - else if (TstWinHPos()) ChgWinHPos(); - if (TstSBfHeight()) + else if (data->curcfg.win_width != cfg->win_width) { ChgWinWidth(); } + + if (data->curcfg.sb_height != cfg->sb_height) { - if (TstWinVPos()) + if (data->curcfg.win_height != cfg->win_height) { - if (cfg->sb_height >= data->curcfg.win_height) - { - ChgSBfHeight(); ChgWinVPos(); - } - else - { - ChgWinVPos(); ChgSBfHeight(); - } + if (cfg->sb_height >= data->curcfg.win_height) { ChgSBfHeight(); ChgWinHeight(); } + else { ChgWinHeight(); ChgSBfHeight(); } } - else ChgSBfHeight(); + else { ChgSBfHeight(); } } - else if (TstWinVPos()) ChgWinVPos(); - } while (0); -#undef TstSBfWidth -#undef TstWinHPos -#undef ChgSBfWidth -#undef ChgWinHPos -#undef TstSBfHeight -#undef TstWinVPos -#undef ChgSBfHeight -#undef ChgWinVPos + else if (data->curcfg.win_height != cfg->win_height) { ChgWinHeight(); } + } while(0); + + #undef ChgSBfWidth + #undef ChgWinWidth + #undef ChgSBfHeight + #undef ChgWinHeight + /* other console data */ data->curcfg.exit_on_die = cfg->exit_on_die; if (data->curcfg.edition_mode != cfg->edition_mode) { data->curcfg.edition_mode = cfg->edition_mode; WINECON_SetEditionMode(data->hConIn, cfg->edition_mode); } - /* we now need to gather all events we got from the operations above, - * in order to get data correctly updated - */ + + /* gather all events from the above operations and update server data */ WINECON_GrabChanges(data); data->in_set_config = FALSE; } @@ -532,7 +561,7 @@ static void WINECON_Delete(struct inner_data* data) */ static BOOL WINECON_GetServerConfig(struct inner_data* data) { - BOOL ret; + BOOL ret; SERVER_START_REQ(get_console_input_info) { @@ -576,6 +605,8 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna DWORD ret; struct config_data cfg; STARTUPINFOW si; + COORD max_console; + int sb_width = 80, sb_height = 25; data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); if (!data) return 0; @@ -625,15 +656,28 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna if (!ret) goto error; WINE_TRACE("using hConIn %p, hSynchro event %p\n", data->hConIn, data->hSynchro); + /* calculate the largest possible console window */ + max_console = WINECON_GetMaxWindowSize((*backend), cfg.cell_width, cfg.cell_height); + + /* check screen buffer does not exceed maximum console window size */ + if (sb_width > max_console.X) sb_width = max_console.X; + if (sb_height > max_console.Y) sb_height = max_console.Y; + SERVER_START_REQ(create_console_output) { - req->handle_in = wine_server_obj_handle( data->hConIn ); - req->access = GENERIC_WRITE|GENERIC_READ; - req->attributes = 0; - req->share = FILE_SHARE_READ|FILE_SHARE_WRITE; - req->fd = -1; + req->handle_in = wine_server_obj_handle( data->hConIn ); + req->access = GENERIC_WRITE|GENERIC_READ; + req->attributes = 0; + req->share = FILE_SHARE_READ|FILE_SHARE_WRITE; + req->fd = -1; + req->width = sb_width; /* console screen buffer size */ + req->height = sb_height; + req->max_width = max_console.X; /* maximum console window size */ + req->max_height = max_console.Y; + req->font_width = cfg.cell_width; /* active console font size */ + req->font_height = cfg.cell_height; ret = !wine_server_call_err( req ); - data->hConOut = wine_server_ptr_handle( reply->handle_out ); + data->hConOut = wine_server_ptr_handle( reply->handle_out ); } SERVER_END_REQ; if (!ret) goto error; -- 1.7.10.4