Commit 0b83d4cb authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

New console code based on Win32 windows.

parent 6b6596a1
...@@ -28,7 +28,8 @@ PROGRAMS = \ ...@@ -28,7 +28,8 @@ PROGRAMS = \
# Programs that link with libwine # Programs that link with libwine
LIBPROGRAMS = \ LIBPROGRAMS = \
debugger/winedbg debugger/winedbg \
programs/wineconsole/wineconsole
# Libraries (not dlls) to build # Libraries (not dlls) to build
LIBRARIES = \ LIBRARIES = \
...@@ -59,6 +60,7 @@ INSTALLSUBDIRS = \ ...@@ -59,6 +60,7 @@ INSTALLSUBDIRS = \
include \ include \
library \ library \
ole \ ole \
programs/wineconsole \
server \ server \
tools \ tools \
tsx11 \ tsx11 \
......
...@@ -7166,6 +7166,7 @@ programs/regtest/Makefile ...@@ -7166,6 +7166,7 @@ programs/regtest/Makefile
programs/uninstaller/Makefile programs/uninstaller/Makefile
programs/view/Makefile programs/view/Makefile
programs/wcmd/Makefile programs/wcmd/Makefile
programs/wineconsole/Makefile
programs/winemine/Makefile programs/winemine/Makefile
programs/winetest/Makefile programs/winetest/Makefile
programs/winhelp/Makefile programs/winhelp/Makefile
...@@ -7426,6 +7427,7 @@ programs/regtest/Makefile ...@@ -7426,6 +7427,7 @@ programs/regtest/Makefile
programs/uninstaller/Makefile programs/uninstaller/Makefile
programs/view/Makefile programs/view/Makefile
programs/wcmd/Makefile programs/wcmd/Makefile
programs/wineconsole/Makefile
programs/winemine/Makefile programs/winemine/Makefile
programs/winetest/Makefile programs/winetest/Makefile
programs/winhelp/Makefile programs/winhelp/Makefile
......
...@@ -1336,6 +1336,7 @@ programs/regtest/Makefile ...@@ -1336,6 +1336,7 @@ programs/regtest/Makefile
programs/uninstaller/Makefile programs/uninstaller/Makefile
programs/view/Makefile programs/view/Makefile
programs/wcmd/Makefile programs/wcmd/Makefile
programs/wineconsole/Makefile
programs/winemine/Makefile programs/winemine/Makefile
programs/winetest/Makefile programs/winetest/Makefile
programs/winhelp/Makefile programs/winhelp/Makefile
......
...@@ -444,7 +444,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) ...@@ -444,7 +444,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (synchronous) XSynchronize( data->display, True ); if (synchronous) XSynchronize( data->display, True );
wine_tsx11_unlock(); wine_tsx11_unlock();
data->display_fd = FILE_DupUnixHandle( ConnectionNumber(data->display), data->display_fd = FILE_DupUnixHandle( ConnectionNumber(data->display),
GENERIC_READ | SYNCHRONIZE ); GENERIC_READ | SYNCHRONIZE, FALSE );
data->process_event_count = 0; data->process_event_count = 0;
NtCurrentTeb()->driver_data = data; NtCurrentTeb()->driver_data = data;
return data; return data;
......
...@@ -93,6 +93,17 @@ Options: ...@@ -93,6 +93,17 @@ Options:
options that affect the Windows program should come options that affect the Windows program should come
<emphasis>after</emphasis> it. <emphasis>after</emphasis> it.
</para> </para>
<para>
If you want to run a console program (aka a CUI executable), use
<command>wineconsole</command> instead of <command>wine</command>
to start it. It will display the program in a separate Window
(this requires X11 to be run). If you don't, you'll still be able
to run able your program, in the Unix console were you're started
your program, but with very limited capacities (so, your program
might work, but your mileage may vary). This shall be improved
in the future.
</para>
</sect1> </sect1>
<sect1 id="command-line-options"> <sect1 id="command-line-options">
......
.\" -*- nroff -*- .\" -*- nroff -*-
.TH WINE 1 "Aug 5, 2001" "Version 20010731" "Windows On Unix" .TH WINE 1 "Oct 13, 2001" "Version 20011004" "Windows On Unix"
.SH NAME .SH NAME
wine \- run Windows programs on Unix wine \- run Windows programs on Unix
.SH SYNOPSIS .SH SYNOPSIS
...@@ -20,6 +20,16 @@ For debugging wine, use ...@@ -20,6 +20,16 @@ For debugging wine, use
.I program .I program
instead. instead.
.PP .PP
For running CUI executables (Windows console programs), use
.B wineconsole
instead of
.B wine
. This will display all the output in a separate windows (this requires X11 to
run). Not using
.B wineconsole
for CUI programs will only provide very limited console support, and your
program might not function properly.
.PP
.B wine .B wine
currently runs a growing list of applications written for all kinds of currently runs a growing list of applications written for all kinds of
Windows versions >= Win2.0, e.g. Win3.1, Win95/98, NT. Windows versions >= Win2.0, e.g. Win3.1, Win95/98, NT.
...@@ -350,6 +360,11 @@ The ...@@ -350,6 +360,11 @@ The
.B wine .B wine
program loader. program loader.
.TP .TP
.I @prefix@/bin/wineconsole
The
.B wine
program loader for CUI (console) applications.
.TP
.I @prefix@/bin/dosmod .I @prefix@/bin/dosmod
The DOS program loader. The DOS program loader.
.TP .TP
......
...@@ -182,7 +182,7 @@ void FILE_SetDosError(void) ...@@ -182,7 +182,7 @@ void FILE_SetDosError(void)
* Duplicate a Unix handle into a task handle. * Duplicate a Unix handle into a task handle.
* Returns 0 on failure. * Returns 0 on failure.
*/ */
HANDLE FILE_DupUnixHandle( int fd, DWORD access ) HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
{ {
HANDLE ret; HANDLE ret;
...@@ -191,6 +191,7 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access ) ...@@ -191,6 +191,7 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access )
SERVER_START_REQ( alloc_file_handle ) SERVER_START_REQ( alloc_file_handle )
{ {
req->access = access; req->access = access;
req->inherit = inherit;
req->fd = fd; req->fd = fd;
SERVER_CALL(); SERVER_CALL();
ret = req->handle; ret = req->handle;
...@@ -255,14 +256,15 @@ int FILE_GetUnixHandle( HANDLE handle, DWORD access ) ...@@ -255,14 +256,15 @@ int FILE_GetUnixHandle( HANDLE handle, DWORD access )
* Open a handle to the current process console. * Open a handle to the current process console.
* Returns 0 on failure. * Returns 0 on failure.
*/ */
static HANDLE FILE_OpenConsole( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa ) static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
{ {
HANDLE ret; HANDLE ret;
SERVER_START_REQ( open_console ) SERVER_START_REQ( open_console )
{ {
req->output = output; req->from = output;
req->access = access; req->access = access;
req->share = sharing;
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
SetLastError(0); SetLastError(0);
SERVER_CALL_ERR(); SERVER_CALL_ERR();
...@@ -477,12 +479,12 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, ...@@ -477,12 +479,12 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
/* Open a console for CONIN$ or CONOUT$ */ /* Open a console for CONIN$ or CONOUT$ */
if (!strcasecmp(filename, "CONIN$")) if (!strcasecmp(filename, "CONIN$"))
{ {
ret = FILE_OpenConsole( FALSE, access, sa ); ret = FILE_OpenConsole( FALSE, access, sharing, sa );
goto done; goto done;
} }
if (!strcasecmp(filename, "CONOUT$")) if (!strcasecmp(filename, "CONOUT$"))
{ {
ret = FILE_OpenConsole( TRUE, access, sa ); ret = FILE_OpenConsole( TRUE, access, sharing, sa );
goto done; goto done;
} }
...@@ -1452,15 +1454,14 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ...@@ -1452,15 +1454,14 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
if (!bytesToRead) return TRUE; if (!bytesToRead) return TRUE;
unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type ); unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type );
if (unix_handle == -1)
return FALSE;
switch(type) switch (type)
{ {
case FD_TYPE_OVERLAPPED: case FD_TYPE_OVERLAPPED:
if(!overlapped) if (unix_handle == -1) return FALSE;
if (!overlapped)
{ {
close(unix_handle); close(unix_handle);
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
...@@ -1493,23 +1494,28 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ...@@ -1493,23 +1494,28 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
SetLastError(ERROR_IO_PENDING); SetLastError(ERROR_IO_PENDING);
return FALSE; return FALSE;
case FD_TYPE_CONSOLE:
return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
default: default:
if(overlapped) /* normal unix files */
{ if (unix_handle == -1)
close(unix_handle); return FALSE;
SetLastError(ERROR_INVALID_PARAMETER); if (overlapped)
return FALSE; {
} close(unix_handle);
break; SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
break;
} }
/* code for synchronous reads */ /* code for synchronous reads */
while ((result = read( unix_handle, buffer, bytesToRead )) == -1) while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
{ {
if ((errno == EAGAIN) || (errno == EINTR)) continue; if ((errno == EAGAIN) || (errno == EINTR)) continue;
if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue; if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
FILE_SetDosError(); FILE_SetDosError();
break; break;
} }
close( unix_handle ); close( unix_handle );
if (result == -1) return FALSE; if (result == -1) return FALSE;
...@@ -1648,6 +1654,7 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, ...@@ -1648,6 +1654,7 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
LPDWORD bytesWritten, LPOVERLAPPED overlapped ) LPDWORD bytesWritten, LPOVERLAPPED overlapped )
{ {
int unix_handle, result; int unix_handle, result;
DWORD type;
TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite, TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
bytesWritten, overlapped ); bytesWritten, overlapped );
...@@ -1659,8 +1666,18 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, ...@@ -1659,8 +1666,18 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
if ( overlapped ) if ( overlapped )
return WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL); return WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL);
unix_handle = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type );
if (unix_handle == -1) return FALSE;
switch (type)
{
case FD_TYPE_CONSOLE:
TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
bytesWritten, overlapped );
return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
default:
if (unix_handle == -1)
return FALSE;
}
/* synchronous file write */ /* synchronous file write */
while ((result = write( unix_handle, buffer, bytesToWrite )) == -1) while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
......
...@@ -71,7 +71,7 @@ inline static int FILE_contains_path (LPCSTR name) ...@@ -71,7 +71,7 @@ inline static int FILE_contains_path (LPCSTR name)
extern int FILE_strcasecmp( const char *str1, const char *str2 ); extern int FILE_strcasecmp( const char *str1, const char *str2 );
extern int FILE_strncasecmp( const char *str1, const char *str2, int len ); extern int FILE_strncasecmp( const char *str1, const char *str2, int len );
extern void FILE_SetDosError(void); extern void FILE_SetDosError(void);
extern HANDLE FILE_DupUnixHandle( int fd, DWORD access ); extern HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit );
extern int FILE_GetUnixHandle( HANDLE handle, DWORD access ); extern int FILE_GetUnixHandle( HANDLE handle, DWORD access );
extern BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info ); extern BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info );
extern HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 ); extern HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 );
......
...@@ -17,6 +17,8 @@ extern "C" { ...@@ -17,6 +17,8 @@ extern "C" {
#define ENABLE_ECHO_INPUT 0x04 #define ENABLE_ECHO_INPUT 0x04
#define ENABLE_WINDOW_INPUT 0x08 #define ENABLE_WINDOW_INPUT 0x08
#define ENABLE_MOUSE_INPUT 0x10 #define ENABLE_MOUSE_INPUT 0x10
/* Wine only code (extension) */
#define WINE_ENABLE_LINE_INPUT_EMACS 0x80
#define ENABLE_PROCESSED_OUTPUT 0x01 #define ENABLE_PROCESSED_OUTPUT 0x01
#define ENABLE_WRAP_AT_EOL_OUTPUT 0x02 #define ENABLE_WRAP_AT_EOL_OUTPUT 0x02
......
...@@ -577,6 +577,7 @@ struct alloc_file_handle_request ...@@ -577,6 +577,7 @@ struct alloc_file_handle_request
{ {
struct request_header __header; struct request_header __header;
unsigned int access; unsigned int access;
int inherit;
int fd; int fd;
handle_t handle; handle_t handle;
}; };
...@@ -755,8 +756,9 @@ struct alloc_console_request ...@@ -755,8 +756,9 @@ struct alloc_console_request
struct request_header __header; struct request_header __header;
unsigned int access; unsigned int access;
int inherit; int inherit;
void* pid;
handle_t handle_in; handle_t handle_in;
handle_t handle_out; handle_t event;
}; };
...@@ -767,25 +769,69 @@ struct free_console_request ...@@ -767,25 +769,69 @@ struct free_console_request
}; };
#define CONSOLE_RENDERER_NONE_EVENT 0x00
struct open_console_request #define CONSOLE_RENDERER_TITLE_EVENT 0x01
#define CONSOLE_RENDERER_ACTIVE_SB_EVENT 0x02
#define CONSOLE_RENDERER_SB_RESIZE_EVENT 0x03
#define CONSOLE_RENDERER_UPDATE_EVENT 0x04
#define CONSOLE_RENDERER_CURSOR_POS_EVENT 0x05
#define CONSOLE_RENDERER_CURSOR_GEOM_EVENT 0x06
#define CONSOLE_RENDERER_DISPLAY_EVENT 0x07
#define CONSOLE_RENDERER_EXIT_EVENT 0x08
struct console_renderer_event
{
short event;
union
{
struct update
{
short top;
short bottom;
} update;
struct resize
{
short width;
short height;
} resize;
struct cursor_pos
{
short x;
short y;
} cursor_pos;
struct cursor_geom
{
short visible;
short size;
} cursor_geom;
struct display
{
short left;
short top;
short width;
short height;
} display;
} u;
};
struct get_console_renderer_events_request
{ {
struct request_header __header; struct request_header __header;
int output;
unsigned int access;
int inherit;
handle_t handle; handle_t handle;
/* VARARG(data,bytes); */
}; };
struct set_console_fd_request struct open_console_request
{ {
struct request_header __header; struct request_header __header;
int from;
unsigned int access;
int inherit;
int share;
handle_t handle; handle_t handle;
int fd_in;
int fd_out;
int pid;
}; };
...@@ -808,30 +854,113 @@ struct set_console_mode_request ...@@ -808,30 +854,113 @@ struct set_console_mode_request
struct set_console_info_request struct set_console_input_info_request
{ {
struct request_header __header; struct request_header __header;
handle_t handle; handle_t handle;
int mask; int mask;
int cursor_size; handle_t active_sb;
int cursor_visible; int history_mode;
/* VARARG(title,string); */ int history_size;
/* VARARG(title,unicode_str); */
};
#define SET_CONSOLE_INPUT_INFO_ACTIVE_SB 0x01
#define SET_CONSOLE_INPUT_INFO_TITLE 0x02
#define SET_CONSOLE_INPUT_INFO_HISTORY_MODE 0x04
#define SET_CONSOLE_INPUT_INFO_HISTORY_SIZE 0x08
struct get_console_input_info_request
{
struct request_header __header;
handle_t handle;
int history_mode;
int history_size;
int history_index;
/* VARARG(title,unicode_str); */
};
struct append_console_input_history_request
{
struct request_header __header;
handle_t handle;
/* VARARG(line,unicode_str); */
};
struct get_console_input_history_request
{
struct request_header __header;
handle_t handle;
int index;
/* VARARG(line,unicode_str); */
};
struct create_console_output_request
{
struct request_header __header;
handle_t handle_in;
int access;
int share;
int inherit;
handle_t handle_out;
}; };
#define SET_CONSOLE_INFO_CURSOR 0x01
#define SET_CONSOLE_INFO_TITLE 0x02
struct get_console_info_request
struct set_console_output_info_request
{ {
struct request_header __header; struct request_header __header;
handle_t handle; handle_t handle;
int cursor_size; int mask;
int cursor_visible; short int cursor_size;
int pid; short int cursor_visible;
/* VARARG(title,string); */ short int cursor_x;
short int cursor_y;
short int width;
short int height;
short int attr;
short int win_left;
short int win_top;
short int win_right;
short int win_bottom;
short int max_width;
short int max_height;
}; };
#define SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM 0x01
#define SET_CONSOLE_OUTPUT_INFO_CURSOR_POS 0x02
#define SET_CONSOLE_OUTPUT_INFO_SIZE 0x04
#define SET_CONSOLE_OUTPUT_INFO_ATTR 0x08
#define SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW 0x10
#define SET_CONSOLE_OUTPUT_INFO_MAX_SIZE 0x20
struct get_console_output_info_request
{
struct request_header __header;
handle_t handle;
short int cursor_size;
short int cursor_visible;
short int cursor_x;
short int cursor_y;
short int width;
short int height;
short int attr;
short int win_left;
short int win_top;
short int win_right;
short int win_bottom;
short int max_width;
short int max_height;
};
struct write_console_input_request struct write_console_input_request
{ {
...@@ -842,6 +971,7 @@ struct write_console_input_request ...@@ -842,6 +971,7 @@ struct write_console_input_request
}; };
struct read_console_input_request struct read_console_input_request
{ {
struct request_header __header; struct request_header __header;
...@@ -853,6 +983,53 @@ struct read_console_input_request ...@@ -853,6 +983,53 @@ struct read_console_input_request
struct write_console_output_request
{
struct request_header __header;
handle_t handle;
int mode;
short int x;
short int y;
/* VARARG(data,bytes); */
int written;
};
#define WRITE_CONSOLE_MODE_TEXT 0x00
#define WRITE_CONSOLE_MODE_ATTR 0x01
#define WRITE_CONSOLE_MODE_TEXTATTR 0x02
#define WRITE_CONSOLE_MODE_TEXTSTDATTR 0x03
#define WRITE_CONSOLE_MODE_UNIFORM 0x04
struct read_console_output_request
{
struct request_header __header;
handle_t handle;
short int x;
short int y;
short int w;
short int h;
short int eff_w;
short int eff_h;
/* VARARG(data,bytes); */
};
struct move_console_output_request
{
struct request_header __header;
handle_t handle;
short int x_src;
short int y_src;
short int x_dst;
short int y_dst;
short int w;
short int h;
};
struct create_change_notification_request struct create_change_notification_request
{ {
struct request_header __header; struct request_header __header;
...@@ -1843,14 +2020,22 @@ enum request ...@@ -1843,14 +2020,22 @@ enum request
REQ_enable_socket_event, REQ_enable_socket_event,
REQ_alloc_console, REQ_alloc_console,
REQ_free_console, REQ_free_console,
REQ_get_console_renderer_events,
REQ_open_console, REQ_open_console,
REQ_set_console_fd,
REQ_get_console_mode, REQ_get_console_mode,
REQ_set_console_mode, REQ_set_console_mode,
REQ_set_console_info, REQ_set_console_input_info,
REQ_get_console_info, REQ_get_console_input_info,
REQ_append_console_input_history,
REQ_get_console_input_history,
REQ_create_console_output,
REQ_set_console_output_info,
REQ_get_console_output_info,
REQ_write_console_input, REQ_write_console_input,
REQ_read_console_input, REQ_read_console_input,
REQ_write_console_output,
REQ_read_console_output,
REQ_move_console_output,
REQ_create_change_notification, REQ_create_change_notification,
REQ_create_mapping, REQ_create_mapping,
REQ_open_mapping, REQ_open_mapping,
...@@ -1990,14 +2175,22 @@ union generic_request ...@@ -1990,14 +2175,22 @@ union generic_request
struct enable_socket_event_request enable_socket_event; struct enable_socket_event_request enable_socket_event;
struct alloc_console_request alloc_console; struct alloc_console_request alloc_console;
struct free_console_request free_console; struct free_console_request free_console;
struct get_console_renderer_events_request get_console_renderer_events;
struct open_console_request open_console; struct open_console_request open_console;
struct set_console_fd_request set_console_fd;
struct get_console_mode_request get_console_mode; struct get_console_mode_request get_console_mode;
struct set_console_mode_request set_console_mode; struct set_console_mode_request set_console_mode;
struct set_console_info_request set_console_info; struct set_console_input_info_request set_console_input_info;
struct get_console_info_request get_console_info; struct get_console_input_info_request get_console_input_info;
struct append_console_input_history_request append_console_input_history;
struct get_console_input_history_request get_console_input_history;
struct create_console_output_request create_console_output;
struct set_console_output_info_request set_console_output_info;
struct get_console_output_info_request get_console_output_info;
struct write_console_input_request write_console_input; struct write_console_input_request write_console_input;
struct read_console_input_request read_console_input; struct read_console_input_request read_console_input;
struct write_console_output_request write_console_output;
struct read_console_output_request read_console_output;
struct move_console_output_request move_console_output;
struct create_change_notification_request create_change_notification; struct create_change_notification_request create_change_notification;
struct create_mapping_request create_mapping; struct create_mapping_request create_mapping;
struct open_mapping_request open_mapping; struct open_mapping_request open_mapping;
...@@ -2080,6 +2273,6 @@ union generic_request ...@@ -2080,6 +2273,6 @@ union generic_request
struct get_window_properties_request get_window_properties; struct get_window_properties_request get_window_properties;
}; };
#define SERVER_PROTOCOL_VERSION 64 #define SERVER_PROTOCOL_VERSION 65
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -1052,10 +1052,6 @@ BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine, ...@@ -1052,10 +1052,6 @@ BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
/* Warn if unsupported features are used */ /* Warn if unsupported features are used */
if (dwCreationFlags & DETACHED_PROCESS)
FIXME("(%s,...): DETACHED_PROCESS ignored\n", name);
if (dwCreationFlags & CREATE_NEW_CONSOLE)
FIXME("(%s,...): CREATE_NEW_CONSOLE ignored\n", name);
if (dwCreationFlags & NORMAL_PRIORITY_CLASS) if (dwCreationFlags & NORMAL_PRIORITY_CLASS)
FIXME("(%s,...): NORMAL_PRIORITY_CLASS ignored\n", name); FIXME("(%s,...): NORMAL_PRIORITY_CLASS ignored\n", name);
if (dwCreationFlags & IDLE_PRIORITY_CLASS) if (dwCreationFlags & IDLE_PRIORITY_CLASS)
......
...@@ -17,6 +17,7 @@ SUBDIRS = \ ...@@ -17,6 +17,7 @@ SUBDIRS = \
uninstaller \ uninstaller \
view \ view \
wcmd \ wcmd \
wineconsole \
winemine \ winemine \
winetest \ winetest \
winhelp \ winhelp \
......
Makefile
wineconsole.spec.c
wineconsole_res.res
EXTRADEFS = -DSTRICT -DUNICODE
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = wineconsole
C_SRCS = \
dialog.c \
user.c \
wineconsole.c
RC_SRCS = \
wineconsole_res.rc
@MAKE_PROG_RULES@
### Dependencies:
/* dialog management for wineconsole
* (c) 2001 Eric Pouech
*/
#include <stdio.h>
#include "winecon_private.h"
#include "commctrl.h"
#include "prsht.h"
/* FIXME: so far, part of the code is made in ASCII because the Uncode property sheet functions
* are not implemented yet
*/
struct dialog_info
{
struct inner_data* data; /* pointer to current winecon info */
HWND hDlg; /* handle to window dialog */
int nFont; /* number of font size in size LB */
struct font_info
{
TEXTMETRIC tm;
LOGFONT lf;
} *font; /* array of nFont. index sync'ed with SIZE LB */
};
/******************************************************************
* WCUSER_OptionDlgProc
*
* Dialog prop for the option property sheet
*/
static BOOL WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct dialog_info* di;
unsigned idc;
switch (msg)
{
case WM_INITDIALOG:
di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
di->hDlg = hDlg;
SetWindowLongA(hDlg, DWL_USER, (DWORD)di);
if (di->data->cursor_size < 33) idc = IDC_OPT_CURSOR_SMALL;
else if (di->data->cursor_size < 66) idc = IDC_OPT_CURSOR_MEDIUM;
else idc = IDC_OPT_CURSOR_LARGE;
SendDlgItemMessage(hDlg, idc, BM_SETCHECK, BST_CHECKED, 0L);
SetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, WINECON_GetHistorySize(di->data->hConIn), FALSE);
if (WINECON_GetHistoryMode(di->data->hConIn))
SendDlgItemMessage(hDlg, IDC_OPT_HIST_DOUBLE, BM_SETCHECK, BST_CHECKED, 0L);
return FALSE; /* because we set the focus */
case WM_COMMAND:
break;
case WM_NOTIFY:
{
NMHDR* nmhdr = (NMHDR*)lParam;
di = (struct dialog_info*)GetWindowLongA(hDlg, DWL_USER);
switch (nmhdr->code)
{
case PSN_SETACTIVE:
/* needed in propsheet to keep properly the selected radio button
* otherwise, the focus would be set to the first tab stop in the
* propsheet, which would always activate the first radio button
*/
if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED)
idc = IDC_OPT_CURSOR_SMALL;
else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED)
idc = IDC_OPT_CURSOR_MEDIUM;
else
idc = IDC_OPT_CURSOR_LARGE;
PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, idc), TRUE);
break;
case PSN_APPLY:
{
int curs_size;
int hist_size;
BOOL done;
if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED) curs_size = 33;
else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED) curs_size = 66;
else curs_size = 99;
if (curs_size != di->data->cursor_size)
{
CONSOLE_CURSOR_INFO cinfo;
cinfo.dwSize = curs_size;
cinfo.bVisible = di->data->cursor_visible;
SetConsoleCursorInfo(di->data->hConOut, &cinfo);
}
hist_size = GetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, &done, FALSE);
if (done) WINECON_SetHistorySize(di->data->hConIn, hist_size);
SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
WINECON_SetHistoryMode(di->data->hConIn,
IsDlgButtonChecked(hDlg, IDC_OPT_HIST_DOUBLE) & BST_CHECKED);
return TRUE;
}
default:
return FALSE;
}
break;
}
default:
return FALSE;
}
return TRUE;
}
/******************************************************************
* WCUSER_FontPreviewProc
*
* Window proc for font previewer in font property sheet
*/
static LRESULT WINAPI WCUSER_FontPreviewProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
int font_idx;
int size_idx;
struct dialog_info* di;
di = (struct dialog_info*)GetWindowLong(GetParent(hWnd), DWL_USER);
BeginPaint(hWnd, &ps);
font_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
size_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
if (font_idx >= 0 && size_idx >= 0 && size_idx < di->nFont)
{
HFONT hFont, hOldFont;
WCHAR buf1[256];
WCHAR buf2[256];
int len1, len2;
hFont = CreateFontIndirect(&di->font[size_idx].lf);
len1 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_1,
buf1, sizeof(buf1) / sizeof(WCHAR));
len2 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_2,
buf2, sizeof(buf2) / sizeof(WCHAR));
if (hFont && len1)
{
hOldFont = SelectObject(ps.hdc, hFont);
SetBkColor(ps.hdc, RGB(0x00, 0x00, 0x00));
SetTextColor(ps.hdc, RGB(0xFF, 0xFF, 0xFF));
TextOut(ps.hdc, 0, 0, buf1, len1);
if (len2)
TextOut(ps.hdc, 0, di->font[size_idx].tm.tmHeight, buf2, len2);
SelectObject(ps.hdc, hOldFont);
DeleteObject(hFont);
}
}
EndPaint(hWnd, &ps);
break;
}
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0L;
}
/******************************************************************
* font_enum
*
*
*/
static int CALLBACK font_enum_size2(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct dialog_info* di = (struct dialog_info*)lParam;
if (WCUSER_ValidateFontMetric(di->data, tm))
{
di->nFont++;
}
return 1;
}
static int CALLBACK font_enum(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct dialog_info* di = (struct dialog_info*)lParam;
HDC hdc;
if (WCUSER_ValidateFont(di->data, lf) && (hdc = GetDC(di->hDlg)))
{
di->nFont = 0;
EnumFontFamilies(hdc, lf->lfFaceName, font_enum_size2, (LPARAM)di);
if (di->nFont)
{
int idx;
idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_ADDSTRING,
0, (LPARAM)lf->lfFaceName);
}
ReleaseDC(di->hDlg, hdc);
}
return 1;
}
/******************************************************************
* font_enum_size
*
*
*/
static int CALLBACK font_enum_size(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct dialog_info* di = (struct dialog_info*)lParam;
if (WCUSER_ValidateFontMetric(di->data, tm))
{
WCHAR buf[32];
WCHAR fmt[] = {'%','l','d',0};
int idx;
/* we want the string to be sorted with a numeric order, not a lexicographic...
* do the job by hand... get where to insert the new string
*/
for (idx = 0; idx < di->nFont && tm->tmHeight > di->font[idx].tm.tmHeight; idx++);
wsprintfW(buf, fmt, tm->tmHeight);
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, idx, (LPARAM)buf);
/* now grow our arrays and insert to values at the same index than in the list box */
di->font = HeapReAlloc(GetProcessHeap(), 0, di->font, sizeof(*di->font) * (di->nFont + 1));
if (idx != di->nFont)
memmove(&di->font[idx + 1], &di->font[idx], (di->nFont - idx) * sizeof(*di->font));
di->font[idx].tm = *tm;
di->font[idx].lf = *lf;
di->nFont++;
}
return 1;
}
/******************************************************************
* select_font
*
*
*/
static BOOL select_font(struct dialog_info* di)
{
int idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
WCHAR buf[256];
WCHAR fmt[128];
if (idx < 0 || idx >= di->nFont)
return FALSE;
LoadString(GetModuleHandle(NULL), IDS_FNT_DISPLAY, fmt, sizeof(fmt) / sizeof(WCHAR));
wsprintfW(buf, fmt, di->font[idx].tm.tmMaxCharWidth, di->font[idx].tm.tmHeight);
SendDlgItemMessage(di->hDlg, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf);
InvalidateRect(GetDlgItem(di->hDlg, IDC_FNT_PREVIEW), NULL, TRUE);
UpdateWindow(GetDlgItem(di->hDlg, IDC_FNT_PREVIEW));
return TRUE;
}
/******************************************************************
* fill_list_size
*
* fills the size list box according to selected family in font LB
*/
static BOOL fill_list_size(struct dialog_info* di, BOOL doInit)
{
HDC hdc;
int idx;
WCHAR lfFaceName[LF_FACESIZE];
idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
if (idx < 0) return FALSE;
hdc = GetDC(di->hDlg);
if (!hdc) return FALSE;
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETTEXT, idx, (LPARAM)lfFaceName);
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_RESETCONTENT, 0L, 0L);
if (di->font) HeapFree(GetProcessHeap(), 0, di->font);
di->nFont = 0;
di->font = NULL;
EnumFontFamilies(hdc, lfFaceName, font_enum_size, (LPARAM)di);
ReleaseDC(di->hDlg, hdc);
if (doInit)
{
for (idx = 0; idx < di->nFont; idx++)
{
if (memcmp(&di->data->logFont, &di->font[idx].lf, sizeof(LOGFONT)) == 0)
break;
}
if (idx == di->nFont) idx = 0;
}
else
idx = 0;
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0L);
select_font(di);
return TRUE;
}
/******************************************************************
* fill_list_font
*
* Fills the font LB
*/
static BOOL fill_list_font(struct dialog_info* di)
{
HDC hdc;
hdc = GetDC(di->hDlg);
if (!hdc) return FALSE;
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_RESETCONTENT, 0L, 0L);
EnumFontFamilies(hdc, NULL, font_enum, (LPARAM)di);
ReleaseDC(di->hDlg, hdc);
if (SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
(WPARAM)-1, (LPARAM)di->data->logFont.lfFaceName) == LB_ERR)
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0L, 0L);
fill_list_size(di, TRUE);
return TRUE;
}
/******************************************************************
* WCUSER_FontDlgProc
*
* Dialog proc for the Font property sheet
*/
static BOOL WINAPI WCUSER_FontDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct dialog_info* di;
switch (msg)
{
case WM_INITDIALOG:
di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
di->hDlg = hDlg;
SetWindowLong(hDlg, DWL_USER, (DWORD)di);
fill_list_font(di);
break;
case WM_COMMAND:
di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
switch (LOWORD(wParam))
{
case IDC_FNT_LIST_FONT:
if (HIWORD(wParam) == LBN_SELCHANGE)
{
fill_list_size(di, FALSE);
}
break;
case IDC_FNT_LIST_SIZE:
if (HIWORD(wParam) == LBN_SELCHANGE)
{
select_font(di);
}
break;
}
break;
case WM_NOTIFY:
{
NMHDR* nmhdr = (NMHDR*)lParam;
di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
switch (nmhdr->code)
{
case PSN_APPLY:
{
int idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
if (idx >= 0 && idx < di->nFont)
{
WCUSER_SetFont(di->data, &di->font[idx].lf, &di->font[idx].tm);
}
SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
return TRUE;
}
default:
return FALSE;
}
break;
}
default:
return FALSE;
}
return TRUE;
}
/******************************************************************
* WCUSER_ConfigDlgProc
*
* Dialog proc for the config property sheet
*/
static BOOL WINAPI WCUSER_ConfigDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct dialog_info* di;
switch (msg)
{
case WM_INITDIALOG:
di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
di->hDlg = hDlg;
SetWindowLong(hDlg, DWL_USER, (DWORD)di);
SetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH, di->data->sb_width, FALSE);
SetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT, di->data->sb_height, FALSE);
SetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH, di->data->win_width, FALSE);
SetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, di->data->win_height, FALSE);
break;
case WM_COMMAND:
di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
switch (LOWORD(wParam))
{
}
break;
case WM_NOTIFY:
{
NMHDR* nmhdr = (NMHDR*)lParam;
di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
switch (nmhdr->code)
{
case PSN_APPLY:
{
COORD sb;
SMALL_RECT pos;
BOOL st_w, st_h;
sb.X = GetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH, &st_w, FALSE);
sb.Y = GetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT, &st_h, FALSE);
if (st_w && st_h && (sb.X != di->data->sb_width || sb.Y != di->data->sb_height))
{
SetConsoleScreenBufferSize(di->data->hConOut, sb);
}
pos.Right = GetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH, &st_w, FALSE);
pos.Bottom = GetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, &st_h, FALSE);
if (st_w && st_h &&
(pos.Right != di->data->win_width || pos.Bottom != di->data->win_height))
{
pos.Left = pos.Top = 0;
pos.Right--; pos.Bottom--;
SetConsoleWindowInfo(di->data->hConOut, FALSE, &pos);
}
SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
return TRUE;
}
default:
return FALSE;
}
break;
}
default:
return FALSE;
}
return TRUE;
}
/******************************************************************
* WCUSER_GetProperties
*
* Runs the dialog box to set up the winconsole options
*/
BOOL WCUSER_GetProperties(struct inner_data* data)
{
HPROPSHEETPAGE psPage[3];
PROPSHEETPAGEA psp;
PROPSHEETHEADERA psHead;
WNDCLASS wndclass;
static WCHAR szFntPreview[] = {'W','i','n','e','C','o','n','F','o','n','t','P','r','e','v','i','e','w',0};
struct dialog_info di;
InitCommonControls();
di.data = data;
di.nFont = 0;
di.font = NULL;
wndclass.style = 0;
wndclass.lpfnWndProc = WCUSER_FontPreviewProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = GetModuleHandle(NULL);
wndclass.hIcon = 0;
wndclass.hCursor = LoadCursor(0, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szFntPreview;
RegisterClass(&wndclass);
memset(&psp, 0, sizeof(psp));
psp.dwSize = sizeof(psp);
psp.dwFlags = 0;
psp.hInstance = wndclass.hInstance;
psp.lParam = (LPARAM)&di;
psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_OPTION);
psp.pfnDlgProc = WCUSER_OptionDlgProc;
psPage[0] = CreatePropertySheetPageA(&psp);
psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_FONT);
psp.pfnDlgProc = WCUSER_FontDlgProc;
psPage[1] = CreatePropertySheetPageA(&psp);
psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_CONFIG);
psp.pfnDlgProc = WCUSER_ConfigDlgProc;
psPage[2] = CreatePropertySheetPageA(&psp);
memset(&psHead, 0, sizeof(psHead));
psHead.dwSize = sizeof(psHead);
psHead.pszCaption = "Setup";
psHead.nPages = 3;
psHead.hwndParent = data->hWnd;
psHead.u3.phpage = psPage;
PropertySheetA(&psHead);
return TRUE;
}
/*
* a GUI application for displaying a console
* USER32 back end
* Copyright 2001 Eric Pouech
*/
#include <stdio.h>
#include "winecon_private.h"
/* mapping console colors to RGB values */
static COLORREF color_map[16] =
{
RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0x80, 0x80, 0x80),
RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF),
};
/******************************************************************
* WCUSER_FillMemDC
*
* Fills the Mem DC with current cells values
*/
static void WCUSER_FillMemDC(const struct inner_data* data, int upd_tp, int upd_bm)
{
unsigned i, j, k;
CHAR_INFO* cell;
HFONT hOldFont;
WORD attr;
WCHAR* line;
if (!(line = HeapAlloc(GetProcessHeap(), 0, data->sb_width * sizeof(WCHAR))))
{Trace(0, "OOM\n"); return;}
hOldFont = SelectObject(data->hMemDC, data->hFont);
for (j = upd_tp; j <= upd_bm; j++)
{
cell = &data->cells[j * data->sb_width];
for (i = 0; i < data->win_width; i++)
{
attr = cell[i].Attributes;
SetBkColor(data->hMemDC, color_map[attr & 0x0F]);
SetTextColor(data->hMemDC, color_map[(attr >> 4) & 0x0F]);
for (k = i; k < data->win_width && cell[k].Attributes == attr; k++)
{
line[k - i] = cell[k].Char.UnicodeChar;
}
TextOut(data->hMemDC, i * data->cell_width, j * data->cell_height,
line, k - i);
i = k - 1;
}
}
SelectObject(data->hMemDC, hOldFont);
HeapFree(GetProcessHeap(), 0, line);
}
/******************************************************************
* WCUSER_NewBitmap
*
* Either the font geometry or the sb geometry has changed. we need to recreate the
* bitmap geometry
*/
static void WCUSER_NewBitmap(struct inner_data* data, BOOL fill)
{
HBITMAP hnew, hold;
if (!data->sb_width || !data->sb_height)
return;
hnew = CreateCompatibleBitmap(data->hMemDC,
data->sb_width * data->cell_width,
data->sb_height * data->cell_height);
hold = SelectObject(data->hMemDC, hnew);
if (data->hBitmap)
{
if (hold == data->hBitmap)
DeleteObject(data->hBitmap);
else
Trace(0, "leak\n");
}
data->hBitmap = hnew;
if (fill)
WCUSER_FillMemDC(data, 0, data->sb_height - 1);
}
/******************************************************************
* WCUSER_ResizeScreenBuffer
*
*
*/
static void WCUSER_ResizeScreenBuffer(struct inner_data* data)
{
WCUSER_NewBitmap(data, FALSE);
}
/******************************************************************
* WCUSER_PosCursor
*
* Set a new position for the cursor
*/
static void WCUSER_PosCursor(const struct inner_data* data)
{
if (data->hWnd != GetFocus() || !data->cursor_visible) return;
SetCaretPos((data->cursor.X - data->win_pos.X) * data->cell_width,
(data->cursor.Y - data->win_pos.Y) * data->cell_height);
ShowCaret(data->hWnd);
}
/******************************************************************
* WCUSER_ShapeCursor
*
* Sets a new shape for the cursor
*/
void WCUSER_ShapeCursor(struct inner_data* data, int size, int vis, BOOL force)
{
if (force || size != data->cursor_size)
{
if (data->cursor_visible && data->hWnd == GetFocus()) DestroyCaret();
if (data->cursor_bitmap) DeleteObject(data->cursor_bitmap);
data->cursor_bitmap = (HBITMAP)0;
if (size != 100)
{
int w16b; /* number of byets per row, aligned on word size */
BYTE* ptr;
int i, j, nbl;
w16b = ((data->cell_width + 15) & ~15) / 8;
ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, w16b * data->cell_height);
if (!ptr) {Trace(0, "OOM\n"); return;}
nbl = max((data->cell_height * size) / 100, 1);
for (j = data->cell_height - nbl; j < data->cell_height; j++)
{
for (i = 0; i < data->cell_width; i++)
{
ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
}
}
data->cursor_bitmap = CreateBitmap(data->cell_width, data->cell_height, 1, 1, ptr);
HeapFree(GetProcessHeap(), 0, ptr);
}
data->cursor_size = size;
data->cursor_visible = -1;
}
vis = (vis) ? TRUE : FALSE;
if (force || vis != data->cursor_visible)
{
data->cursor_visible = vis;
if (data->hWnd == GetFocus())
{
if (vis)
{
CreateCaret(data->hWnd, data->cursor_bitmap, data->cell_width, data->cell_height);
WCUSER_PosCursor(data);
}
else
{
DestroyCaret();
}
}
}
}
/******************************************************************
* INECON_ComputePositions
*
* Recomputes all the components (mainly scroll bars) positions
*/
void WCUSER_ComputePositions(struct inner_data* data)
{
RECT r;
int dx, dy;
/* compute window size from desired client size */
r.left = r.top = 0;
r.right = data->win_width * data->cell_width;
r.bottom = data->win_height * data->cell_height;
if (IsRectEmpty(&r))
{
ShowWindow(data->hWnd, SW_HIDE);
return;
}
AdjustWindowRect(&r, GetWindowLong(data->hWnd, GWL_STYLE), FALSE);
dx = dy = 0;
if (data->sb_width > data->win_width)
{
dy = GetSystemMetrics(SM_CYHSCROLL);
SetScrollRange(data->hWnd, SB_HORZ, 0, data->sb_width - data->win_width, FALSE);
SetScrollPos(data->hWnd, SB_HORZ, 0, FALSE); /* FIXME */
ShowScrollBar(data->hWnd, SB_HORZ, TRUE);
}
else
{
ShowScrollBar(data->hWnd, SB_HORZ, FALSE);
}
if (data->sb_height > data->win_height)
{
dx = GetSystemMetrics(SM_CXVSCROLL);
SetScrollRange(data->hWnd, SB_VERT, 0, data->sb_height - data->win_height, FALSE);
SetScrollPos(data->hWnd, SB_VERT, 0, FALSE); /* FIXME */
ShowScrollBar(data->hWnd, SB_VERT, TRUE);
}
else
{
ShowScrollBar(data->hWnd, SB_VERT, FALSE);
}
SetWindowPos(data->hWnd, 0, 0, 0, r.right - r.left + dx, r.bottom - r.top + dy,
SWP_NOMOVE|SWP_NOZORDER|SWP_SHOWWINDOW);
WCUSER_ShapeCursor(data, data->cursor_size, data->cursor_visible, TRUE);
WCUSER_PosCursor(data);
}
/******************************************************************
* WCUSER_SetTitle
*
* Sets the title to the wine console
*/
static void WCUSER_SetTitle(const struct inner_data* data)
{
WCHAR buffer[256];
if (WINECON_GetConsoleTitle(data->hConIn, buffer, sizeof(buffer)))
SetWindowText(data->hWnd, buffer);
}
/******************************************************************
* WCUSER_SetFont
*
*
*/
BOOL WCUSER_SetFont(struct inner_data* data, const LOGFONT* logfont, const TEXTMETRIC* tm)
{
if (!memcmp(logfont, &data->logFont, sizeof(LOGFONT))) return TRUE;
if (data->hFont) DeleteObject(data->hFont);
data->hFont = CreateFontIndirect(logfont);
if (!data->hFont) {Trace(0, "wrong font\n");return FALSE;}
data->cell_width = tm->tmMaxCharWidth; /* font is fixed Avg == Max */
data->cell_height = tm->tmHeight;
data->logFont = *logfont;
WCUSER_ComputePositions(data);
WCUSER_NewBitmap(data, TRUE);
InvalidateRect(data->hWnd, NULL, FALSE);
UpdateWindow(data->hWnd);
return TRUE;
}
/******************************************************************
* WCUSER_GetCell
*
* Get a cell from the a relative coordinate in window (takes into
* account the scrolling)
*/
static COORD WCUSER_GetCell(const struct inner_data* data, LPARAM lParam)
{
COORD c;
c.X = data->win_pos.X + (short)LOWORD(lParam) / data->cell_width;
c.Y = data->win_pos.Y + (short)HIWORD(lParam) / data->cell_height;
return c;
}
/******************************************************************
* WCUSER_GetSelectionRect
*
* Get the selection rectangle
*/
static void WCUSER_GetSelectionRect(const struct inner_data* data, LPRECT r)
{
r->left = (min(data->selectPt1.X, data->selectPt2.X) ) * data->cell_width;
r->top = (min(data->selectPt1.Y, data->selectPt2.Y) ) * data->cell_height;
r->right = (max(data->selectPt1.X, data->selectPt2.X) + 1) * data->cell_width;
r->bottom = (max(data->selectPt1.Y, data->selectPt2.Y) + 1) * data->cell_height;
}
/******************************************************************
* WCUSER_SetSelection
*
*
*/
static void WCUSER_SetSelection(const struct inner_data* data, HDC hRefDC)
{
HDC hDC;
RECT r;
WCUSER_GetSelectionRect(data, &r);
hDC = hRefDC ? hRefDC : GetDC(data->hWnd);
if (hDC)
{
if (data->hWnd == GetFocus() && data->cursor_visible)
HideCaret(data->hWnd);
InvertRect(hDC, &r);
if (hDC != hRefDC)
ReleaseDC(data->hWnd, hDC);
if (data->hWnd == GetFocus() && data->cursor_visible)
ShowCaret(data->hWnd);
}
}
/******************************************************************
* WCUSER_MoveSelection
*
*
*/
static void WCUSER_MoveSelection(struct inner_data* data, COORD dst, BOOL final)
{
RECT r;
HDC hDC;
WCUSER_GetSelectionRect(data, &r);
hDC = GetDC(data->hWnd);
if (hDC)
{
if (data->hWnd == GetFocus() && data->cursor_visible)
HideCaret(data->hWnd);
InvertRect(hDC, &r);
}
data->selectPt2 = dst;
if (hDC)
{
WCUSER_GetSelectionRect(data, &r);
InvertRect(hDC, &r);
ReleaseDC(data->hWnd, hDC);
if (data->hWnd == GetFocus() && data->cursor_visible)
ShowCaret(data->hWnd);
}
if (final)
{
ReleaseCapture();
data->hasSelection = TRUE;
}
}
/******************************************************************
* WCUSER_CopySelectionToClipboard
*
* Copies the current selection into the clipboard
*/
static void WCUSER_CopySelectionToClipboard(const struct inner_data* data)
{
HANDLE hMem;
LPWSTR p;
unsigned w, h;
w = abs(data->selectPt1.X - data->selectPt2.X) + 2;
h = abs(data->selectPt1.Y - data->selectPt2.Y) + 1;
if (!OpenClipboard(data->hWnd)) return;
EmptyClipboard();
hMem = GlobalAlloc(GMEM_MOVEABLE, (w * h - 1) * sizeof(WCHAR));
if (hMem && (p = GlobalLock(hMem)))
{
COORD c;
int y;
c.X = data->win_pos.X + min(data->selectPt1.X, data->selectPt2.X);
c.Y = data->win_pos.Y + min(data->selectPt1.Y, data->selectPt2.Y);
for (y = 0; y < h; y++, c.Y++)
{
ReadConsoleOutputCharacter(data->hConOut, &p[y * w], w - 1, c, NULL);
if (y < h - 1) p[y * w + w - 1] = '\n';
}
GlobalUnlock(hMem);
SetClipboardData(CF_UNICODETEXT, hMem);
}
CloseClipboard();
}
/******************************************************************
* WCUSER_PasteFromClipboard
*
*
*/
static void WCUSER_PasteFromClipboard(struct inner_data* data)
{
HANDLE h;
WCHAR* ptr;
if (!OpenClipboard(data->hWnd)) return;
h = GetClipboardData(CF_UNICODETEXT);
if (h && (ptr = GlobalLock(h)))
{
int i, len = GlobalSize(h) / sizeof(WCHAR);
INPUT_RECORD ir[2];
DWORD n;
SHORT sh;
ir[0].EventType = KEY_EVENT;
ir[0].Event.KeyEvent.wRepeatCount = 0;
ir[0].Event.KeyEvent.dwControlKeyState = 0;
ir[0].Event.KeyEvent.bKeyDown = TRUE;
/* generate the corresponding input records */
for (i = 0; i < len; i++)
{
/* FIXME: the modifying keys are not generated (shift, ctrl...) */
sh = VkKeyScan(ptr[i]);
ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(LOBYTE(sh), 0);
ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
ir[1] = ir[0];
ir[1].Event.KeyEvent.bKeyDown = FALSE;
WriteConsoleInput(data->hConIn, ir, 2, &n);
}
GlobalUnlock(h);
}
CloseClipboard();
}
static void WCUSER_Refresh(const struct inner_data* data, int tp, int bm)
{
if (data->win_pos.Y <= bm && data->win_pos.Y + data->win_height >= tp)
{
RECT r;
r.left = 0;
r.right = data->win_width * data->cell_width;
r.top = (tp - data->win_pos.Y) * data->cell_height;
r.bottom = (bm - data->win_pos.Y + 1) * data->cell_height;
InvalidateRect(data->hWnd, &r, FALSE);
WCUSER_FillMemDC(data, tp, bm);
UpdateWindow(data->hWnd);
}
}
/******************************************************************
* WCUSER_Paint
*
*
*/
static void WCUSER_Paint(const struct inner_data* data)
{
PAINTSTRUCT ps;
BeginPaint(data->hWnd, &ps);
BitBlt(ps.hdc, 0, 0, data->win_width * data->cell_width, data->win_height * data->cell_height,
data->hMemDC, data->win_pos.X * data->cell_width, data->win_pos.Y * data->cell_height,
SRCCOPY);
if (data->hasSelection)
WCUSER_SetSelection(data, ps.hdc);
EndPaint(data->hWnd, &ps);
}
/******************************************************************
* WCUSER_Scroll
*
*
*/
static void WCUSER_Scroll(struct inner_data* data, int pos, BOOL horz)
{
if (horz)
{
SetScrollPos(data->hWnd, SB_HORZ, pos, TRUE);
data->win_pos.X = pos;
InvalidateRect(data->hWnd, NULL, FALSE);
}
else
{
SetScrollPos(data->hWnd, SB_VERT, pos, TRUE);
data->win_pos.Y = pos;
}
InvalidateRect(data->hWnd, NULL, FALSE);
}
struct font_chooser {
struct inner_data* data;
int done;
};
/******************************************************************
* WCUSER_ValidateFontMetric
*
* Returns true if the font described in tm is usable as a font for the renderer
*/
BOOL WCUSER_ValidateFontMetric(const struct inner_data* data, const TEXTMETRIC* tm)
{
return tm->tmMaxCharWidth * data->win_width < GetSystemMetrics(SM_CXSCREEN) &&
tm->tmHeight * data->win_height < GetSystemMetrics(SM_CYSCREEN) &&
!tm->tmItalic && !tm->tmUnderlined && !tm->tmStruckOut;
}
/******************************************************************
* WCUSER_ValidateFont
*
* Returns true if the font family described in lf is usable as a font for the renderer
*/
BOOL WCUSER_ValidateFont(const struct inner_data* data, const LOGFONT* lf)
{
return (lf->lfPitchAndFamily & 3) == FIXED_PITCH && (lf->lfPitchAndFamily & 0xF0) == FF_MODERN;
}
/******************************************************************
* get_first_font_enum_2
* get_first_font_enum
*
* Helper functions to get a decent font for the renderer
*/
static int CALLBACK get_first_font_enum_2(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct font_chooser* fc = (struct font_chooser*)lParam;
if (WCUSER_ValidateFontMetric(fc->data, tm))
{
WCUSER_SetFont(fc->data, lf, tm);
fc->done = 1;
return 0;
}
return 1;
}
static int CALLBACK get_first_font_enum(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct font_chooser* fc = (struct font_chooser*)lParam;
if (WCUSER_ValidateFont(fc->data, lf))
{
EnumFontFamilies(fc->data->hMemDC, lf->lfFaceName, get_first_font_enum_2, lParam);
return !fc->done; /* we just need the first matching one... */
}
return 1;
}
/******************************************************************
* WCUSER_Create
*
* Creates the window for the rendering
*/
static LRESULT WCUSER_Create(HWND hWnd, LPCREATESTRUCT lpcs)
{
struct inner_data* data;
HMENU hMenu;
HMENU hSubMenu;
WCHAR buff[256];
HINSTANCE hInstance = GetModuleHandle(NULL);
data = lpcs->lpCreateParams;
SetWindowLong(hWnd, 0L, (DWORD)data);
data->hWnd = hWnd;
data->cursor_size = 101; /* invalid value, will trigger a complete cleanup */
/* FIXME: error handling & memory cleanup */
hSubMenu = CreateMenu();
if (!hSubMenu) return 0;
hMenu = GetSystemMenu(hWnd, FALSE);
if (!hMenu) return 0;
LoadString(hInstance, IDS_MARK, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff);
LoadString(hInstance, IDS_COPY, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff);
LoadString(hInstance, IDS_PASTE, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff);
LoadString(hInstance, IDS_SELECTALL, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff);
LoadString(hInstance, IDS_SCROLL, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff);
LoadString(hInstance, IDS_SEARCH, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff);
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
LoadString(hInstance, IDS_EDIT, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)hSubMenu, buff);
LoadString(hInstance, IDS_DEFAULT, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff);
LoadString(hInstance, IDS_PROPERTY, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTY, buff);
data->hMemDC = CreateCompatibleDC(0);
if (!data->hMemDC) {Trace(0, "no mem dc\n");return 0;}
return 0;
}
/******************************************************************
* WCUSER_SetMenuDetails
*
* Grays / ungrays the menu items according to their state
*/
static void WCUSER_SetMenuDetails(const struct inner_data* data)
{
HMENU hMenu = GetSystemMenu(data->hWnd, FALSE);
if (!hMenu) {Trace(0, "Issue in getting menu bits\n");return;}
/* FIXME: set the various menu items to their state (if known) */
EnableMenuItem(hMenu, IDS_DEFAULT, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hMenu, IDS_MARK, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hMenu, IDS_COPY, MF_BYCOMMAND|(data->hasSelection ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hMenu, IDS_PASTE,
MF_BYCOMMAND|(IsClipboardFormatAvailable(CF_UNICODETEXT)
? MF_ENABLED : MF_GRAYED));
/* Select all: always active */
EnableMenuItem(hMenu, IDS_SCROLL, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hMenu, IDS_SEARCH, MF_BYCOMMAND|MF_GRAYED);
}
/******************************************************************
* WCUSER_GenerateInputRecord
*
* generates input_record from windows WM_KEYUP/WM_KEYDOWN messages
*/
static void WCUSER_GenerateInputRecord(struct inner_data* data, BOOL down,
WPARAM wParam, LPARAM lParam, BOOL sys)
{
INPUT_RECORD ir;
DWORD n;
WCHAR buf[2];
BYTE keyState[256];
static WCHAR last; /* keep last char seen as feed for key up message */
ir.EventType = KEY_EVENT;
ir.Event.KeyEvent.bKeyDown = down;
ir.Event.KeyEvent.wRepeatCount = LOWORD(lParam);
ir.Event.KeyEvent.wVirtualKeyCode = wParam;
ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lParam) & 0xFF;
GetKeyboardState(keyState);
ir.Event.KeyEvent.uChar.UnicodeChar = 0;
ir.Event.KeyEvent.dwControlKeyState = 0;
if (lParam & (1L << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
if (keyState[VK_SHIFT] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
if (keyState[VK_CONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; /* FIXME: gotta choose one */
if (keyState[VK_LCONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED;
if (keyState[VK_RCONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
if (sys) ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; /* FIXME: gotta choose one */
if (keyState[VK_LMENU] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED;
if (keyState[VK_RMENU] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
if (keyState[VK_CAPITAL] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= CAPSLOCK_ON;
if (keyState[VK_NUMLOCK] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= NUMLOCK_ON;
if (keyState[VK_SCROLL] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= SCROLLLOCK_ON;
if (data->hasSelection && ir.Event.KeyEvent.dwControlKeyState == 0 &&
ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN)
{
data->hasSelection = FALSE;
WCUSER_SetSelection(data, 0);
WCUSER_CopySelectionToClipboard(data);
return;
}
if (!(ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
{
if (down)
{
switch (ToUnicode(wParam, HIWORD(lParam), keyState, buf, 2, 0))
{
case 2:
/* FIXME... should generate two events... */
/* fall thru */
case 1:
last = buf[0];
break;
default:
last = 0;
break;
}
}
ir.Event.KeyEvent.uChar.UnicodeChar = last; /* FIXME HACKY... and buggy 'coz it should be a stack, not a single value */
if (!down) last = 0;
}
WriteConsoleInput(data->hConIn, &ir, 1, &n);
}
/******************************************************************
* WCUSER_Proc
*
*
*/
static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
struct inner_data* data = (struct inner_data*)GetWindowLong(hWnd, 0);
switch (uMsg)
{
case WM_CREATE:
return WCUSER_Create(hWnd, (LPCREATESTRUCT)lParam);
case WM_DESTROY:
data->hWnd = 0;
PostQuitMessage(0);
break;
case WM_PAINT:
WCUSER_Paint(data);
break;
case WM_KEYDOWN:
case WM_KEYUP:
WCUSER_GenerateInputRecord(data, uMsg == WM_KEYDOWN, wParam, lParam, FALSE);
break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
WCUSER_GenerateInputRecord(data, uMsg == WM_SYSKEYDOWN, wParam, lParam, TRUE);
break;
case WM_LBUTTONDOWN:
/* EPP if (wParam != MK_LBUTTON) */
if (data->hasSelection)
{
data->hasSelection = FALSE;
}
else
{
data->selectPt1 = data->selectPt2 = WCUSER_GetCell(data, lParam);
SetCapture(data->hWnd);
}
WCUSER_SetSelection(data, 0);
break;
case WM_MOUSEMOVE:
/* EPP if (wParam != MK_LBUTTON) */
if (GetCapture() == data->hWnd)
{
WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), FALSE);
}
break;
case WM_LBUTTONUP:
/* EPP if (wParam != MK_LBUTTON) */
if (GetCapture() == data->hWnd)
{
WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), TRUE);
}
break;
case WM_SETFOCUS:
if (data->cursor_visible)
{
CreateCaret(data->hWnd, data->cursor_bitmap, data->cell_width, data->cell_height);
WCUSER_PosCursor(data);
}
break;
case WM_KILLFOCUS:
if (data->cursor_visible)
DestroyCaret();
break;
case WM_HSCROLL:
{
int pos = data->win_pos.X;
switch (LOWORD(wParam))
{
case SB_PAGEUP: pos -= 8; break;
case SB_PAGEDOWN: pos += 8; break;
case SB_LINEUP: pos--; break;
case SB_LINEDOWN: pos++; break;
case SB_THUMBTRACK: pos = HIWORD(wParam); break;
default: break;
}
if (pos < 0) pos = 0;
if (pos > data->sb_width - data->win_width) pos = data->sb_width - data->win_width;
if (pos != data->win_pos.X)
{
ScrollWindow(hWnd, (data->win_pos.X - pos) * data->cell_width, 0, NULL, NULL);
data->win_pos.X = pos;
SetScrollPos(hWnd, SB_HORZ, pos, TRUE);
UpdateWindow(hWnd);
WCUSER_PosCursor(data);
WINECON_NotifyWindowChange(data);
}
}
break;
case WM_VSCROLL:
{
int pos = data->win_pos.Y;
switch (LOWORD(wParam))
{
case SB_PAGEUP: pos -= 8; break;
case SB_PAGEDOWN: pos += 8; break;
case SB_LINEUP: pos--; break;
case SB_LINEDOWN: pos++; break;
case SB_THUMBTRACK: pos = HIWORD(wParam); break;
default: break;
}
if (pos < 0) pos = 0;
if (pos > data->sb_height - data->win_height) pos = data->sb_height - data->win_height;
if (pos != data->win_pos.Y)
{
ScrollWindow(hWnd, 0, (data->win_pos.Y - pos) * data->cell_height, NULL, NULL);
data->win_pos.Y = pos;
SetScrollPos(hWnd, SB_VERT, pos, TRUE);
UpdateWindow(hWnd);
WCUSER_PosCursor(data);
WINECON_NotifyWindowChange(data);
}
}
break;
case WM_SYSCOMMAND:
switch (wParam)
{
case IDS_DEFAULT:
Trace(0, "unhandled yet command: %x\n", wParam);
break;
case IDS_PROPERTY:
WCUSER_GetProperties(data);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
break;
case WM_RBUTTONDOWN:
WCUSER_GetProperties(data);
break;
case WM_COMMAND:
switch (wParam)
{
case IDS_MARK:
goto niy;
case IDS_COPY:
data->hasSelection = FALSE;
WCUSER_SetSelection(data, 0);
WCUSER_CopySelectionToClipboard(data);
break;
case IDS_PASTE:
WCUSER_PasteFromClipboard(data);
break;
case IDS_SELECTALL:
data->selectPt1.X = data->selectPt1.Y = 0;
data->selectPt2.X = (data->sb_width - 1) * data->cell_width;
data->selectPt2.Y = (data->sb_height - 1) * data->cell_height;
WCUSER_SetSelection(data, 0);
data->hasSelection = TRUE;
break;
case IDS_SCROLL:
case IDS_SEARCH:
niy:
Trace(0, "unhandled yet command: %x\n", wParam);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
break;
case WM_INITMENUPOPUP:
if (!HIWORD(lParam)) return DefWindowProc(hWnd, uMsg, wParam, lParam);
WCUSER_SetMenuDetails(data);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
/******************************************************************
* WCUSER_DeleteBackend
*
*
*/
void WCUSER_DeleteBackend(struct inner_data* data)
{
if (data->hWnd) DestroyWindow(data->hWnd);
if (data->hFont) DeleteObject(data->hFont);
if (data->cursor_bitmap) DeleteObject(data->cursor_bitmap);
if (data->hMemDC) DeleteDC(data->hMemDC);
if (data->hBitmap) DeleteObject(data->hBitmap);
}
/******************************************************************
* WCUSER_MainLoop
*
*
*/
static int WCUSER_MainLoop(struct inner_data* data)
{
MSG msg;
for (;;)
{
switch (MsgWaitForMultipleObjects(1, &data->hSynchro, FALSE, INFINITE, QS_ALLINPUT))
{
case WAIT_OBJECT_0:
if (!WINECON_GrabChanges(data))
PostQuitMessage(0);
break;
case WAIT_OBJECT_0+1:
switch (GetMessage(&msg, 0, 0, 0))
{
case -1: /* the event handle became invalid, so exit */
return -1;
case 0: /* WM_QUIT has been posted */
return 0;
default:
DispatchMessage(&msg);
break;
}
break;
default:
Trace(0, "got pb\n");
/* err */
break;
}
}
}
/******************************************************************
* WCUSER_InitBackend
*
* Initialisation part II: creation of window.
*
*/
BOOL WCUSER_InitBackend(struct inner_data* data)
{
static WCHAR wClassName[] = {'W','i','n','e','C','o','n','s','o','l','e','C','l','a','s','s',0};
WNDCLASS wndclass;
struct font_chooser fc;
data->fnMainLoop = WCUSER_MainLoop;
data->fnPosCursor = WCUSER_PosCursor;
data->fnShapeCursor = WCUSER_ShapeCursor;
data->fnComputePositions = WCUSER_ComputePositions;
data->fnRefresh = WCUSER_Refresh;
data->fnResizeScreenBuffer = WCUSER_ResizeScreenBuffer;
data->fnSetTitle = WCUSER_SetTitle;
data->fnScroll = WCUSER_Scroll;
data->fnDeleteBackend = WCUSER_DeleteBackend;
wndclass.style = 0;
wndclass.lpfnWndProc = WCUSER_Proc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(DWORD);
wndclass.hInstance = GetModuleHandle(NULL);
wndclass.hIcon = LoadIcon(0, IDI_WINLOGO);
wndclass.hCursor = LoadCursor(0, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = wClassName;
RegisterClass(&wndclass);
CreateWindow(wndclass.lpszClassName, NULL,
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_HSCROLL|WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, 0, wndclass.hInstance, data);
if (!data->hWnd) return FALSE;
/* force update of current data */
WINECON_GrabChanges(data);
/* try to find an acceptable font */
fc.data = data;
fc.done = 0;
EnumFontFamilies(data->hMemDC, NULL, get_first_font_enum, (LPARAM)&fc);
return fc.done;
}
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
#include <wincon.h>
#include "wineconsole_res.h"
struct inner_data {
unsigned sb_width; /* active screen buffer width */
unsigned sb_height; /* active screen buffer height */
CHAR_INFO* cells; /* local copy of cells (sb_width * sb_height) */
COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
unsigned win_width; /* size (in cells) of visible part of window (width & height) */
unsigned win_height;
COORD cursor; /* position in cells of cursor */
int cursor_visible;
int cursor_size; /* in % of cell height */
HANDLE hConIn; /* console input handle */
HANDLE hConOut; /* screen buffer handle: has to be changed when active sb changes */
HANDLE hSynchro; /* waitable handle signalled by server when something in server has been modified */
int (*fnMainLoop)(struct inner_data* data);
void (*fnPosCursor)(const struct inner_data* data);
void (*fnShapeCursor)(struct inner_data* data, int size, int vis, BOOL force);
void (*fnComputePositions)(struct inner_data* data);
void (*fnRefresh)(const struct inner_data* data, int tp, int bm);
void (*fnResizeScreenBuffer)(struct inner_data* data);
void (*fnSetTitle)(const struct inner_data* data);
void (*fnScroll)(struct inner_data* data, int pos, BOOL horz);
void (*fnDeleteBackend)(struct inner_data* data);
/* the following fields are only user by the USER backend (should be hidden in user) */
HWND hWnd; /* handle to windows for rendering */
HFONT hFont; /* font used for rendering, usually fixed */
LOGFONT logFont; /* logFont dscription for used hFont */
unsigned cell_width; /* width in pixels of a character */
unsigned cell_height; /* height in pixels of a character */
HDC hMemDC; /* memory DC holding the bitmap below */
HBITMAP hBitmap; /* bitmap of display window content */
HBITMAP cursor_bitmap; /* bitmap used for the caret */
BOOL hasSelection; /* a rectangular mouse selection has taken place */
COORD selectPt1; /* start (and end) point of a mouse selection */
COORD selectPt2;
};
# ifdef __GNUC__
extern void XTracer(int level, const char* format, ...) __attribute__((format (printf,2,3)));
# else
extern void XTracer(int level, const char* format, ...);
# endif
#if 0
/* Trace mode */
# define Trace XTracer
#else
/* non trace mode */
# define Trace (1) ? (void)0 : XTracer
#endif
extern void WINECON_NotifyWindowChange(struct inner_data* data);
extern int WINECON_GetHistorySize(HANDLE hConIn);
extern BOOL WINECON_SetHistorySize(HANDLE hConIn, int size);
extern int WINECON_GetHistoryMode(HANDLE hConIn);
extern BOOL WINECON_SetHistoryMode(HANDLE hConIn, int mode);
extern BOOL WINECON_GetConsoleTitle(HANDLE hConIn, WCHAR* buffer, size_t len);
extern void WINECON_FetchCells(struct inner_data* data, int upd_tp, int upd_bm);
extern int WINECON_GrabChanges(struct inner_data* data);
extern BOOL WCUSER_GetProperties(struct inner_data*);
extern BOOL WCUSER_SetFont(struct inner_data* data, const LOGFONT* font, const TEXTMETRIC* tm);
extern BOOL WCUSER_ValidateFont(const struct inner_data* data, const LOGFONT* lf);
extern BOOL WCUSER_ValidateFontMetric(const struct inner_data* data, const TEXTMETRIC* tm);
extern BOOL WCUSER_InitBackend(struct inner_data* data);
/*
* an application for displaying Win32 console
*
* Copyright 2001 Eric Pouech
*/
#include <stdio.h>
#include <wine/server.h>
#include "winecon_private.h"
static int trace_level = 1;
void XTracer(int level, const char* format, ...)
{
char buf[1024];
va_list valist;
int len;
if (level > trace_level) return;
va_start(valist, format);
len = wvsnprintfA(buf, sizeof(buf), format, valist);
va_end(valist);
if (len <= -1)
{
len = sizeof(buf) - 1;
buf[len] = 0;
buf[len - 1] = buf[len - 2] = buf[len - 3] = '.';
}
fprintf(stderr, buf);
}
/******************************************************************
* WINECON_FetchCells
*
* updates the local copy of cells (band to update)
*/
void WINECON_FetchCells(struct inner_data* data, int upd_tp, int upd_bm)
{
int step;
int j, nr;
step = REQUEST_MAX_VAR_SIZE / (data->sb_width * 4);
for (j = upd_tp; j <= upd_bm; j += step)
{
nr = min(step, upd_bm - j + 1);
SERVER_START_VAR_REQ( read_console_output, 4 * nr * data->sb_width )
{
req->handle = (handle_t)data->hConOut;
req->x = 0;
req->y = j;
req->w = data->sb_width;
req->h = nr;
if (!SERVER_CALL_ERR())
{
if (data->sb_width != req->eff_w || nr != req->eff_h)
Trace(0, "pb here... wrong eff_w %d/%d or eff_h %d/%d\n",
req->eff_w, data->sb_width, req->eff_h, nr);
memcpy(&data->cells[j * data->sb_width], server_data_ptr(req),
4 * nr * data->sb_width);
}
}
SERVER_END_VAR_REQ;
}
data->fnRefresh(data, upd_tp, upd_bm);
}
/******************************************************************
* WINECON_NotifyWindowChange
*
* Inform server that visible window on sb has changed
*/
void WINECON_NotifyWindowChange(struct inner_data* data)
{
SERVER_START_REQ( set_console_output_info )
{
req->handle = (handle_t)data->hConOut;
req->win_left = data->win_pos.X;
req->win_top = data->win_pos.Y;
req->win_right = data->win_pos.X + data->win_width - 1;
req->win_bottom = data->win_pos.Y + data->win_height - 1;
req->mask = SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW;
if (!SERVER_CALL_ERR())
{
}
}
SERVER_END_REQ;
}
/******************************************************************
* WINECON_GetHistorySize
*
*
*/
int WINECON_GetHistorySize(HANDLE hConIn)
{
int ret = 0;
SERVER_START_REQ(get_console_input_info)
{
req->handle = (handle_t)hConIn;
if (!SERVER_CALL_ERR()) ret = req->history_size;
}
SERVER_END_REQ;
return ret;
}
/******************************************************************
* WINECON_SetHistorySize
*
*
*/
BOOL WINECON_SetHistorySize(HANDLE hConIn, int size)
{
BOOL ret;
SERVER_START_REQ(set_console_input_info)
{
req->handle = (handle_t)hConIn;
req->mask = SET_CONSOLE_INPUT_INFO_HISTORY_SIZE;
req->history_size = size;
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
return ret;
}
/******************************************************************
* WINECON_GetHistoryMode
*
*
*/
int WINECON_GetHistoryMode(HANDLE hConIn)
{
int ret = 0;
SERVER_START_REQ(get_console_input_info)
{
req->handle = (handle_t)hConIn;
if (!SERVER_CALL_ERR()) ret = req->history_mode;
}
SERVER_END_REQ;
return ret;
}
/******************************************************************
* WINECON_SetHistoryMode
*
*
*/
BOOL WINECON_SetHistoryMode(HANDLE hConIn, int mode)
{
BOOL ret;
SERVER_START_REQ(set_console_input_info)
{
req->handle = (handle_t)hConIn;
req->mask = SET_CONSOLE_INPUT_INFO_HISTORY_MODE;
req->history_mode = mode;
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
return ret;
}
/******************************************************************
* WINECON_GetConsoleTitle
*
*
*/
BOOL WINECON_GetConsoleTitle(HANDLE hConIn, WCHAR* buffer, size_t len)
{
BOOL ret;
DWORD size = 0;
SERVER_START_VAR_REQ(get_console_input_info, sizeof(buffer))
{
req->handle = (handle_t)hConIn;
if ((ret = !SERVER_CALL_ERR()))
{
size = min(len - sizeof(WCHAR), server_data_size(req));
memcpy(buffer, server_data_ptr(req), size);
buffer[size / sizeof(WCHAR)] = 0;
}
}
SERVER_END_VAR_REQ;
return ret;
}
/******************************************************************
* WINECON_GrabChanges
*
* A change occurs, try to figure out which
*/
int WINECON_GrabChanges(struct inner_data* data)
{
struct console_renderer_event evts[16];
int i, num;
HANDLE h;
SERVER_START_VAR_REQ( get_console_renderer_events, sizeof(evts) )
{
req->handle = (handle_t)data->hSynchro;
if (!SERVER_CALL_ERR())
{
num = server_data_size(req);
memcpy(evts, server_data_ptr(req), num);
num /= sizeof(evts[0]);
}
else num = 0;
}
SERVER_END_VAR_REQ;
if (!num) {Trace(0, "hmm renderer signaled but no events available\n"); return 1;}
/* FIXME: should do some event compression here (cursor pos, update) */
Trace(1, "Change notification:");
for (i = 0; i < num; i++)
{
switch (evts[i].event)
{
case CONSOLE_RENDERER_TITLE_EVENT:
data->fnSetTitle(data);
break;
case CONSOLE_RENDERER_ACTIVE_SB_EVENT:
SERVER_START_REQ( open_console )
{
req->from = (int)data->hConIn;
req->access = GENERIC_READ | GENERIC_WRITE;
req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
req->inherit = FALSE;
h = SERVER_CALL_ERR() ? 0 : (HANDLE)req->handle;
}
SERVER_END_REQ;
Trace(1, " active(%d)", (int)h);
if (h)
{
CloseHandle(data->hConOut);
data->hConOut = h;
}
break;
case CONSOLE_RENDERER_SB_RESIZE_EVENT:
if (data->sb_width != evts[i].u.resize.width ||
data->sb_height != evts[i].u.resize.height)
{
Trace(1, " resize(%d,%d)", evts[i].u.resize.width, evts[i].u.resize.height);
data->sb_width = evts[i].u.resize.width;
data->sb_height = evts[i].u.resize.height;
data->cells = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data->cells,
data->sb_width * data->sb_height * sizeof(CHAR_INFO));
if (!data->cells) {Trace(0, "OOM\n"); exit(0);}
data->fnResizeScreenBuffer(data);
data->fnComputePositions(data);
}
break;
case CONSOLE_RENDERER_UPDATE_EVENT:
Trace(1, " update(%d,%d)", evts[i].u.update.top, evts[i].u.update.bottom);
WINECON_FetchCells(data, evts[i].u.update.top, evts[i].u.update.bottom);
break;
case CONSOLE_RENDERER_CURSOR_POS_EVENT:
if (evts[i].u.cursor_pos.x != data->cursor.X || evts[i].u.cursor_pos.y != data->cursor.Y)
{
data->cursor.X = evts[i].u.cursor_pos.x;
data->cursor.Y = evts[i].u.cursor_pos.y;
data->fnPosCursor(data);
Trace(1, " curs-pos(%d,%d)",evts[i].u.cursor_pos.x, evts[i].u.cursor_pos.y);
}
break;
case CONSOLE_RENDERER_CURSOR_GEOM_EVENT:
if (evts[i].u.cursor_geom.size != data->cursor_size ||
evts[i].u.cursor_geom.visible != data->cursor_visible)
{
data->fnShapeCursor(data, evts[i].u.cursor_geom.size,
evts[i].u.cursor_geom.visible, FALSE);
Trace(1, " curs-geom(%d,%d)",
evts[i].u.cursor_geom.size, evts[i].u.cursor_geom.visible);
}
break;
case CONSOLE_RENDERER_DISPLAY_EVENT:
if (evts[i].u.display.left != data->win_pos.X)
{
data->fnScroll(data, evts[i].u.display.left, TRUE);
data->fnPosCursor(data);
Trace(1, " h-scroll(%d)", evts[i].u.display.left);
}
if (evts[i].u.display.top != data->win_pos.Y)
{
data->fnScroll(data, evts[i].u.display.top, FALSE);
data->fnPosCursor(data);
Trace(1, " v-scroll(%d)", evts[i].u.display.top);
}
if (evts[i].u.display.width != data->win_width ||
evts[i].u.display.height != data->win_height)
{
Trace(1, " win-size(%d,%d)", evts[i].u.display.width, evts[i].u.display.height);
data->win_width = evts[i].u.display.width;
data->win_height = evts[i].u.display.height;
data->fnComputePositions(data);
}
break;
case CONSOLE_RENDERER_EXIT_EVENT:
Trace(1, ". Exit!!\n");
return 0;
default:
Trace(0, "Unknown event type (%d)\n", evts[i].event);
}
}
Trace(1, ". Done\n");
return 1;
}
/******************************************************************
* WINECON_Delete
*
* Destroy wineconsole internal data
*/
static void WINECON_Delete(struct inner_data* data)
{
if (!data) return;
if (data->hConIn) CloseHandle(data->hConIn);
if (data->hConOut) CloseHandle(data->hConOut);
if (data->hSynchro) CloseHandle(data->hSynchro);
if (data->cells) HeapFree(GetProcessHeap(), 0, data->cells);
data->fnDeleteBackend(data);
HeapFree(GetProcessHeap(), 0, data);
}
/******************************************************************
* WINECON_Init
*
* Initialisation part I. Creation of server object (console input and
* active screen buffer)
*/
static struct inner_data* WINECON_Init(HINSTANCE hInst, void* pid)
{
struct inner_data* data = NULL;
DWORD ret;
WCHAR szTitle[] = {'W','i','n','e',' ','c','o','n','s','o','l','e',0};
size_t len;
data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
if (!data) return 0;
/* the handles here are created without the whistles and bells required by console
* (mainly because wineconsole doesn't need it)
* - there are not inheritable
* - hConIn is not synchronizable
*/
SERVER_START_REQ(alloc_console)
{
req->access = GENERIC_READ | GENERIC_WRITE;
req->inherit = FALSE;
req->pid = pid;
ret = !SERVER_CALL_ERR();
data->hConIn = (HANDLE)req->handle_in;
data->hSynchro = (HANDLE)req->event;
}
SERVER_END_REQ;
if (!ret) goto error;
len = lstrlenW(szTitle) * sizeof(WCHAR);
len = min(len, REQUEST_MAX_VAR_SIZE);
SERVER_START_VAR_REQ(set_console_input_info, len)
{
req->handle = (handle_t)data->hConIn;
req->mask = SET_CONSOLE_INPUT_INFO_TITLE;
memcpy(server_data_ptr(req), szTitle, len);
ret = !SERVER_CALL_ERR();
}
SERVER_END_VAR_REQ;
if (ret)
{
SERVER_START_REQ(create_console_output)
{
req->handle_in = (handle_t)data->hConIn;
req->access = GENERIC_WRITE|GENERIC_READ;
req->share = FILE_SHARE_READ|FILE_SHARE_WRITE;
req->inherit = FALSE;
data->hConOut = (HANDLE)(SERVER_CALL_ERR() ? 0 : req->handle_out);
}
SERVER_END_REQ;
if (data->hConOut) return data;
}
error:
WINECON_Delete(data);
return NULL;
}
/******************************************************************
* WINECON_Spawn
*
* Spawn the child processus when invoked with wineconsole foo bar
*/
static BOOL WINECON_Spawn(struct inner_data* data, LPCSTR lpCmdLine)
{
PROCESS_INFORMATION info;
STARTUPINFO startup;
LPWSTR ptr = GetCommandLine(); /* we're unicode... */
BOOL done;
/* we're in the case wineconsole <exe> <options>... spawn the new process */
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
startup.wShowWindow = SW_SHOWNORMAL;
/* the attributes of wineconsole's handles are not adequate for inheritance, so
* get them with the correct attributes before process creation
*/
if (!DuplicateHandle(GetCurrentProcess(), data->hConIn, GetCurrentProcess(),
&startup.hStdInput, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, TRUE, 0) ||
!DuplicateHandle(GetCurrentProcess(), data->hConOut, GetCurrentProcess(),
&startup.hStdOutput, GENERIC_READ|GENERIC_WRITE, TRUE, 0) ||
!DuplicateHandle(GetCurrentProcess(), data->hConOut, GetCurrentProcess(),
&startup.hStdError, GENERIC_READ|GENERIC_WRITE, TRUE, 0))
{
Trace(0, "can't dup handles\n");
/* no need to delete handles, we're exiting the programm anyway */
return FALSE;
}
/* we could have several ' ' in process command line... so try first space...
* FIXME:
* the correct way would be to check the existence of the left part of ptr
* (to be a file)
*/
while (*ptr && *ptr++ != ' ');
done = *ptr && CreateProcess(NULL, ptr, NULL, NULL, TRUE, 0L, NULL, NULL, &startup, &info);
/* we no longer need the handles passed to the child for the console */
CloseHandle(startup.hStdInput);
CloseHandle(startup.hStdOutput);
CloseHandle(startup.hStdError);
return done;
}
/******************************************************************
* WINECON_WinMain
*
* wineconsole can either be started as:
* wineconsole <int> used when a new console is created (AllocConsole)
* wineconsole <pgm> <arguments> used to start the program <pgm> from the command line in
* a freshly created console
*/
int PASCAL WINECON_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPCSTR lpCmdLine, UINT nCmdShow)
{
struct inner_data* data;
int ret = 1;
unsigned evt;
/* case of wineconsole <evt>, signal process that created us that we're up and running */
if (sscanf(lpCmdLine, "%d", &evt) == 1)
{
if (!(data = WINECON_Init(hInst, 0))) return 0;
ret = SetEvent((HANDLE)evt);
}
else
{
if (!(data = WINECON_Init(hInst, (void*)GetCurrentProcessId()))) return 0;
ret = WINECON_Spawn(data, lpCmdLine);
}
if (ret && WCUSER_InitBackend(data))
{
ret = data->fnMainLoop(data);
}
WINECON_Delete(data);
return ret;
}
name wineconsole
mode guiexe
type win32
init WINECON_WinMain
rsrc wineconsole_res.res
import -delay comctl32
import gdi32.dll
import user32.dll
#import advapi32.dll
import kernel32.dll
import ntdll.dll
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
STRINGTABLE LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
BEGIN
IDS_EDIT, "&Edit"
IDS_DEFAULT, "&Default"
IDS_PROPERTY, "&Property"
IDS_MARK, "&Mark"
IDS_COPY, "&Copy"
IDS_PASTE, "&Paste"
IDS_SELECTALL, "&Select all"
IDS_SCROLL, "Sc&roll"
IDS_SEARCH, "S&earch"
IDS_FNT_DISPLAY, "Each character is %ld pixels wide on %ld pixels high"
IDS_FNT_PREVIEW_1, "This is a test"
IDS_FNT_PREVIEW_2, ""
END
IDD_OPTION DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION " Options "
FONT 8, "Helv"
{
GROUPBOX "Cursor size", -1, 10, 11, 120, 44, BS_GROUPBOX
AUTORADIOBUTTON "&Small", IDC_OPT_CURSOR_SMALL, 14, 23, 84, 10, WS_TABSTOP
AUTORADIOBUTTON "&Medium", IDC_OPT_CURSOR_MEDIUM, 14, 33, 84, 10, WS_TABSTOP
AUTORADIOBUTTON "&Large", IDC_OPT_CURSOR_LARGE, 14, 43, 84, 10, WS_TABSTOP
GROUPBOX "Command history", -1, 10, 57, 180, 35, BS_GROUPBOX
LTEXT "&Numbers of recalled commands :", -1, 14, 67, 78, 18
EDITTEXT IDC_OPT_HIST_SIZE, 92, 69, 31, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_OPT_HIST_SIZE_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
AUTOCHECKBOX "&Remove doubles", IDC_OPT_HIST_DOUBLE, 130, 67, 50, 18, WS_TABSTOP|BS_MULTILINE
}
IDD_FONT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION " Font "
FONT 8, "Helv"
{
LTEXT "&Font", -1, 5, 5, 24, 8
LISTBOX IDC_FNT_LIST_FONT, 5,18,109,42, LBS_SORT|WS_VSCROLL
LTEXT "&Size", -1, 128, 5, 60, 8
LISTBOX IDC_FNT_LIST_SIZE, 128, 18, 50, 60, WS_VSCROLL
CONTROL "", IDC_FNT_PREVIEW, "WineConFontPreview", 0L, 5,60,109,40
LTEXT "", IDC_FNT_FONT_INFO, 128, 76, 80, 18
}
IDD_CONFIG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION " Configuration "
FONT 8, "Helv"
{
GROUPBOX "Buffer zone", -1, 10, 11, 110, 42, BS_GROUPBOX
LTEXT "&Width :", -1, 14, 25, 54, 9
EDITTEXT IDC_CNF_SB_WIDTH, 78, 23, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_CNF_SB_WIDTH_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
LTEXT "&Height :", -1, 14, 39, 54, 9
EDITTEXT IDC_CNF_SB_HEIGHT, 78, 37, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_CNF_SB_HEIGHT_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
GROUPBOX "Window size", -1, 10, 55, 110, 42
LTEXT "W&idth :", -1, 14, 69, 54, 9
EDITTEXT IDC_CNF_WIN_WIDTH, 78, 67, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_CNF_WIN_WIDTH_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
LTEXT "H&eight :", -1, 14, 83, 54, 9
EDITTEXT IDC_CNF_WIN_HEIGHT, 78, 81, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_CNF_WIN_HEIGHT_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
}
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
STRINGTABLE LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
BEGIN
IDS_EDIT, "&Editer"
IDS_DEFAULT, "Par &dfaut"
IDS_PROPERTY, "&Proprits"
IDS_MARK, "&Marquer"
IDS_COPY, "&Copier"
IDS_PASTE, "C&oller"
IDS_SELECTALL, "&Slectionner tout"
IDS_SCROLL, "&Dfiler"
IDS_SEARCH, "C&hercher"
IDS_FNT_DISPLAY, "Chaque caractre a %ld points en largeur et %ld points en hauteur"
IDS_FNT_PREVIEW_1, "Ceci est un test"
IDS_FNT_PREVIEW_2, ""
END
IDD_OPTION DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION " Options "
FONT 8, "Helv"
{
GROUPBOX "Taille du curseur", -1, 10, 11, 120, 44, BS_GROUPBOX
AUTORADIOBUTTON "&Petit", IDC_OPT_CURSOR_SMALL, 14, 23, 84, 10, WS_TABSTOP
AUTORADIOBUTTON "&Moyen", IDC_OPT_CURSOR_MEDIUM, 14, 33, 84, 10, WS_TABSTOP
AUTORADIOBUTTON "&Grand", IDC_OPT_CURSOR_LARGE, 14, 43, 84, 10, WS_TABSTOP
GROUPBOX "Historique des commandes", -1, 10, 57, 180, 35, BS_GROUPBOX
LTEXT "&Taille de la mmoire tampon :", -1, 14, 67, 78, 18
EDITTEXT IDC_OPT_HIST_SIZE, 92, 69, 31, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_OPT_HIST_SIZE_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
AUTOCHECKBOX "&Supprimer les doublons", IDC_OPT_HIST_DOUBLE, 130, 67, 50, 18, WS_TABSTOP|BS_MULTILINE
}
IDD_FONT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION " Police "
FONT 8, "Helv"
{
LTEXT "&Police", -1, 5, 5, 24, 8
LISTBOX IDC_FNT_LIST_FONT, 5, 18, 109, 42, LBS_SORT|WS_VSCROLL
LTEXT "&Taille", -1, 128, 5, 60, 8
LISTBOX IDC_FNT_LIST_SIZE, 128, 18, 50, 60, WS_VSCROLL
CONTROL "", IDC_FNT_PREVIEW, "WineConFontPreview", 0L, 5, 60, 109, 40
LTEXT "", IDC_FNT_FONT_INFO, 128, 76, 80, 18
}
IDD_CONFIG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION " Configuration "
FONT 8, "Helv"
{
GROUPBOX "Taille mmoire tampon cran", -1, 10, 11, 110, 42, BS_GROUPBOX
LTEXT "&Largeur :", -1, 14, 25, 54, 9
EDITTEXT IDC_CNF_SB_WIDTH, 78, 23, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_CNF_SB_WIDTH_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
LTEXT "Ha&uteur :", -1, 14, 39, 54, 9
EDITTEXT IDC_CNF_SB_HEIGHT, 78, 37, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_CNF_SB_HEIGHT_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
GROUPBOX "Taille de la fentre", -1, 10, 55, 110, 42
LTEXT "La&rgeur :", -1, 14, 69, 54, 9
EDITTEXT IDC_CNF_WIN_WIDTH, 78, 67, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_CNF_WIN_WIDTH_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
LTEXT "Hau&teur :", -1, 14, 83, 54, 9
EDITTEXT IDC_CNF_WIN_HEIGHT, 78, 81, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
CONTROL "", IDC_CNF_WIN_HEIGHT_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
}
/* wineconsole resource definitions */
/* strings */
#define IDS_EDIT 0x100
#define IDS_DEFAULT 0x101
#define IDS_PROPERTY 0x102
#define IDS_MARK 0x110
#define IDS_COPY 0x111
#define IDS_PASTE 0x112
#define IDS_SELECTALL 0x113
#define IDS_SCROLL 0x114
#define IDS_SEARCH 0x115
#define IDS_FNT_DISPLAY 0x200
#define IDS_FNT_PREVIEW_1 0x201
#define IDS_FNT_PREVIEW_2 0x202
#define IDD_OPTION 0x0100
#define IDD_FONT 0x0200
#define IDD_CONFIG 0x0300
/* dialog boxes */
#define IDC_OPT_CURSOR_SMALL 0x0101
#define IDC_OPT_CURSOR_MEDIUM 0x0102
#define IDC_OPT_CURSOR_LARGE 0x0103
#define IDC_OPT_HIST_SIZE 0x0104
#define IDC_OPT_HIST_SIZE_UD 0x0105
#define IDC_OPT_HIST_DOUBLE 0x0106
#define IDC_FNT_LIST_FONT 0x0201
#define IDC_FNT_LIST_SIZE 0x0202
#define IDC_FNT_FONT_INFO 0x0203
#define IDC_FNT_PREVIEW 0x0204
#define IDC_CNF_SB_WIDTH 0x0301
#define IDC_CNF_SB_WIDTH_UD 0x0302
#define IDC_CNF_SB_HEIGHT 0x0303
#define IDC_CNF_SB_HEIGHT_UD 0x0304
#define IDC_CNF_WIN_WIDTH 0x0305
#define IDC_CNF_WIN_WIDTH_UD 0x0306
#define IDC_CNF_WIN_HEIGHT 0x0307
#define IDC_CNF_WIN_HEIGHT_UD 0x0308
#include "windef.h"
#include "winuser.h"
#include "winnls.h"
#include "commctrl.h"
#include "wineconsole_res.h"
#include "wineconsole_En.rc"
#include "wineconsole_Fr.rc"
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "file.h" #include "file.h"
#include "thread.h" #include "thread.h"
#include "winerror.h" #include "winerror.h"
#include "wincon.h"
#include "wine/server.h" #include "wine/server.h"
#include "options.h" #include "options.h"
#include "callback.h" #include "callback.h"
...@@ -216,29 +217,6 @@ void PROCESS_CallUserSignalProc( UINT uCode, HMODULE16 hModule ) ...@@ -216,29 +217,6 @@ void PROCESS_CallUserSignalProc( UINT uCode, HMODULE16 hModule )
Callout.UserSignalProc( uCode, GetCurrentProcessId(), dwFlags, hModule ); Callout.UserSignalProc( uCode, GetCurrentProcessId(), dwFlags, hModule );
} }
/***********************************************************************
* set_console_handles
*
* Set the console handles to use stdin/stdout.
*/
static void set_console_handles( HANDLE console )
{
wine_server_send_fd( 0 );
wine_server_send_fd( 1 );
SERVER_START_REQ( set_console_fd )
{
req->handle = console;
req->fd_in = 0;
req->fd_out = 1;
req->pid = 0;
SERVER_CALL();
}
SERVER_END_REQ;
}
/*********************************************************************** /***********************************************************************
* process_init * process_init
* *
...@@ -287,15 +265,28 @@ static BOOL process_init( char *argv[] ) ...@@ -287,15 +265,28 @@ static BOOL process_init( char *argv[] )
SERVER_END_VAR_REQ; SERVER_END_VAR_REQ;
if (!ret) return FALSE; if (!ret) return FALSE;
SetStdHandle( STD_INPUT_HANDLE, current_startupinfo.hStdInput );
SetStdHandle( STD_OUTPUT_HANDLE, current_startupinfo.hStdOutput );
SetStdHandle( STD_ERROR_HANDLE, current_startupinfo.hStdError );
if (create_flags & CREATE_NEW_CONSOLE)
set_console_handles( current_startupinfo.hStdOutput );
/* Create the process heap */ /* Create the process heap */
current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 ); current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
if (create_flags == 0 &&
current_startupinfo.hStdInput == 0 &&
current_startupinfo.hStdOutput == 0 &&
current_startupinfo.hStdError == 0)
{
/* no parent, and no new console requested, create a simple console with bare handles to
* unix stdio input & output streams (aka simple console)
*/
SetStdHandle( STD_INPUT_HANDLE, FILE_DupUnixHandle( 0, GENERIC_READ, TRUE ));
SetStdHandle( STD_OUTPUT_HANDLE, FILE_DupUnixHandle( 1, GENERIC_WRITE, TRUE ));
SetStdHandle( STD_ERROR_HANDLE, FILE_DupUnixHandle( 1, GENERIC_WRITE, TRUE ));
}
else if (!(create_flags & (DETACHED_PROCESS|CREATE_NEW_CONSOLE)))
{
SetStdHandle( STD_INPUT_HANDLE, current_startupinfo.hStdInput );
SetStdHandle( STD_OUTPUT_HANDLE, current_startupinfo.hStdOutput );
SetStdHandle( STD_ERROR_HANDLE, current_startupinfo.hStdError );
}
/* Now we can use the pthreads routines */ /* Now we can use the pthreads routines */
PTHREAD_init_done(); PTHREAD_init_done();
...@@ -305,7 +296,11 @@ static BOOL process_init( char *argv[] ) ...@@ -305,7 +296,11 @@ static BOOL process_init( char *argv[] )
/* Parse command line arguments */ /* Parse command line arguments */
OPTIONS_ParseOptions( argv ); OPTIONS_ParseOptions( argv );
return MAIN_MainInit(); ret = MAIN_MainInit();
if (create_flags & CREATE_NEW_CONSOLE)
AllocConsole();
return ret;
} }
......
...@@ -2,22 +2,15 @@ ...@@ -2,22 +2,15 @@
* Server-side console management * Server-side console management
* *
* Copyright (C) 1998 Alexandre Julliard * Copyright (C) 1998 Alexandre Julliard
* 2001 Eric Pouech
* *
* FIXME: all this stuff is a hack to avoid breaking
* the client-side console support.
*/ */
#include "config.h" #include "config.h"
#include <assert.h> #include <assert.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "winnt.h" #include "winnt.h"
...@@ -26,180 +19,353 @@ ...@@ -26,180 +19,353 @@
#include "handle.h" #include "handle.h"
#include "process.h" #include "process.h"
#include "thread.h"
#include "request.h" #include "request.h"
#include "unicode.h"
struct screen_buffer; #include "console.h"
struct console_input
{
struct object obj; /* object header */
int mode; /* input mode */
struct screen_buffer *output; /* associated screen buffer */
int recnum; /* number of input records */
INPUT_RECORD *records; /* input records */
};
struct screen_buffer
{
struct object obj; /* object header */
int mode; /* output mode */
struct console_input *input; /* associated console input */
int cursor_size; /* size of cursor (percentage filled) */
int cursor_visible;/* cursor visibility flag */
int pid; /* xterm pid (hack) */
char *title; /* console title */
};
static void console_input_dump( struct object *obj, int verbose ); static void console_input_dump( struct object *obj, int verbose );
static int console_input_get_poll_events( struct object *obj );
static int console_input_get_fd( struct object *obj );
static void console_input_destroy( struct object *obj ); static void console_input_destroy( struct object *obj );
static int console_input_signaled( struct object *obj, struct thread *thread );
static void screen_buffer_dump( struct object *obj, int verbose );
static int screen_buffer_get_poll_events( struct object *obj );
static int screen_buffer_get_fd( struct object *obj );
static void screen_buffer_destroy( struct object *obj );
/* common routine */ /* common routine */
static int console_get_info( struct object *obj, struct get_file_info_request *req ); static int console_get_file_info( struct object *obj, struct get_file_info_request *req );
static const struct object_ops console_input_ops = static const struct object_ops console_input_ops =
{ {
sizeof(struct console_input), /* size */ sizeof(struct console_input), /* size */
console_input_dump, /* dump */ console_input_dump, /* dump */
default_poll_add_queue, /* add_queue */ add_queue, /* add_queue */
default_poll_remove_queue, /* remove_queue */ remove_queue, /* remove_queue */
default_poll_signaled, /* signaled */ console_input_signaled, /* signaled */
no_satisfied, /* satisfied */ no_satisfied, /* satisfied */
console_input_get_poll_events, /* get_poll_events */ NULL, /* get_poll_events */
default_poll_event, /* poll_event */ NULL, /* poll_event */
console_input_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
console_get_info, /* get_file_info */ console_get_file_info, /* get_file_info */
console_input_destroy /* destroy */ console_input_destroy /* destroy */
}; };
static void console_input_events_dump( struct object *obj, int verbose );
static void console_input_events_destroy( struct object *obj );
static int console_input_events_signaled( struct object *obj, struct thread *thread );
struct console_input_events
{
struct object obj; /* object header */
int num_alloc; /* number of allocated events */
int num_used; /* number of actually used events */
struct console_renderer_event* events;
};
static const struct object_ops console_input_events_ops =
{
sizeof(struct console_input_events), /* size */
console_input_events_dump, /* dump */
add_queue, /* add_queue */
remove_queue, /* remove_queue */
console_input_events_signaled, /* signaled */
no_satisfied, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
no_get_fd, /* get_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
console_input_events_destroy /* destroy */
};
struct screen_buffer
{
struct object obj; /* object header */
int mode; /* output mode */
struct console_input *input; /* associated console input */
struct screen_buffer *next; /* linked list of all screen buffers */
short int cursor_size; /* size of cursor (percentage filled) */
short int cursor_visible;/* cursor visibility flag */
COORD cursor; /* position of cursor */
short int width; /* size (w-h) of the screen buffer */
short int height;
short int max_width; /* size (w-h) of the window given font size */
short int max_height;
unsigned *data; /* the data for each cell - a width x height matrix */
unsigned short attr; /* default attribute for screen buffer */
SMALL_RECT win; /* current visible window on the screen buffer *
* as seen in wineconsole */
};
static void screen_buffer_dump( struct object *obj, int verbose );
static void screen_buffer_destroy( struct object *obj );
static const struct object_ops screen_buffer_ops = static const struct object_ops screen_buffer_ops =
{ {
sizeof(struct screen_buffer), /* size */ sizeof(struct screen_buffer), /* size */
screen_buffer_dump, /* dump */ screen_buffer_dump, /* dump */
default_poll_add_queue, /* add_queue */ no_add_queue, /* add_queue */
default_poll_remove_queue, /* remove_queue */ NULL, /* remove_queue */
default_poll_signaled, /* signaled */ NULL, /* signaled */
no_satisfied, /* satisfied */ NULL, /* satisfied */
screen_buffer_get_poll_events, /* get_poll_events */ NULL, /* get_poll_events */
default_poll_event, /* poll_event */ NULL, /* poll_event */
screen_buffer_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
console_get_info, /* get_file_info */ console_get_file_info, /* get_file_info */
screen_buffer_destroy /* destroy */ screen_buffer_destroy /* destroy */
}; };
static struct screen_buffer *screen_buffer_list;
/* dumps the renderer events of a console */
static void console_input_events_dump( struct object *obj, int verbose )
{
struct console_input_events *evts = (struct console_input_events *)obj;
assert( obj->ops == &console_input_events_ops );
fprintf( stderr, "Console input events: %d/%d events\n",
evts->num_used, evts->num_alloc );
}
/* destroys the renderer events of a console */
static void console_input_events_destroy( struct object *obj )
{
struct console_input_events *evts = (struct console_input_events *)obj;
assert( obj->ops == &console_input_events_ops );
free( evts->events );
}
static struct object *create_console_input( int fd ) /* the rendere events list is signaled when it's not empty */
static int console_input_events_signaled( struct object *obj, struct thread *thread )
{
struct console_input_events *evts = (struct console_input_events *)obj;
assert( obj->ops == &console_input_events_ops );
return evts->num_used ? 1 : 0;
}
/* add an event to the console's renderer events list */
static void console_input_events_append( struct console_input_events* evts,
struct console_renderer_event* evt)
{
if (!evt) return;
/* to be done even when the renderer generates the events ? */
if (evts->num_used == evts->num_alloc)
{
evts->num_alloc += 16;
evts->events = realloc( evts->events, evts->num_alloc * sizeof(*evt) );
assert(evts->events);
}
evts->events[evts->num_used++] = *evt;
wake_up( &evts->obj, 0 );
}
/* retrieves events from the console's renderer events list */
static size_t console_input_events_get( struct console_input_events* evts,
struct console_renderer_event* evt, size_t num )
{
if (num % sizeof(*evt) != 0)
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
num /= sizeof(*evt);
if (num > evts->num_used)
num = evts->num_used;
memcpy( evt, evts->events, num * sizeof(*evt) );
if (num < evts->num_used)
{
memmove( &evts->events[0], &evts->events[num],
(evts->num_used - num) * sizeof(*evt) );
}
evts->num_used -= num;
return num * sizeof(struct console_renderer_event);
}
static struct console_input_events *create_console_input_events(void)
{
struct console_input_events* evt;
if (!(evt = alloc_object( &console_input_events_ops, -1 ))) return NULL;
evt->num_alloc = evt->num_used = 0;
evt->events = NULL;
return evt;
}
static struct object *create_console_input( struct process* renderer )
{ {
struct console_input *console_input; struct console_input *console_input;
if ((fd = (fd != -1) ? dup(fd) : dup(0)) == -1) if (!(console_input = alloc_object( &console_input_ops, -1 ))) return NULL;
console_input->renderer = renderer;
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
console_input->num_proc = 0;
console_input->active = NULL;
console_input->recnum = 0;
console_input->records = NULL;
console_input->evt = create_console_input_events();
console_input->title = NULL;
console_input->history_size = 50;
console_input->history = calloc( console_input->history_size, sizeof(WCHAR*) );
console_input->history_index = 0;
console_input->history_mode = 0;
if (!console_input->history || !console_input->evt)
{ {
file_set_error(); release_object( console_input );
return NULL; return NULL;
} }
if (!(console_input = alloc_object( &console_input_ops, fd ))) return NULL;
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
console_input->output = NULL;
console_input->recnum = 0;
console_input->records = NULL;
return &console_input->obj; return &console_input->obj;
} }
static struct object *create_console_output( int fd, struct object *input ) static struct object *create_console_output( struct console_input *console_input )
{ {
struct console_input *console_input = (struct console_input *)input;
struct screen_buffer *screen_buffer; struct screen_buffer *screen_buffer;
struct console_renderer_event evt;
int i;
if ((fd = (fd != -1) ? dup(fd) : dup(1)) == -1) if (!(screen_buffer = alloc_object( &screen_buffer_ops, -1 ))) return NULL;
{
file_set_error();
return NULL;
}
if (!(screen_buffer = alloc_object( &screen_buffer_ops, fd ))) return NULL;
screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
screen_buffer->input = console_input; screen_buffer->input = console_input;
screen_buffer->cursor_size = 100; screen_buffer->cursor_size = 100;
screen_buffer->cursor_visible = 1; screen_buffer->cursor_visible = 1;
screen_buffer->pid = 0; screen_buffer->width = 80;
screen_buffer->title = strdup( "Wine console" ); screen_buffer->height = 150;
console_input->output = screen_buffer; screen_buffer->max_width = 80;
return &screen_buffer->obj; screen_buffer->max_height = 25;
} screen_buffer->data = malloc( 4 * screen_buffer->width * screen_buffer->height );
/* fill the buffer with white on black spaces */
/* allocate a console for this process */ for (i = 0; i < screen_buffer->width * screen_buffer->height; i++)
int alloc_console( struct process *process )
{
if (process->console_in || process->console_out)
{ {
set_error( STATUS_ACCESS_DENIED ); screen_buffer->data[i] = 0x00F00020;
return 0;
} }
if ((process->console_in = create_console_input( -1 ))) screen_buffer->cursor.X = 0;
screen_buffer->cursor.Y = 0;
screen_buffer->attr = 0xF0;
screen_buffer->win.Left = 0;
screen_buffer->win.Right = screen_buffer->max_width - 1;
screen_buffer->win.Top = 0;
screen_buffer->win.Bottom = screen_buffer->max_height - 1;
screen_buffer->next = screen_buffer_list;
screen_buffer_list = screen_buffer;
if (!console_input->active)
{ {
if ((process->console_out = create_console_output( -1, process->console_in ))) console_input->active = (struct screen_buffer*)grab_object( screen_buffer );
return 1;
release_object( process->console_in ); /* generate the fist events */
evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT;
console_input_events_append( console_input->evt, &evt );
evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT;
evt.u.resize.width = screen_buffer->width;
evt.u.resize.height = screen_buffer->height;
console_input_events_append( console_input->evt, &evt );
evt.event = CONSOLE_RENDERER_DISPLAY_EVENT;
evt.u.display.left = screen_buffer->win.Left;
evt.u.display.top = screen_buffer->win.Top;
evt.u.display.width = screen_buffer->win.Right - screen_buffer->win.Left + 1;
evt.u.display.height = screen_buffer->win.Bottom - screen_buffer->win.Top + 1;
console_input_events_append( console_input->evt, &evt );
evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
evt.u.update.top = 0;
evt.u.update.bottom = screen_buffer->height - 1;
console_input_events_append( console_input->evt, &evt );
evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT;
evt.u.cursor_geom.size = screen_buffer->cursor_size;
evt.u.cursor_geom.visible = screen_buffer->cursor_visible;
console_input_events_append( console_input->evt, &evt );
evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
evt.u.cursor_pos.x = screen_buffer->cursor.X;
evt.u.cursor_pos.y = screen_buffer->cursor.Y;
console_input_events_append( console_input->evt, &evt );
} }
return 0;
return &screen_buffer->obj;
} }
/* free the console for this process */ /* free the console for this process */
int free_console( struct process *process ) int free_console( struct process *process )
{ {
if (process->console_in) release_object( process->console_in ); struct console_input* console = process->console;
if (process->console_out) release_object( process->console_out );
process->console_in = process->console_out = NULL; if (!console || !console->renderer) return 0;
process->console = NULL;
if (--console->num_proc == 0)
{
/* all processes have terminated... tell the renderer to terminate too */
struct console_renderer_event evt;
evt.event = CONSOLE_RENDERER_EXIT_EVENT;
console_input_events_append( console->evt, &evt );
}
release_object( console );
return 1; return 1;
} }
static int set_console_fd( handle_t handle, int fd_in, int fd_out, int pid ) /* let process inherit the console from parent... this handle two cases :
* 1/ generic console inheritance
* 2/ parent is a renderer which launches process, and process should attach to the console
* renderered by parent
*/
void inherit_console(struct process *parent, struct process *process, handle_t hconin)
{ {
struct console_input *input; int done = 0;
struct screen_buffer *output;
struct object *obj;
if (!(obj = get_handle_obj( current->process, handle, 0, NULL ))) /* if parent is a renderer, then attach current process to its console
return 0; * a bit hacky....
if (obj->ops == &console_input_ops) */
if (hconin)
{ {
input = (struct console_input *)obj; struct console_input* console;
output = input->output;
grab_object( output ); if ((console = (struct console_input*)get_handle_obj( parent, hconin, 0, NULL )))
{
if (console->renderer == parent)
{
process->console = (struct console_input*)grab_object( console );
process->console->num_proc++;
done = 1;
}
release_object( console );
}
} }
else if (obj->ops == &screen_buffer_ops) /* otherwise, if parent has a console, attach child to this console */
if (!done && parent->console)
{ {
output = (struct screen_buffer *)obj; assert(parent->console->renderer);
input = output->input; process->console = (struct console_input*)grab_object( parent->console );
grab_object( input ); process->console->num_proc++;
} }
else }
static struct console_input* console_input_get( handle_t handle, unsigned access )
{
struct console_input* console = 0;
if (handle)
console = (struct console_input *)get_handle_obj( current->process, handle,
access, &console_input_ops );
else if (current->process->console)
{ {
set_error( STATUS_OBJECT_TYPE_MISMATCH ); assert( current->process->console->renderer );
release_object( obj ); console = (struct console_input *)grab_object( current->process->console );
return 0;
} }
/* can't change the fd if someone is waiting on it */ if (!console && !get_error()) set_error(STATUS_INVALID_PARAMETER);
assert( !input->obj.head ); return console;
assert( !output->obj.head ); }
change_select_fd( &input->obj, fd_in ); /* check if a console input is signaled: yes if non read input records */
change_select_fd( &output->obj, fd_out ); static int console_input_signaled( struct object *obj, struct thread *thread )
output->pid = pid; {
release_object( input ); struct console_input *console = (struct console_input *)obj;
release_object( output ); assert( obj->ops == &console_input_ops );
return 1; return console->recnum ? 1 : 0;
} }
static int get_console_mode( handle_t handle ) static int get_console_mode( handle_t handle )
...@@ -220,15 +386,17 @@ static int get_console_mode( handle_t handle ) ...@@ -220,15 +386,17 @@ static int get_console_mode( handle_t handle )
return ret; return ret;
} }
/* changes the mode of either a console input or a screen buffer */
static int set_console_mode( handle_t handle, int mode ) static int set_console_mode( handle_t handle, int mode )
{ {
struct object *obj; struct object *obj;
int ret = 0; int ret = 0;
if (!(obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL ))) if (!(obj = get_handle_obj( current->process, handle, GENERIC_WRITE, NULL )))
return 0; return 0;
if (obj->ops == &console_input_ops) if (obj->ops == &console_input_ops)
{ {
/* FIXME: if we remove the edit mode bits, we need (???) to clean up the history */
((struct console_input *)obj)->mode = mode; ((struct console_input *)obj)->mode = mode;
ret = 1; ret = 1;
} }
...@@ -242,43 +410,12 @@ static int set_console_mode( handle_t handle, int mode ) ...@@ -242,43 +410,12 @@ static int set_console_mode( handle_t handle, int mode )
return ret; return ret;
} }
/* set misc console information (output handle only) */
static int set_console_info( handle_t handle, struct set_console_info_request *req,
const char *title, size_t len )
{
struct screen_buffer *console;
if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
GENERIC_WRITE, &screen_buffer_ops )))
return 0;
if (req->mask & SET_CONSOLE_INFO_CURSOR)
{
console->cursor_size = req->cursor_size;
console->cursor_visible = req->cursor_visible;
}
if (req->mask & SET_CONSOLE_INFO_TITLE)
{
char *new_title = mem_alloc( len + 1 );
if (new_title)
{
memcpy( new_title, title, len );
new_title[len] = 0;
if (console->title) free( console->title );
console->title = new_title;
}
}
release_object( console );
return 1;
}
/* add input events to a console input queue */ /* add input events to a console input queue */
static int write_console_input( handle_t handle, int count, INPUT_RECORD *records ) static int write_console_input( struct console_input* console, int count, INPUT_RECORD *records )
{ {
INPUT_RECORD *new_rec; INPUT_RECORD *new_rec;
struct console_input *console;
if (!(console = (struct console_input *)get_handle_obj( current->process, handle, assert(count);
GENERIC_WRITE, &console_input_ops )))
return -1;
if (!(new_rec = realloc( console->records, if (!(new_rec = realloc( console->records,
(console->recnum + count) * sizeof(INPUT_RECORD) ))) (console->recnum + count) * sizeof(INPUT_RECORD) )))
{ {
...@@ -289,7 +426,9 @@ static int write_console_input( handle_t handle, int count, INPUT_RECORD *record ...@@ -289,7 +426,9 @@ static int write_console_input( handle_t handle, int count, INPUT_RECORD *record
console->records = new_rec; console->records = new_rec;
memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) ); memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
console->recnum += count; console->recnum += count;
release_object( console );
/* wake up all waiters */
wake_up( &console->obj, 0 );
return count; return count;
} }
...@@ -317,7 +456,7 @@ static int read_console_input( handle_t handle, int count, INPUT_RECORD *rec, in ...@@ -317,7 +456,7 @@ static int read_console_input( handle_t handle, int count, INPUT_RECORD *rec, in
{ {
int i; int i;
for (i = count; i < console->recnum; i++) for (i = count; i < console->recnum; i++)
console->records[i-count] = console->records[i]; ((INPUT_RECORD*)console->records)[i-count] = ((INPUT_RECORD*)console->records)[i];
if ((console->recnum -= count) > 0) if ((console->recnum -= count) > 0)
{ {
INPUT_RECORD *new_rec = realloc( console->records, INPUT_RECORD *new_rec = realloc( console->records,
...@@ -334,26 +473,283 @@ static int read_console_input( handle_t handle, int count, INPUT_RECORD *rec, in ...@@ -334,26 +473,283 @@ static int read_console_input( handle_t handle, int count, INPUT_RECORD *rec, in
return count; return count;
} }
static void console_input_dump( struct object *obj, int verbose ) /* set misc console input information */
static int set_console_input_info( struct set_console_input_info_request *req,
const WCHAR *title, size_t len )
{ {
struct console_input *console = (struct console_input *)obj; struct console_input *console;
assert( obj->ops == &console_input_ops ); struct console_renderer_event evt;
fprintf( stderr, "Console input fd=%d\n", console->obj.fd );
if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) goto error;
if (req->mask & SET_CONSOLE_INPUT_INFO_ACTIVE_SB)
{
struct screen_buffer *screen_buffer;
screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, req->active_sb,
GENERIC_READ, &screen_buffer_ops );
if (!screen_buffer || screen_buffer->input != console)
{
set_error( STATUS_INVALID_PARAMETER );
if (screen_buffer) release_object( screen_buffer );
goto error;
}
if (screen_buffer != console->active)
{
if (console->active) release_object( console->active );
console->active = screen_buffer;
evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT;
console_input_events_append( console->evt, &evt );
}
else
release_object( screen_buffer );
}
if (req->mask & SET_CONSOLE_INPUT_INFO_TITLE)
{
WCHAR *new_title = mem_alloc( len + sizeof(WCHAR) );
if (new_title)
{
memcpy( new_title, title, len + sizeof(WCHAR) );
new_title[len / sizeof(WCHAR)] = 0;
if (console->title) free( console->title );
console->title = new_title;
}
}
if (req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_MODE)
{
console->history_mode = req->history_mode;
}
if ((req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_SIZE) &&
console->history_size != req->history_size)
{
WCHAR** mem = NULL;
int i;
int delta;
if (req->history_size)
{
mem = mem_alloc( req->history_size * sizeof(WCHAR*) );
if (!mem) goto error;
memset( mem, 0, req->history_size * sizeof(WCHAR*) );
}
delta = (console->history_index > req->history_size) ?
(console->history_index - req->history_size) : 0;
for (i = delta; i < console->history_index; i++)
{
mem[i - delta] = console->history[i];
console->history[i] = NULL;
}
console->history_index -= delta;
for (i = 0; i < console->history_size; i++)
if (console->history[i]) free( console->history[i] );
free( console->history );
console->history = mem;
console->history_size = req->history_size;
}
release_object( console );
return 1;
error:
if (console) release_object( console );
return 0;
}
/* set misc screen buffer information */
static int set_console_output_info( struct screen_buffer *screen_buffer,
struct set_console_output_info_request *req )
{
struct console_renderer_event evt;
if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM)
{
if (req->cursor_size < 1 || req->cursor_size > 100)
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
if (screen_buffer->cursor_size != req->cursor_size ||
screen_buffer->cursor_visible != req->cursor_visible)
{
screen_buffer->cursor_size = req->cursor_size;
screen_buffer->cursor_visible = req->cursor_visible;
evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT;
evt.u.cursor_geom.size = req->cursor_size;
evt.u.cursor_geom.visible = req->cursor_visible;
console_input_events_append( screen_buffer->input->evt, &evt );
}
}
if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_POS)
{
if (req->cursor_x < 0 || req->cursor_x >= screen_buffer->width ||
req->cursor_y < 0 || req->cursor_y >= screen_buffer->height)
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
if (screen_buffer->cursor.X != req->cursor_x || screen_buffer->cursor.Y != req->cursor_y)
{
screen_buffer->cursor.X = req->cursor_x;
screen_buffer->cursor.Y = req->cursor_y;
evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
evt.u.cursor_pos.x = req->cursor_x;
evt.u.cursor_pos.y = req->cursor_y;
console_input_events_append( screen_buffer->input->evt, &evt );
}
}
if (req->mask & SET_CONSOLE_OUTPUT_INFO_SIZE)
{
int i, j;
/* FIXME: there are also some basic minimum and max size to deal with */
unsigned* new_data = mem_alloc( 4 * req->width * req->height );
if (!new_data) return 0;
/* fill the buffer with either the old buffer content or white on black spaces */
for (j = 0; j < req->height; j++)
{
for (i = 0; i < req->width; i++)
{
new_data[j * req->width + i] =
(i < screen_buffer->width && j < screen_buffer->height) ?
screen_buffer->data[j * screen_buffer->width + i] : 0x00F00020;
}
}
free( screen_buffer->data );
screen_buffer->data = new_data;
screen_buffer->width = req->width;
screen_buffer->height = req->height;
evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT;
evt.u.resize.width = req->width;
evt.u.resize.height = req->height;
console_input_events_append( screen_buffer->input->evt, &evt );
if (screen_buffer == screen_buffer->input->active &&
screen_buffer->input->mode & ENABLE_WINDOW_INPUT)
{
INPUT_RECORD ir;
ir.EventType = WINDOW_BUFFER_SIZE_EVENT;
ir.Event.WindowBufferSizeEvent.dwSize.X = req->width;
ir.Event.WindowBufferSizeEvent.dwSize.Y = req->height;
write_console_input( screen_buffer->input, 1, &ir );
}
}
if (req->mask & SET_CONSOLE_OUTPUT_INFO_ATTR)
{
screen_buffer->attr = req->attr;
}
if (req->mask & SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW)
{
if (req->win_left < 0 || req->win_left > req->win_right ||
req->win_right >= screen_buffer->width ||
req->win_top < 0 || req->win_top > req->win_bottom ||
req->win_bottom >= screen_buffer->height)
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
if (screen_buffer->win.Left != req->win_left || screen_buffer->win.Top != req->win_top ||
screen_buffer->win.Right != req->win_right || screen_buffer->win.Bottom != req->win_bottom)
{
screen_buffer->win.Left = req->win_left;
screen_buffer->win.Top = req->win_top;
screen_buffer->win.Right = req->win_right;
screen_buffer->win.Bottom = req->win_bottom;
evt.event = CONSOLE_RENDERER_DISPLAY_EVENT;
evt.u.display.left = req->win_left;
evt.u.display.top = req->win_top;
evt.u.display.width = req->win_right - req->win_left + 1;
evt.u.display.height = req->win_bottom - req->win_top + 1;
console_input_events_append( screen_buffer->input->evt, &evt );
}
}
if (req->mask & SET_CONSOLE_OUTPUT_INFO_MAX_SIZE)
{
/* can only be done by renderer */
if (current->process->console != screen_buffer->input)
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
screen_buffer->max_width = req->max_width;
screen_buffer->max_height = req->max_height;
}
return 1;
} }
static int console_input_get_poll_events( struct object *obj ) /* appends a new line to history (history is a fixed size array) */
static void console_input_append_hist( struct console_input* console, const WCHAR* buf, size_t len )
{ {
return POLLIN; WCHAR* ptr = mem_alloc( (len + 1) * sizeof(WCHAR) );
if (!ptr)
{
set_error( STATUS_NO_MEMORY );
return;
}
if (!console || !console->history_size)
{
set_error( STATUS_INVALID_PARAMETER ); /* FIXME */
return;
}
memcpy( ptr, buf, len * sizeof(WCHAR) );
ptr[len] = 0;
if (console->history_mode && console->history_index &&
strncmpW( console->history[console->history_index - 1], ptr, len * sizeof(WCHAR) ) == 0)
{
/* ok, mode ask us to not use twice the same string...
* so just free mem and returns
*/
set_error( STATUS_ALIAS_EXISTS );
free(ptr);
return;
}
if (console->history_index < console->history_size)
{
console->history[console->history_index++] = ptr;
}
else
{
free( console->history[0]) ;
memmove( &console->history[0], &console->history[1],
(console->history_size - 1) * sizeof(WCHAR*) );
console->history[console->history_size - 1] = ptr;
}
} }
static int console_input_get_fd( struct object *obj ) /* returns a line from the cachde */
static int console_input_get_hist( struct console_input* console, WCHAR* buf, size_t len, int index )
{
int ret;
/* FIXME: don't use len yet */
if (!console || index >= console->history_index)
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
ret = strlenW(console->history[index]);
memcpy( buf, console->history[index], ret * sizeof(WCHAR) ); /* FIXME should use len */
return ret;
}
/* dumb dump */
static void console_input_dump( struct object *obj, int verbose )
{ {
struct console_input *console = (struct console_input *)obj; struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops ); assert( obj->ops == &console_input_ops );
return console->obj.fd; fprintf( stderr, "Console input active=%p evt=%p\n",
console->active, console->evt );
} }
static int console_get_info( struct object *obj, struct get_file_info_request *req ) static int console_get_file_info( struct object *obj, struct get_file_info_request *req )
{ {
if (req) if (req)
{ {
...@@ -373,59 +769,245 @@ static int console_get_info( struct object *obj, struct get_file_info_request *r ...@@ -373,59 +769,245 @@ static int console_get_info( struct object *obj, struct get_file_info_request *r
static void console_input_destroy( struct object *obj ) static void console_input_destroy( struct object *obj )
{ {
struct console_input *console = (struct console_input *)obj; struct console_input* console_in = (struct console_input *)obj;
struct screen_buffer* curr;
int i;
assert( obj->ops == &console_input_ops ); assert( obj->ops == &console_input_ops );
if (console->output) console->output->input = NULL; if (console_in->title) free( console_in->title );
if (console_in->records) free( console_in->records );
if (console_in->active) release_object( console_in->active );
console_in->active = NULL;
for (curr = screen_buffer_list; curr; curr = curr->next)
{
if (curr->input == console_in) curr->input = NULL;
}
release_object( console_in->evt );
console_in->evt = NULL;
for (i = 0; i < console_in->history_size; i++)
if (console_in->history[i]) free( console_in->history[i] );
if (console_in->history) free( console_in->history );
} }
static void screen_buffer_dump( struct object *obj, int verbose ) static void screen_buffer_dump( struct object *obj, int verbose )
{ {
struct screen_buffer *console = (struct screen_buffer *)obj; struct screen_buffer *screen_buffer = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops ); assert( obj->ops == &screen_buffer_ops );
fprintf( stderr, "Console screen buffer fd=%d\n", console->obj.fd );
fprintf(stderr, "Console screen buffer input=%p\n", screen_buffer->input );
} }
static int screen_buffer_get_poll_events( struct object *obj ) static void screen_buffer_destroy( struct object *obj )
{ {
return POLLOUT; struct screen_buffer* screen_buffer = (struct screen_buffer *)obj;
struct screen_buffer** psb;
assert( obj->ops == &screen_buffer_ops );
for (psb = &screen_buffer_list; *psb; *psb = (*psb)->next)
{
if (*psb == screen_buffer)
{
*psb = screen_buffer->next;
break;
}
}
if (screen_buffer->input && screen_buffer->input->active == screen_buffer)
{
struct screen_buffer* sb;
for (sb = screen_buffer_list; sb && sb->input != screen_buffer->input; sb = sb->next);
screen_buffer->input->active = sb;
}
} }
static int screen_buffer_get_fd( struct object *obj ) /* write data into a screen buffer */
static int write_console_output( struct screen_buffer *screen_buffer, size_t size,
const unsigned char* data, int mode, short int x, short int y )
{ {
struct screen_buffer *console = (struct screen_buffer *)obj; int uniform = mode & WRITE_CONSOLE_MODE_UNIFORM;
assert( obj->ops == &screen_buffer_ops ); unsigned *ptr;
return console->obj.fd; unsigned i, inc;
int len;
mode &= ~WRITE_CONSOLE_MODE_UNIFORM;
if (mode < 0 || mode > 3)
{
set_error(STATUS_INVALID_PARAMETER);
return 0;
}
/* set destination pointer and increment */
ptr = screen_buffer->data + (y * screen_buffer->width + x);
if (mode == WRITE_CONSOLE_MODE_ATTR) ptr = (unsigned*)((char*)ptr + 2);
inc = (mode == WRITE_CONSOLE_MODE_TEXTATTR) ? 4 : 2;
len = size / inc;
/* crop if needed */
if (x + len > screen_buffer->width) len = screen_buffer->width - x;
for (i = 0; i < len; i++)
{
if (mode == WRITE_CONSOLE_MODE_TEXTSTDATTR)
{
memcpy( (char*)ptr + 2, &screen_buffer->attr, 2 );
}
memcpy( ptr++, data, inc );
if (!uniform) data += inc;
}
if (len && screen_buffer == screen_buffer->input->active)
{
int y2;
struct console_renderer_event evt;
y2 = (y * screen_buffer->width + x + len - 1) / screen_buffer->width;
evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
evt.u.update.top = y;
evt.u.update.bottom = y2;
console_input_events_append( screen_buffer->input->evt, &evt );
}
return len;
} }
static void screen_buffer_destroy( struct object *obj ) /* read data from a screen buffer */
static int read_console_output( struct screen_buffer *screen_buffer, size_t size, void* data,
short int x, short int y, short int w, short int h,
short int* eff_w, short int* eff_h )
{ {
struct screen_buffer *console = (struct screen_buffer *)obj; int j;
assert( obj->ops == &screen_buffer_ops );
if (console->input) console->input->output = NULL; if (size < w * h * 4 || x >= screen_buffer->width || y >= screen_buffer->height)
if (console->title) free( console->title ); {
set_error(STATUS_INVALID_PARAMETER);
return 0;
}
*eff_w = w;
*eff_h = h;
if (x + w > screen_buffer->width) *eff_w = screen_buffer->width - x;
if (y + h > screen_buffer->height) *eff_h = screen_buffer->height - y;
for (j = 0; j < *eff_h; j++)
{
memcpy( (char*)data + 4 * j * w, &screen_buffer->data[(y + j) * screen_buffer->width + x],
*eff_w * 4 );
}
return *eff_w * *eff_h;
} }
/* allocate a console for the current process */ /* scroll parts of a screen buffer */
DECL_HANDLER(alloc_console) static void scroll_console_output( handle_t handle, short int xsrc, short int ysrc,
short int xdst, short int ydst, short int w, short int h )
{ {
handle_t in = 0, out = 0; struct screen_buffer *screen_buffer;
int j;
unsigned* psrc;
unsigned* pdst;
struct console_renderer_event evt;
if (!alloc_console( current->process )) goto done; if (!(screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, handle,
GENERIC_READ, &screen_buffer_ops )))
return;
if (xsrc < 0 || ysrc < 0 || xdst < 0 || ydst < 0 ||
xsrc + w > screen_buffer->width ||
xdst + w > screen_buffer->width ||
ysrc + h > screen_buffer->height ||
ydst + h > screen_buffer->height ||
w == 0 || h == 0)
{
set_error( STATUS_INVALID_PARAMETER );
release_object( screen_buffer );
return;
}
if ((in = alloc_handle( current->process, current->process->console_in, if (ysrc < ydst)
req->access, req->inherit )))
{ {
if ((out = alloc_handle( current->process, current->process->console_out, psrc = &screen_buffer->data[(ysrc + h - 1) * screen_buffer->width + xsrc];
req->access, req->inherit ))) pdst = &screen_buffer->data[(ydst + h - 1) * screen_buffer->width + xdst];
goto done; /* everything is fine */
close_handle( current->process, in, NULL ); for (j = h; j > 0; j--)
in = 0; {
memcpy(pdst, psrc, w * 4);
pdst -= screen_buffer->width;
psrc -= screen_buffer->width;
}
} }
free_console( current->process ); else
{
psrc = &screen_buffer->data[ysrc * screen_buffer->width + xsrc];
pdst = &screen_buffer->data[ydst * screen_buffer->width + xdst];
for (j = 0; j < h; j++)
{
/* we use memmove here because when psrc and pdst are the same,
* copies are done on the same row, so the dst and src blocks
* can overlap */
memmove( pdst, psrc, w * 4 );
pdst += screen_buffer->width;
psrc += screen_buffer->width;
}
}
/* FIXME: this could be enhanced, by signalling scroll */
evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
evt.u.update.top = min(ysrc, ydst);
evt.u.update.bottom = max(ysrc, ydst) + h - 1;
console_input_events_append( screen_buffer->input->evt, &evt );
done: release_object( screen_buffer );
req->handle_in = in; }
req->handle_out = out;
/* allocate a console for the renderer */
DECL_HANDLER(alloc_console)
{
handle_t in = 0;
handle_t evt = 0;
struct process *process;
struct process *renderer = current->process;
struct console_input *console;
process = (req->pid) ? get_process_from_id( req->pid ) :
(struct process *)grab_object( renderer->parent );
req->handle_in = 0;
req->event = 0;
if (!process) return;
if (process != renderer && process->console)
{
set_error( STATUS_ACCESS_DENIED );
goto the_end;
}
if ((console = (struct console_input*)create_console_input( renderer )))
{
if ((in = alloc_handle( renderer, console, req->access, req->inherit )))
{
if ((evt = alloc_handle( renderer, console->evt,
SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, FALSE )))
{
if (process != renderer)
{
process->console = (struct console_input*)grab_object( console );
console->num_proc++;
}
req->handle_in = in;
req->event = evt;
release_object( console );
goto the_end;
}
close_handle( renderer, in, NULL );
}
free_console( process );
}
the_end:
release_object( process );
} }
/* free the console of the current process */ /* free the console of the current process */
...@@ -434,58 +1016,83 @@ DECL_HANDLER(free_console) ...@@ -434,58 +1016,83 @@ DECL_HANDLER(free_console)
free_console( current->process ); free_console( current->process );
} }
/* let the renderer peek the events it's waiting on */
DECL_HANDLER(get_console_renderer_events)
{
struct console_input_events* evt;
size_t len = 0;
evt = (struct console_input_events *)get_handle_obj( current->process, req->handle,
GENERIC_WRITE, &console_input_events_ops );
if (!evt) return;
len = console_input_events_get( evt, get_req_data(req), get_req_data_size(req) );
set_req_data_size( req, len );
release_object( evt );
}
/* open a handle to the process console */ /* open a handle to the process console */
DECL_HANDLER(open_console) DECL_HANDLER(open_console)
{ {
struct object *obj= req->output ? current->process->console_out : current->process->console_in; struct object *obj = NULL;
req->handle = 0; req->handle = 0;
if (obj) req->handle = alloc_handle( current->process, obj, req->access, req->inherit ); switch (req->from)
else set_error( STATUS_ACCESS_DENIED ); {
case 0:
if (current->process->console && current->process->console->renderer)
obj = grab_object( (struct object*)current->process->console );
break;
case 1:
if (current->process->console && current->process->console->renderer &&
current->process->console->active)
obj = grab_object( (struct object*)current->process->console->active );
break;
default:
if ((obj = get_handle_obj( current->process, (handle_t)req->from,
GENERIC_READ|GENERIC_WRITE, &console_input_ops )))
{
struct console_input* console = (struct console_input*)obj;
obj = (console->active) ? grab_object( console->active ) : NULL;
release_object( console );
}
break;
}
/* FIXME: req->share is not used (as in screen buffer creation) */
if (obj)
{
req->handle = alloc_handle( current->process, obj, req->access, req->inherit );
release_object( obj );
}
if (!req->handle && !get_error()) set_error( STATUS_ACCESS_DENIED );
} }
/* set info about a console (output only) */ /* set info about a console input */
DECL_HANDLER(set_console_info) DECL_HANDLER(set_console_input_info)
{ {
set_console_info( req->handle, req, get_req_data(req), get_req_data_size(req) ); set_console_input_info( req, get_req_data(req), get_req_data_size(req) );
} }
/* get info about a console (output only) */ /* get info about a console (output only) */
DECL_HANDLER(get_console_info) DECL_HANDLER(get_console_input_info)
{ {
struct screen_buffer *console; struct console_input *console = 0;
size_t len = 0;
set_req_data_size( req, 0 );
if (!(console = console_input_get( req->handle, GENERIC_READ ))) return;
if ((console = (struct screen_buffer *)get_handle_obj( current->process, req->handle, if (console->title)
GENERIC_READ, &screen_buffer_ops )))
{ {
req->cursor_size = console->cursor_size; size_t len = strlenW( console->title ) * sizeof(WCHAR);
req->cursor_visible = console->cursor_visible; if (len > get_req_data_size(req)) len = get_req_data_size(req);
req->pid = console->pid; memcpy( get_req_data(req), console->title, len );
if (console->title) set_req_data_size( req, len );
{
len = strlen( console->title );
if (len > get_req_data_size(req)) len = get_req_data_size(req);
memcpy( get_req_data(req), console->title, len );
}
release_object( console );
} }
set_req_data_size( req, len ); req->history_mode = console->history_mode;
} req->history_size = console->history_size;
req->history_index = console->history_index;
/* set a console fd */
DECL_HANDLER(set_console_fd)
{
int fd_out, fd_in = thread_get_inflight_fd( current, req->fd_in );
if (req->fd_out == req->fd_in) fd_out = dup( fd_in );
else fd_out = thread_get_inflight_fd( current, req->fd_out );
if (fd_in == -1 || fd_out == -1) set_error( STATUS_INVALID_HANDLE ); release_object( console );
else if (set_console_fd( req->handle, fd_in, fd_out, req->pid )) return;
if (fd_in != -1) close( fd_in );
if (fd_out != -1) close( fd_out );
} }
/* get a console mode (input or output) */ /* get a console mode (input or output) */
...@@ -503,8 +1110,16 @@ DECL_HANDLER(set_console_mode) ...@@ -503,8 +1110,16 @@ DECL_HANDLER(set_console_mode)
/* add input records to a console input queue */ /* add input records to a console input queue */
DECL_HANDLER(write_console_input) DECL_HANDLER(write_console_input)
{ {
req->written = write_console_input( req->handle, get_req_data_size(req) / sizeof(INPUT_RECORD), struct console_input *console;
req->written = 0;
if (!(console = (struct console_input *)get_handle_obj( current->process, req->handle,
GENERIC_WRITE, &console_input_ops )))
return;
req->written = write_console_input( console, get_req_data_size(req) / sizeof(INPUT_RECORD),
get_req_data(req) ); get_req_data(req) );
release_object( console );
} }
/* fetch input records from a console input queue */ /* fetch input records from a console input queue */
...@@ -516,3 +1131,132 @@ DECL_HANDLER(read_console_input) ...@@ -516,3 +1131,132 @@ DECL_HANDLER(read_console_input)
if (size) set_req_data_size( req, res * sizeof(INPUT_RECORD) ); if (size) set_req_data_size( req, res * sizeof(INPUT_RECORD) );
req->read = res; req->read = res;
} }
/* appends a string to console's history */
DECL_HANDLER(append_console_input_history)
{
struct console_input* console;
if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) return;
console_input_append_hist( console, get_req_data(req),
get_req_data_size(req) / sizeof(WCHAR) );
release_object( console );
}
/* appends a string to console's history */
DECL_HANDLER(get_console_input_history)
{
struct console_input* console;
int len;
if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) return;
len = console_input_get_hist( console, get_req_data(req), 0 /* FIXME */, req->index );
set_req_data_size( req, len * sizeof(WCHAR));
release_object( console );
}
/* creates a screen buffer */
DECL_HANDLER(create_console_output)
{
struct console_input* console;
struct screen_buffer* screen_buffer;
if (!(console = console_input_get( req->handle_in, GENERIC_WRITE))) return;
screen_buffer = (struct screen_buffer*)create_console_output( console );
if (screen_buffer)
{
/* FIXME: should store sharing and test it when opening the CONOUT$ device
* see file.c on how this could be done
*/
req->handle_out = alloc_handle( current->process, screen_buffer, req->access, req->inherit );
release_object( screen_buffer );
}
release_object( console );
}
/* set info about a console screen buffer */
DECL_HANDLER(set_console_output_info)
{
struct screen_buffer *screen_buffer;
if (!(screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
GENERIC_WRITE, &screen_buffer_ops )))
return;
set_console_output_info( screen_buffer, req );
release_object( screen_buffer );
}
/* get info about a console screen buffer */
DECL_HANDLER(get_console_output_info)
{
struct screen_buffer *screen_buffer;
size_t len = 0;
if ((screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, req->handle,
GENERIC_READ, &screen_buffer_ops )))
{
req->cursor_size = screen_buffer->cursor_size;
req->cursor_visible = screen_buffer->cursor_visible;
req->cursor_x = screen_buffer->cursor.X;
req->cursor_y = screen_buffer->cursor.Y;
req->width = screen_buffer->width;
req->height = screen_buffer->height;
req->attr = screen_buffer->attr;
req->win_left = screen_buffer->win.Left;
req->win_top = screen_buffer->win.Top;
req->win_right = screen_buffer->win.Right;
req->win_bottom = screen_buffer->win.Bottom;
req->max_width = screen_buffer->max_width;
req->max_height = screen_buffer->max_height;
release_object( screen_buffer );
}
set_req_data_size( req, len );
}
/* read data (chars & attrs) from a screen buffer */
DECL_HANDLER(read_console_output)
{
struct screen_buffer *screen_buffer;
size_t size = get_req_data_size(req);
int res;
if (!(screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
GENERIC_READ, &screen_buffer_ops )))
return;
res = read_console_output( screen_buffer, size, get_req_data(req),
req->x, req->y, req->w, req->h, &req->eff_w, &req->eff_h);
/* if size was 0 we didn't fetch anything */
if (size) set_req_data_size( req, res * 4 );
release_object( screen_buffer );
}
/* write data (char and/or attrs) to a screen buffer */
DECL_HANDLER(write_console_output)
{
struct screen_buffer *screen_buffer;
size_t size = get_req_data_size(req);
int res;
if (!(screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
GENERIC_WRITE, &screen_buffer_ops )))
return;
res = write_console_output( screen_buffer, size, get_req_data(req), req->mode, req->x, req->y );
/* if size was 0 we didn't fetch anything */
if (size) set_req_data_size( req, res );
req->written = res;
release_object( screen_buffer );
}
/* move a rect of data in a screen buffer */
DECL_HANDLER(move_console_output)
{
scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst,
req->w, req->h );
}
/*
* Wine server consoles
*
* Copyright (C) 2001 Eric Pouech
*/
#ifndef __WINE_SERVER_CONSOLE_H
#define __WINE_SERVER_CONSOLE_H
struct screen_buffer;
struct console_input_events;
struct console_input
{
struct object obj; /* object header */
int num_proc; /* number of processes attached to this console */
struct process *renderer; /* console renderer thread */
int mode; /* input mode */
struct screen_buffer *active; /* active screen buffer */
int recnum; /* number of input records */
void *records; /* input records */
struct console_input_events *evt; /* synchronization event with renderer */
WCHAR *title; /* console title */
WCHAR **history; /* lines history */
int history_size; /* number of entries in history array */
int history_index; /* number of used entries in history array */
int history_mode; /* mode of history (non zero means remove doubled strings */
};
/* console functions */
extern void inherit_console(struct process *parent, struct process *process, handle_t hconin);
extern int free_console( struct process *process );
#endif /* __WINE_SERVER_CONSOLE_H */
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "process.h" #include "process.h"
#include "thread.h" #include "thread.h"
#include "request.h" #include "request.h"
#include "console.h"
enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED }; enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED };
...@@ -411,6 +412,11 @@ static int debugger_attach( struct process *process, struct thread *debugger ) ...@@ -411,6 +412,11 @@ static int debugger_attach( struct process *process, struct thread *debugger )
for (thread = debugger; thread; thread = thread->process->debugger) for (thread = debugger; thread; thread = thread->process->debugger)
if (thread->process == process) goto error; if (thread->process == process) goto error;
/* don't let a debugger debug its console... won't work */
if (debugger->process->console &&
debugger->process->console->renderer == process &&
process->console) goto error;
suspend_process( process ); suspend_process( process );
/* we must have been able to attach all threads */ /* we must have been able to attach all threads */
......
...@@ -494,7 +494,7 @@ DECL_HANDLER(alloc_file_handle) ...@@ -494,7 +494,7 @@ DECL_HANDLER(alloc_file_handle)
if ((file = create_file_for_fd( fd, req->access, FILE_SHARE_READ | FILE_SHARE_WRITE, if ((file = create_file_for_fd( fd, req->access, FILE_SHARE_READ | FILE_SHARE_WRITE,
0, DRIVE_UNKNOWN ))) 0, DRIVE_UNKNOWN )))
{ {
req->handle = alloc_handle( current->process, file, req->access, 0 ); req->handle = alloc_handle( current->process, file, req->access, req->inherit );
release_object( file ); release_object( file );
} }
} }
......
...@@ -355,6 +355,7 @@ struct object *get_handle_obj( struct process *process, handle_t handle, ...@@ -355,6 +355,7 @@ struct object *get_handle_obj( struct process *process, handle_t handle,
if (!(entry = get_handle( process, handle ))) return NULL; if (!(entry = get_handle( process, handle ))) return NULL;
if ((entry->access & access) != access) if ((entry->access & access) != access)
{ {
fprintf( stderr, "handle %d access %08x denied (%08x)\n", handle, access, entry->access );
set_error( STATUS_ACCESS_DENIED ); set_error( STATUS_ACCESS_DENIED );
return NULL; return NULL;
} }
...@@ -376,6 +377,7 @@ int get_handle_fd( struct process *process, handle_t handle, unsigned int access ...@@ -376,6 +377,7 @@ int get_handle_fd( struct process *process, handle_t handle, unsigned int access
if (!(entry = get_handle( process, handle ))) return -1; if (!(entry = get_handle( process, handle ))) return -1;
if ((entry->access & access) != access) if ((entry->access & access) != access)
{ {
fprintf( stderr, "handle %d access %08x denied (%08x)\n", handle, access, entry->access );
set_error( STATUS_ACCESS_DENIED ); set_error( STATUS_ACCESS_DENIED );
return -1; return -1;
} }
......
...@@ -155,11 +155,6 @@ extern void file_set_error(void); ...@@ -155,11 +155,6 @@ extern void file_set_error(void);
int get_serial_async_timeout(struct object *obj, int type, int count); int get_serial_async_timeout(struct object *obj, int type, int count);
/* console functions */
extern int alloc_console( struct process *process );
extern int free_console( struct process *process );
/* debugger functions */ /* debugger functions */
extern int set_process_debugger( struct process *process, struct thread *debugger ); extern int set_process_debugger( struct process *process, struct thread *debugger );
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "process.h" #include "process.h"
#include "thread.h" #include "thread.h"
#include "request.h" #include "request.h"
#include "console.h"
/* process structure */ /* process structure */
...@@ -101,12 +102,18 @@ static int set_process_console( struct process *process, struct process *parent, ...@@ -101,12 +102,18 @@ static int set_process_console( struct process *process, struct process *parent,
{ {
if (process->create_flags & CREATE_NEW_CONSOLE) if (process->create_flags & CREATE_NEW_CONSOLE)
{ {
if (!alloc_console( process )) return 0; /* let the process init do the allocation */
return 1;
} }
else if (parent && !(process->create_flags & DETACHED_PROCESS)) else if (parent && !(process->create_flags & DETACHED_PROCESS))
{ {
if (parent->console_in) process->console_in = grab_object( parent->console_in ); /* FIXME: some better error checking should be done...
if (parent->console_out) process->console_out = grab_object( parent->console_out ); * like if hConOut and hConIn are console handles, then they should be on the same
* physical console
*/
inherit_console( parent, process,
(info->inherit_all || (info->start_flags & STARTF_USESTDHANDLES)) ?
info->hstdin : 0 );
} }
if (parent) if (parent)
{ {
...@@ -129,13 +136,20 @@ static int set_process_console( struct process *process, struct process *parent, ...@@ -129,13 +136,20 @@ static int set_process_console( struct process *process, struct process *parent,
} }
else else
{ {
/* no parent, use handles to the console for stdio */ if (process->console)
req->hstdin = alloc_handle( process, process->console_in, {
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 ); req->hstdin = alloc_handle( process, process->console,
req->hstdout = alloc_handle( process, process->console_out, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 ); req->hstdout = alloc_handle( process, process->console->active,
req->hstderr = alloc_handle( process, process->console_out, GENERIC_READ | GENERIC_WRITE, 1 );
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 ); req->hstderr = alloc_handle( process, process->console->active,
GENERIC_READ | GENERIC_WRITE, 1 );
}
else
{
/* no parent, let the caller decide what to do */
req->hstdin = req->hstdout = req->hstderr = 0;
}
} }
/* some handles above may have been invalid; this is not an error */ /* some handles above may have been invalid; this is not an error */
if (get_error() == STATUS_INVALID_HANDLE) clear_error(); if (get_error() == STATUS_INVALID_HANDLE) clear_error();
...@@ -152,6 +166,7 @@ struct thread *create_process( int fd ) ...@@ -152,6 +166,7 @@ struct thread *create_process( int fd )
if (!(process = alloc_object( &process_ops, fd ))) return NULL; if (!(process = alloc_object( &process_ops, fd ))) return NULL;
process->next = NULL; process->next = NULL;
process->prev = NULL; process->prev = NULL;
process->parent = NULL;
process->thread_list = NULL; process->thread_list = NULL;
process->debugger = NULL; process->debugger = NULL;
process->handles = NULL; process->handles = NULL;
...@@ -161,8 +176,7 @@ struct thread *create_process( int fd ) ...@@ -161,8 +176,7 @@ struct thread *create_process( int fd )
process->affinity = 1; process->affinity = 1;
process->suspend = 0; process->suspend = 0;
process->create_flags = 0; process->create_flags = 0;
process->console_in = NULL; process->console = NULL;
process->console_out = NULL;
process->init_event = NULL; process->init_event = NULL;
process->idle_event = NULL; process->idle_event = NULL;
process->queue = NULL; process->queue = NULL;
...@@ -173,6 +187,7 @@ struct thread *create_process( int fd ) ...@@ -173,6 +187,7 @@ struct thread *create_process( int fd )
process->exe.file = NULL; process->exe.file = NULL;
process->exe.dbg_offset = 0; process->exe.dbg_offset = 0;
process->exe.dbg_size = 0; process->exe.dbg_size = 0;
gettimeofday( &process->start_time, NULL ); gettimeofday( &process->start_time, NULL );
if ((process->next = first_process) != NULL) process->next->prev = process; if ((process->next = first_process) != NULL) process->next->prev = process;
first_process = process; first_process = process;
...@@ -222,10 +237,11 @@ static void init_process( int ppid, struct init_process_request *req ) ...@@ -222,10 +237,11 @@ static void init_process( int ppid, struct init_process_request *req )
fatal_protocol_error( current, "init_process: called twice?\n" ); fatal_protocol_error( current, "init_process: called twice?\n" );
return; return;
} }
process->parent = (struct process *)grab_object( parent );
} }
/* set the process flags */ /* set the process flags */
process->create_flags = info ? info->create_flags : CREATE_NEW_CONSOLE; process->create_flags = info ? info->create_flags : 0;
/* create the handle table */ /* create the handle table */
if (parent && info->inherit_all) if (parent && info->inherit_all)
...@@ -288,6 +304,8 @@ static void process_destroy( struct object *obj ) ...@@ -288,6 +304,8 @@ static void process_destroy( struct object *obj )
/* we can't have a thread remaining */ /* we can't have a thread remaining */
assert( !process->thread_list ); assert( !process->thread_list );
if (process->console) release_object( process->console );
if (process->parent) release_object( process->parent );
if (process->next) process->next->prev = process->prev; if (process->next) process->next->prev = process->prev;
if (process->prev) process->prev->next = process->next; if (process->prev) process->prev->next = process->next;
else first_process = process->next; else first_process = process->next;
...@@ -304,9 +322,8 @@ static void process_dump( struct object *obj, int verbose ) ...@@ -304,9 +322,8 @@ static void process_dump( struct object *obj, int verbose )
struct process *process = (struct process *)obj; struct process *process = (struct process *)obj;
assert( obj->ops == &process_ops ); assert( obj->ops == &process_ops );
fprintf( stderr, "Process next=%p prev=%p console=%p/%p handles=%p\n", fprintf( stderr, "Process next=%p prev=%p handles=%p\n",
process->next, process->prev, process->console_in, process->console_out, process->next, process->prev, process->handles );
process->handles );
} }
static int process_signaled( struct object *obj, struct thread *thread ) static int process_signaled( struct object *obj, struct thread *thread )
...@@ -418,6 +435,25 @@ static void process_unload_dll( struct process *process, void *base ) ...@@ -418,6 +435,25 @@ static void process_unload_dll( struct process *process, void *base )
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
} }
/* kill all processes being attached to a console renderer */
static void kill_console_processes( struct process *renderer, int exit_code )
{
for (;;) /* restart from the beginning of the list every time */
{
struct process *process = first_process;
/* find the first process being attached to 'renderer' and still running */
while (process &&
(process == renderer || !process->console ||
process->console->renderer != renderer || !process->running_threads))
{
process = process->next;
}
if (!process) break;
kill_process( process, NULL, exit_code );
}
}
/* a process has been killed (i.e. its last thread died) */ /* a process has been killed (i.e. its last thread died) */
static void process_killed( struct process *process ) static void process_killed( struct process *process )
{ {
...@@ -425,7 +461,13 @@ static void process_killed( struct process *process ) ...@@ -425,7 +461,13 @@ static void process_killed( struct process *process )
gettimeofday( &process->end_time, NULL ); gettimeofday( &process->end_time, NULL );
if (process->handles) release_object( process->handles ); if (process->handles) release_object( process->handles );
process->handles = NULL; process->handles = NULL;
/* close the console attached to this process, if any */
free_console( process ); free_console( process );
/* close the processes using process as renderer, if any */
kill_console_processes( process, 0 );
while (process->exe.next) while (process->exe.next)
{ {
struct process_dll *dll = process->exe.next; struct process_dll *dll = process->exe.next;
...@@ -508,6 +550,7 @@ void resume_process( struct process *process ) ...@@ -508,6 +550,7 @@ void resume_process( struct process *process )
void kill_process( struct process *process, struct thread *skip, int exit_code ) void kill_process( struct process *process, struct thread *skip, int exit_code )
{ {
struct thread *thread = process->thread_list; struct thread *thread = process->thread_list;
while (thread) while (thread)
{ {
struct thread *next = thread->proc_next; struct thread *next = thread->proc_next;
...@@ -532,6 +575,7 @@ void kill_debugged_processes( struct thread *debugger, int exit_code ) ...@@ -532,6 +575,7 @@ void kill_debugged_processes( struct thread *debugger, int exit_code )
} }
} }
/* get all information about a process */ /* get all information about a process */
static void get_process_info( struct process *process, struct get_process_info_request *req ) static void get_process_info( struct process *process, struct get_process_info_request *req )
{ {
......
...@@ -30,6 +30,7 @@ struct process ...@@ -30,6 +30,7 @@ struct process
struct object obj; /* object header */ struct object obj; /* object header */
struct process *next; /* system-wide process list */ struct process *next; /* system-wide process list */
struct process *prev; struct process *prev;
struct process *parent; /* parent process */
struct thread *thread_list; /* head of the thread list */ struct thread *thread_list; /* head of the thread list */
struct thread *debugger; /* thread debugging this process */ struct thread *debugger; /* thread debugging this process */
struct object *handles; /* handle entries */ struct object *handles; /* handle entries */
...@@ -41,8 +42,7 @@ struct process ...@@ -41,8 +42,7 @@ struct process
int affinity; /* process affinity mask */ int affinity; /* process affinity mask */
int suspend; /* global process suspend count */ int suspend; /* global process suspend count */
int create_flags; /* process creation flags */ int create_flags; /* process creation flags */
struct object *console_in; /* console input */ struct console_input*console; /* console input */
struct object *console_out; /* console output */
struct event *init_event; /* event for init done */ struct event *init_event; /* event for init done */
struct event *idle_event; /* event for input idle */ struct event *idle_event; /* event for input idle */
struct msg_queue *queue; /* main message queue */ struct msg_queue *queue; /* main message queue */
...@@ -55,7 +55,6 @@ struct process ...@@ -55,7 +55,6 @@ struct process
struct process_snapshot struct process_snapshot
{ {
struct process *process; /* process ptr */ struct process *process; /* process ptr */
struct process *parent; /* process parent */
int count; /* process refcount */ int count; /* process refcount */
int threads; /* number of threads */ int threads; /* number of threads */
int priority; /* priority class */ int priority; /* priority class */
......
...@@ -533,6 +533,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; ...@@ -533,6 +533,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
/* Allocate a file handle for a Unix fd */ /* Allocate a file handle for a Unix fd */
@REQ(alloc_file_handle) @REQ(alloc_file_handle)
unsigned int access; /* wanted access rights */ unsigned int access; /* wanted access rights */
int inherit; /* inherit flag */
int fd; /* file descriptor on the client side */ int fd; /* file descriptor on the client side */
@REPLY @REPLY
handle_t handle; /* handle to the file */ handle_t handle; /* handle to the file */
...@@ -685,13 +686,14 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; ...@@ -685,13 +686,14 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@END @END
/* Allocate a console for the current process */ /* Allocate a console (only used by a console renderer) */
@REQ(alloc_console) @REQ(alloc_console)
unsigned int access; /* wanted access rights */ unsigned int access; /* wanted access rights */
int inherit; /* inherit flag */ int inherit; /* inherit flag */
void* pid; /* pid of process which shall be attached to the console */
@REPLY @REPLY
handle_t handle_in; /* handle to console input */ handle_t handle_in; /* handle to console input */
handle_t handle_out; /* handle to console output */ handle_t event; /* handle to renderer events change notification */
@END @END
...@@ -700,25 +702,70 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; ...@@ -700,25 +702,70 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@END @END
#define CONSOLE_RENDERER_NONE_EVENT 0x00
#define CONSOLE_RENDERER_TITLE_EVENT 0x01
#define CONSOLE_RENDERER_ACTIVE_SB_EVENT 0x02
#define CONSOLE_RENDERER_SB_RESIZE_EVENT 0x03
#define CONSOLE_RENDERER_UPDATE_EVENT 0x04
#define CONSOLE_RENDERER_CURSOR_POS_EVENT 0x05
#define CONSOLE_RENDERER_CURSOR_GEOM_EVENT 0x06
#define CONSOLE_RENDERER_DISPLAY_EVENT 0x07
#define CONSOLE_RENDERER_EXIT_EVENT 0x08
struct console_renderer_event
{
short event;
union
{
struct update
{
short top;
short bottom;
} update;
struct resize
{
short width;
short height;
} resize;
struct cursor_pos
{
short x;
short y;
} cursor_pos;
struct cursor_geom
{
short visible;
short size;
} cursor_geom;
struct display
{
short left;
short top;
short width;
short height;
} display;
} u;
};
/* retrieve console events for the renderer */
@REQ(get_console_renderer_events)
handle_t handle; /* handle to console input events */
@REPLY
VARARG(data,bytes); /* the various console_renderer_events */
@END
/* Open a handle to the process console */ /* Open a handle to the process console */
@REQ(open_console) @REQ(open_console)
int output; /* input or output? */ int from; /* 0 (resp 1) input (resp output) of current process console */
/* otherwise console_in handle to get active screen buffer? */
unsigned int access; /* wanted access rights */ unsigned int access; /* wanted access rights */
int inherit; /* inherit flag */ int inherit; /* inherit flag */
int share; /* share mask (only for output handles) */
@REPLY @REPLY
handle_t handle; /* handle to the console */ handle_t handle; /* handle to the console */
@END @END
/* Set a console file descriptor */
@REQ(set_console_fd)
handle_t handle; /* handle to the console */
int fd_in; /* file descriptor to use as input */
int fd_out; /* file descriptor to use as output */
int pid; /* pid of xterm (hack) */
@END
/* Get a console mode (input or output) */ /* Get a console mode (input or output) */
@REQ(get_console_mode) @REQ(get_console_mode)
handle_t handle; /* handle to the console */ handle_t handle; /* handle to the console */
...@@ -734,28 +781,104 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; ...@@ -734,28 +781,104 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@END @END
/* Set info about a console (input only) */
@REQ(set_console_input_info)
handle_t handle; /* handle to console input, or 0 for process' console */
int mask; /* setting mask (see below) */
handle_t active_sb; /* active screen buffer */
int history_mode; /* whether we duplicate lines in history */
int history_size; /* number of lines in history */
VARARG(title,unicode_str); /* console title */
@END
#define SET_CONSOLE_INPUT_INFO_ACTIVE_SB 0x01
#define SET_CONSOLE_INPUT_INFO_TITLE 0x02
#define SET_CONSOLE_INPUT_INFO_HISTORY_MODE 0x04
#define SET_CONSOLE_INPUT_INFO_HISTORY_SIZE 0x08
/* Get info about a console (input only) */
@REQ(get_console_input_info)
handle_t handle; /* handle to console input, or 0 for process' console */
@REPLY
int history_mode; /* whether we duplicate lines in history */
int history_size; /* number of lines in history */
int history_index; /* number of used lines in history */
VARARG(title,unicode_str); /* console title */
@END
/* appends a string to console's history */
@REQ(append_console_input_history)
handle_t handle; /* handle to console input, or 0 for process' console */
VARARG(line,unicode_str); /* line to add */
@END
/* appends a string to console's history */
@REQ(get_console_input_history)
handle_t handle; /* handle to console input, or 0 for process' console */
int index; /* index to get line from */
@REPLY
VARARG(line,unicode_str); /* line to add */
@END
/* creates a new screen buffer on process' console */
@REQ(create_console_output)
handle_t handle_in; /* handle to console input, or 0 for process' console */
int access; /* wanted access rights */
int share; /* sharing credentials */
int inherit; /* inherit flag */
@REPLY
handle_t handle_out; /* handle to the screen buffer */
@END
/* Set info about a console (output only) */ /* Set info about a console (output only) */
@REQ(set_console_info) @REQ(set_console_output_info)
handle_t handle; /* handle to the console */ handle_t handle; /* handle to the console */
int mask; /* setting mask (see below) */ int mask; /* setting mask (see below) */
int cursor_size; /* size of cursor (percentage filled) */ short int cursor_size; /* size of cursor (percentage filled) */
int cursor_visible;/* cursor visibility flag */ short int cursor_visible;/* cursor visibility flag */
VARARG(title,string); /* console title */ short int cursor_x; /* position of cursor (x, y) */
@END short int cursor_y;
#define SET_CONSOLE_INFO_CURSOR 0x01 short int width; /* width of the screen buffer */
#define SET_CONSOLE_INFO_TITLE 0x02 short int height; /* height of the screen buffer */
short int attr; /* default attribute */
short int win_left; /* window actually displayed by renderer */
short int win_top; /* the rect area is expressed withing the */
short int win_right; /* boundaries of the screen buffer */
short int win_bottom;
short int max_width; /* maximum size (width x height) for the window */
short int max_height;
@END
#define SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM 0x01
#define SET_CONSOLE_OUTPUT_INFO_CURSOR_POS 0x02
#define SET_CONSOLE_OUTPUT_INFO_SIZE 0x04
#define SET_CONSOLE_OUTPUT_INFO_ATTR 0x08
#define SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW 0x10
#define SET_CONSOLE_OUTPUT_INFO_MAX_SIZE 0x20
/* Get info about a console (output only) */ /* Get info about a console (output only) */
@REQ(get_console_info) @REQ(get_console_output_info)
handle_t handle; /* handle to the console */ handle_t handle; /* handle to the console */
@REPLY @REPLY
int cursor_size; /* size of cursor (percentage filled) */ short int cursor_size; /* size of cursor (percentage filled) */
int cursor_visible;/* cursor visibility flag */ short int cursor_visible;/* cursor visibility flag */
int pid; /* pid of xterm (hack) */ short int cursor_x; /* position of cursor (x, y) */
VARARG(title,string); /* console title */ short int cursor_y;
short int width; /* width of the screen buffer */
short int height; /* height of the screen buffer */
short int attr; /* default attribute */
short int win_left; /* window actually displayed by renderer */
short int win_top; /* the rect area is expressed withing the */
short int win_right; /* boundaries of the screen buffer */
short int win_bottom;
short int max_width; /* maximum size (width x height) for the window */
short int max_height;
@END @END
/* Add input records to a console input queue */ /* Add input records to a console input queue */
@REQ(write_console_input) @REQ(write_console_input)
handle_t handle; /* handle to the console input */ handle_t handle; /* handle to the console input */
...@@ -764,6 +887,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; ...@@ -764,6 +887,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
int written; /* number of records written */ int written; /* number of records written */
@END @END
/* Fetch input records from a console input queue */ /* Fetch input records from a console input queue */
@REQ(read_console_input) @REQ(read_console_input)
handle_t handle; /* handle to the console input */ handle_t handle; /* handle to the console input */
...@@ -774,6 +898,49 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; ...@@ -774,6 +898,49 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@END @END
/* write data (chars and/or attributes) in a screen buffer */
@REQ(write_console_output)
handle_t handle; /* handle to the console input */
int mode; /* 0 for text, 1, for attributes, 2 for both */
/* bit3 (4) set if uniform pattern in data */
short int x; /* position where to start writing */
short int y;
VARARG(data,bytes); /* info to write */
@REPLY
int written; /* number of bytes actually written */
@END
#define WRITE_CONSOLE_MODE_TEXT 0x00
#define WRITE_CONSOLE_MODE_ATTR 0x01
#define WRITE_CONSOLE_MODE_TEXTATTR 0x02
#define WRITE_CONSOLE_MODE_TEXTSTDATTR 0x03
#define WRITE_CONSOLE_MODE_UNIFORM 0x04
/* read data (chars and/or attrubutes) from a screen buffer */
@REQ(read_console_output)
handle_t handle; /* handle to the console input */
short int x; /* position (x,y) where to start reading from */
short int y;
short int w; /* size of area to read from (width x height) */
short int h;
@REPLY
short int eff_w; /* effective width read */
short int eff_h; /* effective height read */
VARARG(data,bytes);
@END
/* move a rect (of data) in screen buffer content */
@REQ(move_console_output)
handle_t handle; /* handle to the console output */
short int x_src; /* position (x, y) of rect to start moving from */
short int y_src;
short int x_dst; /* position (x, y) of rect to move to */
short int y_dst;
short int w; /* size of the rect (width, height) to move */
short int h;
@END
/* Create a change notification */ /* Create a change notification */
@REQ(create_change_notification) @REQ(create_change_notification)
int subtree; /* watch all the subtree */ int subtree; /* watch all the subtree */
......
...@@ -118,14 +118,22 @@ DECL_HANDLER(get_socket_event); ...@@ -118,14 +118,22 @@ DECL_HANDLER(get_socket_event);
DECL_HANDLER(enable_socket_event); DECL_HANDLER(enable_socket_event);
DECL_HANDLER(alloc_console); DECL_HANDLER(alloc_console);
DECL_HANDLER(free_console); DECL_HANDLER(free_console);
DECL_HANDLER(get_console_renderer_events);
DECL_HANDLER(open_console); DECL_HANDLER(open_console);
DECL_HANDLER(set_console_fd);
DECL_HANDLER(get_console_mode); DECL_HANDLER(get_console_mode);
DECL_HANDLER(set_console_mode); DECL_HANDLER(set_console_mode);
DECL_HANDLER(set_console_info); DECL_HANDLER(set_console_input_info);
DECL_HANDLER(get_console_info); DECL_HANDLER(get_console_input_info);
DECL_HANDLER(append_console_input_history);
DECL_HANDLER(get_console_input_history);
DECL_HANDLER(create_console_output);
DECL_HANDLER(set_console_output_info);
DECL_HANDLER(get_console_output_info);
DECL_HANDLER(write_console_input); DECL_HANDLER(write_console_input);
DECL_HANDLER(read_console_input); DECL_HANDLER(read_console_input);
DECL_HANDLER(write_console_output);
DECL_HANDLER(read_console_output);
DECL_HANDLER(move_console_output);
DECL_HANDLER(create_change_notification); DECL_HANDLER(create_change_notification);
DECL_HANDLER(create_mapping); DECL_HANDLER(create_mapping);
DECL_HANDLER(open_mapping); DECL_HANDLER(open_mapping);
...@@ -264,14 +272,22 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = ...@@ -264,14 +272,22 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_enable_socket_event, (req_handler)req_enable_socket_event,
(req_handler)req_alloc_console, (req_handler)req_alloc_console,
(req_handler)req_free_console, (req_handler)req_free_console,
(req_handler)req_get_console_renderer_events,
(req_handler)req_open_console, (req_handler)req_open_console,
(req_handler)req_set_console_fd,
(req_handler)req_get_console_mode, (req_handler)req_get_console_mode,
(req_handler)req_set_console_mode, (req_handler)req_set_console_mode,
(req_handler)req_set_console_info, (req_handler)req_set_console_input_info,
(req_handler)req_get_console_info, (req_handler)req_get_console_input_info,
(req_handler)req_append_console_input_history,
(req_handler)req_get_console_input_history,
(req_handler)req_create_console_output,
(req_handler)req_set_console_output_info,
(req_handler)req_get_console_output_info,
(req_handler)req_write_console_input, (req_handler)req_write_console_input,
(req_handler)req_read_console_input, (req_handler)req_read_console_input,
(req_handler)req_write_console_output,
(req_handler)req_read_console_output,
(req_handler)req_move_console_output,
(req_handler)req_create_change_notification, (req_handler)req_create_change_notification,
(req_handler)req_create_mapping, (req_handler)req_create_mapping,
(req_handler)req_open_mapping, (req_handler)req_open_mapping,
......
...@@ -721,6 +721,7 @@ static void dump_create_file_reply( const struct create_file_request *req ) ...@@ -721,6 +721,7 @@ static void dump_create_file_reply( const struct create_file_request *req )
static void dump_alloc_file_handle_request( const struct alloc_file_handle_request *req ) static void dump_alloc_file_handle_request( const struct alloc_file_handle_request *req )
{ {
fprintf( stderr, " access=%08x,", req->access ); fprintf( stderr, " access=%08x,", req->access );
fprintf( stderr, " inherit=%d,", req->inherit );
fprintf( stderr, " fd=%d", req->fd ); fprintf( stderr, " fd=%d", req->fd );
} }
...@@ -881,24 +882,37 @@ static void dump_enable_socket_event_request( const struct enable_socket_event_r ...@@ -881,24 +882,37 @@ static void dump_enable_socket_event_request( const struct enable_socket_event_r
static void dump_alloc_console_request( const struct alloc_console_request *req ) static void dump_alloc_console_request( const struct alloc_console_request *req )
{ {
fprintf( stderr, " access=%08x,", req->access ); fprintf( stderr, " access=%08x,", req->access );
fprintf( stderr, " inherit=%d", req->inherit ); fprintf( stderr, " inherit=%d,", req->inherit );
fprintf( stderr, " pid=%p", req->pid );
} }
static void dump_alloc_console_reply( const struct alloc_console_request *req ) static void dump_alloc_console_reply( const struct alloc_console_request *req )
{ {
fprintf( stderr, " handle_in=%d,", req->handle_in ); fprintf( stderr, " handle_in=%d,", req->handle_in );
fprintf( stderr, " handle_out=%d", req->handle_out ); fprintf( stderr, " event=%d", req->event );
} }
static void dump_free_console_request( const struct free_console_request *req ) static void dump_free_console_request( const struct free_console_request *req )
{ {
} }
static void dump_get_console_renderer_events_request( const struct get_console_renderer_events_request *req )
{
fprintf( stderr, " handle=%d", req->handle );
}
static void dump_get_console_renderer_events_reply( const struct get_console_renderer_events_request *req )
{
fprintf( stderr, " data=" );
cur_pos += dump_varargs_bytes( req );
}
static void dump_open_console_request( const struct open_console_request *req ) static void dump_open_console_request( const struct open_console_request *req )
{ {
fprintf( stderr, " output=%d,", req->output ); fprintf( stderr, " from=%d,", req->from );
fprintf( stderr, " access=%08x,", req->access ); fprintf( stderr, " access=%08x,", req->access );
fprintf( stderr, " inherit=%d", req->inherit ); fprintf( stderr, " inherit=%d,", req->inherit );
fprintf( stderr, " share=%d", req->share );
} }
static void dump_open_console_reply( const struct open_console_request *req ) static void dump_open_console_reply( const struct open_console_request *req )
...@@ -906,14 +920,6 @@ static void dump_open_console_reply( const struct open_console_request *req ) ...@@ -906,14 +920,6 @@ static void dump_open_console_reply( const struct open_console_request *req )
fprintf( stderr, " handle=%d", req->handle ); fprintf( stderr, " handle=%d", req->handle );
} }
static void dump_set_console_fd_request( const struct set_console_fd_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " fd_in=%d,", req->fd_in );
fprintf( stderr, " fd_out=%d,", req->fd_out );
fprintf( stderr, " pid=%d", req->pid );
}
static void dump_get_console_mode_request( const struct get_console_mode_request *req ) static void dump_get_console_mode_request( const struct get_console_mode_request *req )
{ {
fprintf( stderr, " handle=%d", req->handle ); fprintf( stderr, " handle=%d", req->handle );
...@@ -930,28 +936,102 @@ static void dump_set_console_mode_request( const struct set_console_mode_request ...@@ -930,28 +936,102 @@ static void dump_set_console_mode_request( const struct set_console_mode_request
fprintf( stderr, " mode=%d", req->mode ); fprintf( stderr, " mode=%d", req->mode );
} }
static void dump_set_console_info_request( const struct set_console_info_request *req ) static void dump_set_console_input_info_request( const struct set_console_input_info_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " mask=%d,", req->mask );
fprintf( stderr, " active_sb=%d,", req->active_sb );
fprintf( stderr, " history_mode=%d,", req->history_mode );
fprintf( stderr, " history_size=%d,", req->history_size );
fprintf( stderr, " title=" );
cur_pos += dump_varargs_unicode_str( req );
}
static void dump_get_console_input_info_request( const struct get_console_input_info_request *req )
{
fprintf( stderr, " handle=%d", req->handle );
}
static void dump_get_console_input_info_reply( const struct get_console_input_info_request *req )
{
fprintf( stderr, " history_mode=%d,", req->history_mode );
fprintf( stderr, " history_size=%d,", req->history_size );
fprintf( stderr, " history_index=%d,", req->history_index );
fprintf( stderr, " title=" );
cur_pos += dump_varargs_unicode_str( req );
}
static void dump_append_console_input_history_request( const struct append_console_input_history_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " line=" );
cur_pos += dump_varargs_unicode_str( req );
}
static void dump_get_console_input_history_request( const struct get_console_input_history_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " index=%d", req->index );
}
static void dump_get_console_input_history_reply( const struct get_console_input_history_request *req )
{
fprintf( stderr, " line=" );
cur_pos += dump_varargs_unicode_str( req );
}
static void dump_create_console_output_request( const struct create_console_output_request *req )
{
fprintf( stderr, " handle_in=%d,", req->handle_in );
fprintf( stderr, " access=%d,", req->access );
fprintf( stderr, " share=%d,", req->share );
fprintf( stderr, " inherit=%d", req->inherit );
}
static void dump_create_console_output_reply( const struct create_console_output_request *req )
{
fprintf( stderr, " handle_out=%d", req->handle_out );
}
static void dump_set_console_output_info_request( const struct set_console_output_info_request *req )
{ {
fprintf( stderr, " handle=%d,", req->handle ); fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " mask=%d,", req->mask ); fprintf( stderr, " mask=%d,", req->mask );
fprintf( stderr, " cursor_size=%d,", req->cursor_size ); fprintf( stderr, " cursor_size=%d,", req->cursor_size );
fprintf( stderr, " cursor_visible=%d,", req->cursor_visible ); fprintf( stderr, " cursor_visible=%d,", req->cursor_visible );
fprintf( stderr, " title=" ); fprintf( stderr, " cursor_x=%d,", req->cursor_x );
cur_pos += dump_varargs_string( req ); fprintf( stderr, " cursor_y=%d,", req->cursor_y );
fprintf( stderr, " width=%d,", req->width );
fprintf( stderr, " height=%d,", req->height );
fprintf( stderr, " attr=%d,", req->attr );
fprintf( stderr, " win_left=%d,", req->win_left );
fprintf( stderr, " win_top=%d,", req->win_top );
fprintf( stderr, " win_right=%d,", req->win_right );
fprintf( stderr, " win_bottom=%d,", req->win_bottom );
fprintf( stderr, " max_width=%d,", req->max_width );
fprintf( stderr, " max_height=%d", req->max_height );
} }
static void dump_get_console_info_request( const struct get_console_info_request *req ) static void dump_get_console_output_info_request( const struct get_console_output_info_request *req )
{ {
fprintf( stderr, " handle=%d", req->handle ); fprintf( stderr, " handle=%d", req->handle );
} }
static void dump_get_console_info_reply( const struct get_console_info_request *req ) static void dump_get_console_output_info_reply( const struct get_console_output_info_request *req )
{ {
fprintf( stderr, " cursor_size=%d,", req->cursor_size ); fprintf( stderr, " cursor_size=%d,", req->cursor_size );
fprintf( stderr, " cursor_visible=%d,", req->cursor_visible ); fprintf( stderr, " cursor_visible=%d,", req->cursor_visible );
fprintf( stderr, " pid=%d,", req->pid ); fprintf( stderr, " cursor_x=%d,", req->cursor_x );
fprintf( stderr, " title=" ); fprintf( stderr, " cursor_y=%d,", req->cursor_y );
cur_pos += dump_varargs_string( req ); fprintf( stderr, " width=%d,", req->width );
fprintf( stderr, " height=%d,", req->height );
fprintf( stderr, " attr=%d,", req->attr );
fprintf( stderr, " win_left=%d,", req->win_left );
fprintf( stderr, " win_top=%d,", req->win_top );
fprintf( stderr, " win_right=%d,", req->win_right );
fprintf( stderr, " win_bottom=%d,", req->win_bottom );
fprintf( stderr, " max_width=%d,", req->max_width );
fprintf( stderr, " max_height=%d", req->max_height );
} }
static void dump_write_console_input_request( const struct write_console_input_request *req ) static void dump_write_console_input_request( const struct write_console_input_request *req )
...@@ -979,6 +1059,49 @@ static void dump_read_console_input_reply( const struct read_console_input_reque ...@@ -979,6 +1059,49 @@ static void dump_read_console_input_reply( const struct read_console_input_reque
cur_pos += dump_varargs_input_records( req ); cur_pos += dump_varargs_input_records( req );
} }
static void dump_write_console_output_request( const struct write_console_output_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " mode=%d,", req->mode );
fprintf( stderr, " x=%d,", req->x );
fprintf( stderr, " y=%d,", req->y );
fprintf( stderr, " data=" );
cur_pos += dump_varargs_bytes( req );
}
static void dump_write_console_output_reply( const struct write_console_output_request *req )
{
fprintf( stderr, " written=%d", req->written );
}
static void dump_read_console_output_request( const struct read_console_output_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " x=%d,", req->x );
fprintf( stderr, " y=%d,", req->y );
fprintf( stderr, " w=%d,", req->w );
fprintf( stderr, " h=%d", req->h );
}
static void dump_read_console_output_reply( const struct read_console_output_request *req )
{
fprintf( stderr, " eff_w=%d,", req->eff_w );
fprintf( stderr, " eff_h=%d,", req->eff_h );
fprintf( stderr, " data=" );
cur_pos += dump_varargs_bytes( req );
}
static void dump_move_console_output_request( const struct move_console_output_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " x_src=%d,", req->x_src );
fprintf( stderr, " y_src=%d,", req->y_src );
fprintf( stderr, " x_dst=%d,", req->x_dst );
fprintf( stderr, " y_dst=%d,", req->y_dst );
fprintf( stderr, " w=%d,", req->w );
fprintf( stderr, " h=%d", req->h );
}
static void dump_create_change_notification_request( const struct create_change_notification_request *req ) static void dump_create_change_notification_request( const struct create_change_notification_request *req )
{ {
fprintf( stderr, " subtree=%d,", req->subtree ); fprintf( stderr, " subtree=%d,", req->subtree );
...@@ -1955,14 +2078,22 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { ...@@ -1955,14 +2078,22 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_enable_socket_event_request, (dump_func)dump_enable_socket_event_request,
(dump_func)dump_alloc_console_request, (dump_func)dump_alloc_console_request,
(dump_func)dump_free_console_request, (dump_func)dump_free_console_request,
(dump_func)dump_get_console_renderer_events_request,
(dump_func)dump_open_console_request, (dump_func)dump_open_console_request,
(dump_func)dump_set_console_fd_request,
(dump_func)dump_get_console_mode_request, (dump_func)dump_get_console_mode_request,
(dump_func)dump_set_console_mode_request, (dump_func)dump_set_console_mode_request,
(dump_func)dump_set_console_info_request, (dump_func)dump_set_console_input_info_request,
(dump_func)dump_get_console_info_request, (dump_func)dump_get_console_input_info_request,
(dump_func)dump_append_console_input_history_request,
(dump_func)dump_get_console_input_history_request,
(dump_func)dump_create_console_output_request,
(dump_func)dump_set_console_output_info_request,
(dump_func)dump_get_console_output_info_request,
(dump_func)dump_write_console_input_request, (dump_func)dump_write_console_input_request,
(dump_func)dump_read_console_input_request, (dump_func)dump_read_console_input_request,
(dump_func)dump_write_console_output_request,
(dump_func)dump_read_console_output_request,
(dump_func)dump_move_console_output_request,
(dump_func)dump_create_change_notification_request, (dump_func)dump_create_change_notification_request,
(dump_func)dump_create_mapping_request, (dump_func)dump_create_mapping_request,
(dump_func)dump_open_mapping_request, (dump_func)dump_open_mapping_request,
...@@ -2098,14 +2229,22 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { ...@@ -2098,14 +2229,22 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)0, (dump_func)0,
(dump_func)dump_alloc_console_reply, (dump_func)dump_alloc_console_reply,
(dump_func)0, (dump_func)0,
(dump_func)dump_get_console_renderer_events_reply,
(dump_func)dump_open_console_reply, (dump_func)dump_open_console_reply,
(dump_func)0,
(dump_func)dump_get_console_mode_reply, (dump_func)dump_get_console_mode_reply,
(dump_func)0, (dump_func)0,
(dump_func)0, (dump_func)0,
(dump_func)dump_get_console_info_reply, (dump_func)dump_get_console_input_info_reply,
(dump_func)0,
(dump_func)dump_get_console_input_history_reply,
(dump_func)dump_create_console_output_reply,
(dump_func)0,
(dump_func)dump_get_console_output_info_reply,
(dump_func)dump_write_console_input_reply, (dump_func)dump_write_console_input_reply,
(dump_func)dump_read_console_input_reply, (dump_func)dump_read_console_input_reply,
(dump_func)dump_write_console_output_reply,
(dump_func)dump_read_console_output_reply,
(dump_func)0,
(dump_func)dump_create_change_notification_reply, (dump_func)dump_create_change_notification_reply,
(dump_func)dump_create_mapping_reply, (dump_func)dump_create_mapping_reply,
(dump_func)dump_open_mapping_reply, (dump_func)dump_open_mapping_reply,
...@@ -2241,14 +2380,22 @@ static const char * const req_names[REQ_NB_REQUESTS] = { ...@@ -2241,14 +2380,22 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"enable_socket_event", "enable_socket_event",
"alloc_console", "alloc_console",
"free_console", "free_console",
"get_console_renderer_events",
"open_console", "open_console",
"set_console_fd",
"get_console_mode", "get_console_mode",
"set_console_mode", "set_console_mode",
"set_console_info", "set_console_input_info",
"get_console_info", "get_console_input_info",
"append_console_input_history",
"get_console_input_history",
"create_console_output",
"set_console_output_info",
"get_console_output_info",
"write_console_input", "write_console_input",
"read_console_input", "read_console_input",
"write_console_output",
"read_console_output",
"move_console_output",
"create_change_notification", "create_change_notification",
"create_mapping", "create_mapping",
"open_mapping", "open_mapping",
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
%formats = %formats =
( (
"int" => "%d", "int" => "%d",
"short int" => "%d",
"char" => "%c", "char" => "%c",
"unsigned char" => "%02x", "unsigned char" => "%02x",
"unsigned short"=> "%04x", "unsigned short"=> "%04x",
......
DEFS = @DLLFLAGS@ -D__WINE__ DEFS = @DLLFLAGS@ -D__WINE__ -DBINDIR="\"$(bindir)\""
TOPSRCDIR = @top_srcdir@ TOPSRCDIR = @top_srcdir@
TOPOBJDIR = .. TOPOBJDIR = ..
SRCDIR = @srcdir@ SRCDIR = @srcdir@
...@@ -8,6 +8,7 @@ MODULE = win32 ...@@ -8,6 +8,7 @@ MODULE = win32
C_SRCS = \ C_SRCS = \
console.c \ console.c \
device.c \ device.c \
editline.c \
except.c \ except.c \
file.c \ file.c \
init.c \ init.c \
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* line edition function for Win32 console
*
* Copyright 2001 Eric Pouech
*/
#include "config.h"
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wincon.h"
#include "wine/unicode.h"
#include "winnls.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(console);
/* console.c */
extern int CONSOLE_GetHistory(int idx, WCHAR* buf, int buf_len);
extern BOOL CONSOLE_AppendHistory(const WCHAR *p);
extern unsigned int CONSOLE_GetNumHistoryEntries(void);
struct WCEL_Context;
typedef struct
{
WCHAR val; /* vk or unicode char */
void (*func)(struct WCEL_Context* ctx);
} KeyEntry;
typedef struct
{
DWORD keyState; /* keyState (from INPUT_RECORD) to match */
BOOL chkChar; /* check vk or char */
KeyEntry* entries; /* array of entries */
} KeyMap;
typedef struct WCEL_Context {
WCHAR* line; /* the line being edited */
size_t alloc; /* number of WCHAR in line */
unsigned len; /* number of chars in line */
unsigned ofs; /* offset for cursor in current line */
WCHAR* yanked; /* yanked line */
unsigned mark; /* marked point (emacs mode only) */
CONSOLE_SCREEN_BUFFER_INFO csbi; /* current state (initial cursor, window size, attribute) */
HANDLE hConIn;
HANDLE hConOut;
unsigned done : 1, /* to 1 when we're done with editing */
error : 1; /* to 1 when an error occurred in the editing */
unsigned histSize;
unsigned histPos;
WCHAR* histCurr;
} WCEL_Context;
#if 0
static void WCEL_Dump(WCEL_Context* ctx, const char* pfx)
{
MESSAGE("%s: [line=%s[alloc=%u] ofs=%u len=%u start=(%d,%d) mask=%c%c\n"
"\t\thist=(size=%u pos=%u curr=%s)\n",
pfx, debugstr_w(ctx->line), ctx->alloc, ctx->ofs, ctx->len,
ctx->csbi.dwCursorPosition.X, ctx->csbi.dwCursorPosition.Y,
ctx->done ? 'D' : 'd', ctx->error ? 'E' : 'e',
ctx->histSize, ctx->histPos, debugstr_w(ctx->histCurr));
}
#endif
/* ====================================================================
*
* Console helper functions
*
* ====================================================================*/
static BOOL WCEL_Get(WCEL_Context* ctx, INPUT_RECORD* ir)
{
DWORD retv;
for (;;)
{
/* data available ? */
if (ReadConsoleInputW(ctx->hConIn, ir, 1, &retv) && retv == 1)
return TRUE;
/* then wait... */
switch (WaitForSingleObject(ctx->hConIn, INFINITE))
{
case WAIT_OBJECT_0:
break;
default:
/* we have checked that hConIn was a console handle (could be sb) */
ERR("Shouldn't happen\n");
/* fall thru */
case WAIT_ABANDONED:
case WAIT_TIMEOUT:
ctx->error = 1;
ERR("hmm bad situation\n");
return FALSE;
}
}
}
static inline void WCEL_Beep(WCEL_Context* ctx)
{
Beep(400, 300);
}
static inline COORD WCEL_GetCoord(WCEL_Context* ctx, int ofs)
{
COORD c;
c.X = ctx->csbi.dwCursorPosition.X + ofs;
c.Y = ctx->csbi.dwCursorPosition.Y;
return c;
}
static inline void WCEL_GetRect(WCEL_Context* ctx, LPSMALL_RECT sr, int beg, int end)
{
sr->Left = ctx->csbi.dwCursorPosition.X + beg;
sr->Top = ctx->csbi.dwCursorPosition.Y;
sr->Right = ctx->csbi.dwCursorPosition.X + end;
sr->Bottom = ctx->csbi.dwCursorPosition.Y;
}
/* ====================================================================
*
* context manipulation functions
*
* ====================================================================*/
static BOOL WCEL_Grow(WCEL_Context* ctx, size_t len)
{
if (ctx->csbi.dwCursorPosition.X + ctx->ofs + len >= ctx->csbi.dwSize.X)
{
FIXME("Current implementation doesn't allow edition to spray across several lines\n");
return FALSE;
}
if (ctx->len + len >= ctx->alloc)
{
WCHAR* newline;
newline = HeapReAlloc(GetProcessHeap(), 0, ctx->line, sizeof(WCHAR) * (ctx->alloc + 32));
if (!newline) return FALSE;
ctx->line = newline;
ctx->alloc += 32;
}
return TRUE;
}
static void WCEL_DeleteString(WCEL_Context* ctx, int beg, int end)
{
SMALL_RECT scl, clp;
CHAR_INFO ci;
if (end < ctx->len)
memmove(&ctx->line[beg], &ctx->line[end], (ctx->len - end) * sizeof(WCHAR));
/* make the source rect bigger than the actual rect to that the part outside the clip
* rect (before the scroll) will get redrawn after the scroll
*/
WCEL_GetRect(ctx, &scl, end, ctx->len + end - beg);
WCEL_GetRect(ctx, &clp, beg, ctx->len);
ci.Char.UnicodeChar = ' ';
ci.Attributes = ctx->csbi.wAttributes;
ScrollConsoleScreenBufferW(ctx->hConOut, &scl, &clp, WCEL_GetCoord(ctx, beg), &ci);
ctx->len -= end - beg;
ctx->line[ctx->len] = 0;
}
static void WCEL_InsertString(WCEL_Context* ctx, const WCHAR* str)
{
size_t len = lstrlenW(str);
if (!len || !WCEL_Grow(ctx, len)) return;
if (ctx->len > ctx->ofs)
memmove(&ctx->line[ctx->ofs + len], &ctx->line[ctx->ofs], (ctx->len - ctx->ofs) * sizeof(WCHAR));
memcpy(&ctx->line[ctx->ofs], str, len * sizeof(WCHAR));
ctx->len += len;
ctx->line[ctx->len] = 0;
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], ctx->len - ctx->ofs,
WCEL_GetCoord(ctx, ctx->ofs), NULL);
ctx->ofs += len;
}
static void WCEL_InsertChar(WCEL_Context* ctx, WCHAR c)
{
WCHAR buffer[2];
/* do not insert 0..31 control characters */
if (c < ' ')
{
if (c != '\t') return;
}
buffer[0] = c;
buffer[1] = 0;
WCEL_InsertString(ctx, buffer);
}
static void WCEL_SaveYank(WCEL_Context* ctx, int beg, int end)
{
int len = end - beg;
ctx->yanked = HeapReAlloc(GetProcessHeap(), 0, ctx->yanked, (len + 1) * sizeof(WCHAR));
if (!ctx->yanked) return;
memcpy(ctx->yanked, &ctx->line[beg], len * sizeof(WCHAR));
ctx->yanked[len] = 0;
}
/* FIXME NTDLL doesn't export iswalnum, and I don't want to link in msvcrt when most
* of the data lay in unicode lib
*/
static inline BOOL WCEL_iswalnum(WCHAR wc)
{
return get_char_typeW(wc) & (C1_ALPHA|C1_DIGIT|C1_LOWER|C1_UPPER);
}
static int WCEL_GetLeftWordTransition(WCEL_Context* ctx, int ofs)
{
ofs--;
while (ofs >= 0 && !WCEL_iswalnum(ctx->line[ofs])) ofs--;
while (ofs >= 0 && WCEL_iswalnum(ctx->line[ofs])) ofs--;
if (ofs >= 0) ofs++;
return max(ofs, 0);
}
static int WCEL_GetRightWordTransition(WCEL_Context* ctx, int ofs)
{
ofs++;
while (ofs <= ctx->len && !WCEL_iswalnum(ctx->line[ofs])) ofs++;
while (ofs <= ctx->len && WCEL_iswalnum(ctx->line[ofs])) ofs++;
return min(ofs, ctx->len);
}
static WCHAR* WCEL_GetHistory(WCEL_Context* ctx, int idx)
{
WCHAR* ptr;
if (idx == ctx->histSize - 1)
{
ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(ctx->histCurr) + 1) * sizeof(WCHAR));
lstrcpyW(ptr, ctx->histCurr);
}
else
{
int len = CONSOLE_GetHistory(idx, NULL, 0);
if ((ptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
{
CONSOLE_GetHistory(idx, ptr, len);
}
}
return ptr;
}
static void WCEL_HistoryInit(WCEL_Context* ctx)
{
ctx->histPos = CONSOLE_GetNumHistoryEntries();
ctx->histSize = ctx->histPos + 1;
ctx->histCurr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR));
}
static void WCEL_MoveToHist(WCEL_Context* ctx, int idx)
{
WCHAR* data = WCEL_GetHistory(ctx, idx);
int len = lstrlenW(data) + 1;
/* save current line edition for recall when needed (FIXME seems broken to me) */
if (ctx->histPos == ctx->histSize - 1)
{
if (ctx->histCurr) HeapFree(GetProcessHeap(), 0, ctx->histCurr);
ctx->histCurr = HeapAlloc(GetProcessHeap(), 0, (ctx->len + 1) * sizeof(WCHAR));
memcpy(ctx->histCurr, ctx->line, (ctx->len + 1) * sizeof(WCHAR));
}
/* need to clean also the screen if new string is shorter than old one */
WCEL_DeleteString(ctx, 0, ctx->len);
ctx->ofs = 0;
/* insert new string */
if (WCEL_Grow(ctx, len))
{
WCEL_InsertString(ctx, data);
HeapFree(GetProcessHeap(), 0, data);
ctx->histPos = idx;
}
}
/* ====================================================================
*
* basic edition functions
*
* ====================================================================*/
static void WCEL_Done(WCEL_Context* ctx)
{
if (!WCEL_Grow(ctx, 1)) return;
ctx->line[ctx->len++] = '\n';
ctx->line[ctx->len] = 0;
WriteConsoleA(ctx->hConOut, "\n", 1, NULL, NULL);
ctx->done = 1;
}
static void WCEL_MoveLeft(WCEL_Context* ctx)
{
if (ctx->ofs > 0) ctx->ofs--;
}
static void WCEL_MoveRight(WCEL_Context* ctx)
{
if (ctx->ofs < ctx->len) ctx->ofs++;
}
static void WCEL_MoveToLeftWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetLeftWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs) ctx->ofs = new_ofs;
}
static void WCEL_MoveToRightWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs) ctx->ofs = new_ofs;
}
static void WCEL_MoveToBeg(WCEL_Context* ctx)
{
ctx->ofs = 0;
}
static void WCEL_MoveToEnd(WCEL_Context* ctx)
{
ctx->ofs = ctx->len;
}
static void WCEL_SetMark(WCEL_Context* ctx)
{
ctx->mark = ctx->ofs;
}
static void WCEL_ExchangeMark(WCEL_Context* ctx)
{
unsigned tmp;
if (ctx->mark > ctx->len) return;
tmp = ctx->ofs;
ctx->ofs = ctx->mark;
ctx->mark = tmp;
}
static void WCEL_CopyMarkedZone(WCEL_Context* ctx)
{
unsigned beg, end;
if (ctx->mark > ctx->len || ctx->mark == ctx->ofs) return;
if (ctx->mark > ctx->ofs)
{
beg = ctx->ofs; end = ctx->mark;
}
else
{
beg = ctx->mark; end = ctx->ofs;
}
WCEL_SaveYank(ctx, beg, end);
}
static void WCEL_TransposeChar(WCEL_Context* ctx)
{
WCHAR c;
if (!ctx->ofs || ctx->ofs == ctx->len) return;
c = ctx->line[ctx->ofs];
ctx->line[ctx->ofs] = ctx->line[ctx->ofs - 1];
ctx->line[ctx->ofs - 1] = c;
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs - 1], 2, WCEL_GetCoord(ctx, ctx->ofs - 1), NULL);
ctx->ofs++;
}
static void WCEL_TransposeWords(WCEL_Context* ctx)
{
FIXME("NIY\n");
}
static void WCEL_LowerCaseWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
int i;
for (i = ctx->ofs; i <= new_ofs; i++)
ctx->line[i] = tolowerW(ctx->line[i]);
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1,
WCEL_GetCoord(ctx, ctx->ofs), NULL);
ctx->ofs = new_ofs;
}
}
static void WCEL_UpperCaseWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
int i;
for (i = ctx->ofs; i <= new_ofs; i++)
ctx->line[i] = toupperW(ctx->line[i]);
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1,
WCEL_GetCoord(ctx, ctx->ofs), NULL);
ctx->ofs = new_ofs;
}
}
static void WCEL_CapitalizeWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
int i;
ctx->line[ctx->ofs] = toupperW(ctx->line[ctx->ofs]);
for (i = ctx->ofs + 1; i <= new_ofs; i++)
ctx->line[i] = tolowerW(ctx->line[i]);
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1,
WCEL_GetCoord(ctx, ctx->ofs), NULL);
ctx->ofs = new_ofs;
}
}
static void WCEL_Yank(WCEL_Context* ctx)
{
WCEL_InsertString(ctx, ctx->yanked);
HeapFree(GetProcessHeap(), 0, ctx->yanked);
ctx->yanked = NULL;
}
static void WCEL_KillToEndOfLine(WCEL_Context* ctx)
{
WCEL_SaveYank(ctx, ctx->ofs, ctx->len);
WCEL_DeleteString(ctx, ctx->ofs, ctx->len);
}
static void WCEL_KillMarkedZone(WCEL_Context* ctx)
{
unsigned beg, end;
if (ctx->mark > ctx->len || ctx->mark == ctx->ofs) return;
if (ctx->mark > ctx->ofs)
{
beg = ctx->ofs; end = ctx->mark;
}
else
{
beg = ctx->mark; end = ctx->ofs;
}
WCEL_SaveYank(ctx, beg, end);
WCEL_DeleteString(ctx, beg, end);
ctx->ofs = beg;
}
static void WCEL_DeletePrevChar(WCEL_Context* ctx)
{
if (ctx->ofs)
{
WCEL_DeleteString(ctx, ctx->ofs - 1, ctx->ofs);
ctx->ofs--;
}
}
static void WCEL_DeleteCurrChar(WCEL_Context* ctx)
{
if (ctx->ofs < ctx->len)
WCEL_DeleteString(ctx, ctx->ofs, ctx->ofs + 1);
}
static void WCEL_DeleteLeftWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetLeftWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
WCEL_DeleteString(ctx, new_ofs, ctx->ofs);
ctx->ofs = new_ofs;
}
}
static void WCEL_DeleteRightWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
WCEL_DeleteString(ctx, ctx->ofs, new_ofs);
}
}
static void WCEL_MoveToPrevHist(WCEL_Context* ctx)
{
if (ctx->histPos) WCEL_MoveToHist(ctx, ctx->histPos - 1);
}
static void WCEL_MoveToNextHist(WCEL_Context* ctx)
{
if (ctx->histPos < ctx->histSize - 1) WCEL_MoveToHist(ctx, ctx->histPos + 1);
}
static void WCEL_MoveToFirstHist(WCEL_Context* ctx)
{
if (ctx->histPos != 0) WCEL_MoveToHist(ctx, 0);
}
static void WCEL_MoveToLastHist(WCEL_Context* ctx)
{
if (ctx->histPos != ctx->histSize - 1) WCEL_MoveToHist(ctx, ctx->histSize - 1);
}
/* ====================================================================
*
* Key Maps
*
* ====================================================================*/
#define CTRL(x) ((x) - '@')
static KeyEntry StdKeyMap[] =
{
{/*BACK*/0x08, WCEL_DeletePrevChar },
{/*RETURN*/0x0d, WCEL_Done },
{/*DEL*/127, WCEL_DeleteCurrChar },
{ 0, NULL }
};
static KeyEntry EmacsKeyMapCtrl[] =
{
{ CTRL('@'), WCEL_SetMark },
{ CTRL('A'), WCEL_MoveToBeg },
{ CTRL('B'), WCEL_MoveLeft },
/* C */
{ CTRL('D'), WCEL_DeleteCurrChar },
{ CTRL('E'), WCEL_MoveToEnd },
{ CTRL('F'), WCEL_MoveRight },
{ CTRL('G'), WCEL_Beep },
{ CTRL('H'), WCEL_DeletePrevChar },
/* I: meaningless (or tab ???) */
{ CTRL('J'), WCEL_Done },
{ CTRL('K'), WCEL_KillToEndOfLine },
/* L: [NIY] redraw the whole stuff */
{ CTRL('M'), WCEL_Done },
{ CTRL('N'), WCEL_MoveToNextHist },
/* O; insert line... meaningless */
{ CTRL('P'), WCEL_MoveToPrevHist },
/* Q: [NIY] quoting... */
/* R: [NIY] search backwards... */
/* S: [NIY] search forwards... */
{ CTRL('T'), WCEL_TransposeChar },
/* U: [NIY] set repeat count... */
/* V: paragraph down... meaningless */
{ CTRL('W'), WCEL_KillMarkedZone },
{ CTRL('X'), WCEL_ExchangeMark },
{ CTRL('Y'), WCEL_Yank },
/* Z: meaningless */
{ 0, NULL }
};
static KeyEntry EmacsKeyMapAlt[] =
{
{/*DEL*/127, WCEL_DeleteLeftWord },
{ '<', WCEL_MoveToFirstHist },
{ '>', WCEL_MoveToLastHist },
{ '?', WCEL_Beep },
{ 'b', WCEL_MoveToLeftWord },
{ 'c', WCEL_CapitalizeWord },
{ 'd', WCEL_DeleteRightWord },
{ 'f', WCEL_MoveToRightWord },
{ 'l', WCEL_LowerCaseWord },
{ 't', WCEL_TransposeWords },
{ 'u', WCEL_UpperCaseWord },
{ 'w', WCEL_CopyMarkedZone },
{ 0, NULL }
};
static KeyEntry EmacsKeyMapExtended[] =
{
{/*VK_PRIOR*/0x21, WCEL_MoveToPrevHist },
{/*VK_NEXT*/0x22, WCEL_MoveToNextHist },
{/*VK_RIGHT*/0x27, WCEL_MoveRight },
{/*VK_LEFT*/0x25, WCEL_MoveLeft },
{ 0, NULL }
};
static KeyMap EmacsKeyMap[] =
{
{0x00000000, 1, StdKeyMap},
{0x00000001, 1, EmacsKeyMapAlt}, /* left alt */
{0x00000002, 1, EmacsKeyMapAlt}, /* right alt */
{0x00000004, 1, EmacsKeyMapCtrl}, /* left ctrl */
{0x00000008, 1, EmacsKeyMapCtrl}, /* right ctrl */
{0x00000100, 0, EmacsKeyMapExtended},
{0, 0, 0}
};
static KeyEntry Win32KeyMapExtended[] =
{
{/*VK_LEFT*/ 0x25, WCEL_MoveLeft },
{/*VK_RIGHT*/0x27, WCEL_MoveRight },
{/*VK_HOME*/ 0x24, WCEL_MoveToBeg },
{/*VK_END*/ 0x23, WCEL_MoveToEnd },
{/*VK_UP*/ 0x26, WCEL_MoveToPrevHist },
{/*VK_DOWN*/ 0x28, WCEL_MoveToNextHist },
{ 0, NULL }
};
static KeyEntry Win32KeyMapCtrlExtended[] =
{
{/*VK_LEFT*/ 0x25, WCEL_MoveToLeftWord },
{/*VK_RIGHT*/0x27, WCEL_MoveToRightWord },
{ 0, NULL }
};
KeyMap Win32KeyMap[] =
{
{0x00000000, 1, StdKeyMap},
{0x00000100, 0, Win32KeyMapExtended},
{0x00000104, 0, Win32KeyMapCtrlExtended},
{0x00000108, 0, Win32KeyMapCtrlExtended},
{0, 0, 0}
};
#undef CTRL
/* ====================================================================
*
* Read line master function
*
* ====================================================================*/
WCHAR* CONSOLE_Readline(HANDLE hConsoleIn, int use_emacs)
{
WCEL_Context ctx;
INPUT_RECORD ir;
KeyMap* km;
KeyEntry* ke;
unsigned ofs;
void (*func)(struct WCEL_Context* ctx);
memset(&ctx, 0, sizeof(ctx));
ctx.hConIn = hConsoleIn;
WCEL_HistoryInit(&ctx);
if ((ctx.hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE ||
!GetConsoleScreenBufferInfo(ctx.hConOut, &ctx.csbi))
return NULL;
if (!WCEL_Grow(&ctx, 1))
{
CloseHandle(ctx.hConOut);
return NULL;
}
ctx.line[0] = 0;
/* EPP WCEL_Dump(&ctx, "init"); */
while (!ctx.done && !ctx.error && WCEL_Get(&ctx, &ir))
{
if (ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown) continue;
TRACE("key%s repeatCount=%u, keyCode=%02x scanCode=%02x char=%02x keyState=%08lx\n",
ir.Event.KeyEvent.bKeyDown ? "Down" : "Up ", ir.Event.KeyEvent.wRepeatCount,
ir.Event.KeyEvent.wVirtualKeyCode, ir.Event.KeyEvent.wVirtualScanCode,
ir.Event.KeyEvent.uChar.UnicodeChar, ir.Event.KeyEvent.dwControlKeyState);
/* EPP WCEL_Dump(&ctx, "before func"); */
ofs = ctx.ofs;
func = NULL;
for (km = (use_emacs) ? EmacsKeyMap : Win32KeyMap; km->entries != NULL; km++)
{
if (km->keyState != ir.Event.KeyEvent.dwControlKeyState)
continue;
if (km->chkChar)
{
for (ke = &km->entries[0]; ke->func != 0; ke++)
if (ke->val == ir.Event.KeyEvent.uChar.UnicodeChar) break;
}
else
{
for (ke = &km->entries[0]; ke->func != 0; ke++)
if (ke->val == ir.Event.KeyEvent.wVirtualKeyCode) break;
}
if (ke->func)
{
func = ke->func;
break;
}
}
if (func)
(func)(&ctx);
else if (!(ir.Event.KeyEvent.dwControlKeyState & (ENHANCED_KEY|LEFT_ALT_PRESSED)))
WCEL_InsertChar(&ctx, ir.Event.KeyEvent.uChar.UnicodeChar);
else TRACE("Dropped event\n");
/* EPP WCEL_Dump(&ctx, "after func"); */
if (ctx.ofs != ofs)
SetConsoleCursorPosition(ctx.hConOut, WCEL_GetCoord(&ctx, ctx.ofs));
}
if (ctx.error)
{
HeapFree(GetProcessHeap(), 0, ctx.line);
ctx.line = NULL;
}
if (ctx.line)
CONSOLE_AppendHistory(ctx.line);
CloseHandle(ctx.hConOut);
if (ctx.histCurr) HeapFree(GetProcessHeap(), 0, ctx.histCurr);
return ctx.line;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment