New console code based on Win32 windows.
This commit is contained in:
parent
6b6596a1e3
commit
0b83d4cbc6
|
@ -28,7 +28,8 @@ PROGRAMS = \
|
|||
|
||||
# Programs that link with libwine
|
||||
LIBPROGRAMS = \
|
||||
debugger/winedbg
|
||||
debugger/winedbg \
|
||||
programs/wineconsole/wineconsole
|
||||
|
||||
# Libraries (not dlls) to build
|
||||
LIBRARIES = \
|
||||
|
@ -59,6 +60,7 @@ INSTALLSUBDIRS = \
|
|||
include \
|
||||
library \
|
||||
ole \
|
||||
programs/wineconsole \
|
||||
server \
|
||||
tools \
|
||||
tsx11 \
|
||||
|
|
|
@ -7166,6 +7166,7 @@ programs/regtest/Makefile
|
|||
programs/uninstaller/Makefile
|
||||
programs/view/Makefile
|
||||
programs/wcmd/Makefile
|
||||
programs/wineconsole/Makefile
|
||||
programs/winemine/Makefile
|
||||
programs/winetest/Makefile
|
||||
programs/winhelp/Makefile
|
||||
|
@ -7426,6 +7427,7 @@ programs/regtest/Makefile
|
|||
programs/uninstaller/Makefile
|
||||
programs/view/Makefile
|
||||
programs/wcmd/Makefile
|
||||
programs/wineconsole/Makefile
|
||||
programs/winemine/Makefile
|
||||
programs/winetest/Makefile
|
||||
programs/winhelp/Makefile
|
||||
|
|
|
@ -1336,6 +1336,7 @@ programs/regtest/Makefile
|
|||
programs/uninstaller/Makefile
|
||||
programs/view/Makefile
|
||||
programs/wcmd/Makefile
|
||||
programs/wineconsole/Makefile
|
||||
programs/winemine/Makefile
|
||||
programs/winetest/Makefile
|
||||
programs/winhelp/Makefile
|
||||
|
|
|
@ -444,7 +444,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
|
|||
if (synchronous) XSynchronize( data->display, True );
|
||||
wine_tsx11_unlock();
|
||||
data->display_fd = FILE_DupUnixHandle( ConnectionNumber(data->display),
|
||||
GENERIC_READ | SYNCHRONIZE );
|
||||
GENERIC_READ | SYNCHRONIZE, FALSE );
|
||||
data->process_event_count = 0;
|
||||
NtCurrentTeb()->driver_data = data;
|
||||
return data;
|
||||
|
|
|
@ -93,6 +93,17 @@ Options:
|
|||
options that affect the Windows program should come
|
||||
<emphasis>after</emphasis> it.
|
||||
</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 id="command-line-options">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.\" -*- 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
|
||||
wine \- run Windows programs on Unix
|
||||
.SH SYNOPSIS
|
||||
|
@ -20,6 +20,16 @@ For debugging wine, use
|
|||
.I program
|
||||
instead.
|
||||
.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
|
||||
currently runs a growing list of applications written for all kinds of
|
||||
Windows versions >= Win2.0, e.g. Win3.1, Win95/98, NT.
|
||||
|
@ -350,6 +360,11 @@ The
|
|||
.B wine
|
||||
program loader.
|
||||
.TP
|
||||
.I @prefix@/bin/wineconsole
|
||||
The
|
||||
.B wine
|
||||
program loader for CUI (console) applications.
|
||||
.TP
|
||||
.I @prefix@/bin/dosmod
|
||||
The DOS program loader.
|
||||
.TP
|
||||
|
|
63
files/file.c
63
files/file.c
|
@ -182,7 +182,7 @@ void FILE_SetDosError(void)
|
|||
* Duplicate a Unix handle into a task handle.
|
||||
* Returns 0 on failure.
|
||||
*/
|
||||
HANDLE FILE_DupUnixHandle( int fd, DWORD access )
|
||||
HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
|
||||
{
|
||||
HANDLE ret;
|
||||
|
||||
|
@ -191,6 +191,7 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access )
|
|||
SERVER_START_REQ( alloc_file_handle )
|
||||
{
|
||||
req->access = access;
|
||||
req->inherit = inherit;
|
||||
req->fd = fd;
|
||||
SERVER_CALL();
|
||||
ret = req->handle;
|
||||
|
@ -255,14 +256,15 @@ int FILE_GetUnixHandle( HANDLE handle, DWORD access )
|
|||
* Open a handle to the current process console.
|
||||
* 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;
|
||||
|
||||
SERVER_START_REQ( open_console )
|
||||
{
|
||||
req->output = output;
|
||||
req->from = output;
|
||||
req->access = access;
|
||||
req->share = sharing;
|
||||
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
||||
SetLastError(0);
|
||||
SERVER_CALL_ERR();
|
||||
|
@ -477,12 +479,12 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
|
|||
/* Open a console for CONIN$ or CONOUT$ */
|
||||
if (!strcasecmp(filename, "CONIN$"))
|
||||
{
|
||||
ret = FILE_OpenConsole( FALSE, access, sa );
|
||||
ret = FILE_OpenConsole( FALSE, access, sharing, sa );
|
||||
goto done;
|
||||
}
|
||||
if (!strcasecmp(filename, "CONOUT$"))
|
||||
{
|
||||
ret = FILE_OpenConsole( TRUE, access, sa );
|
||||
ret = FILE_OpenConsole( TRUE, access, sharing, sa );
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -1452,15 +1454,14 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
if (!bytesToRead) return TRUE;
|
||||
|
||||
unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type );
|
||||
if (unix_handle == -1)
|
||||
return FALSE;
|
||||
|
||||
switch(type)
|
||||
switch (type)
|
||||
{
|
||||
case FD_TYPE_OVERLAPPED:
|
||||
if(!overlapped)
|
||||
if (unix_handle == -1) return FALSE;
|
||||
if (!overlapped)
|
||||
{
|
||||
close(unix_handle);
|
||||
close(unix_handle);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1493,23 +1494,28 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
SetLastError(ERROR_IO_PENDING);
|
||||
return FALSE;
|
||||
|
||||
case FD_TYPE_CONSOLE:
|
||||
return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
|
||||
default:
|
||||
if(overlapped)
|
||||
{
|
||||
close(unix_handle);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
/* normal unix files */
|
||||
if (unix_handle == -1)
|
||||
return FALSE;
|
||||
if (overlapped)
|
||||
{
|
||||
close(unix_handle);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* code for synchronous reads */
|
||||
while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
|
||||
{
|
||||
if ((errno == EAGAIN) || (errno == EINTR)) continue;
|
||||
if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
|
||||
FILE_SetDosError();
|
||||
break;
|
||||
if ((errno == EAGAIN) || (errno == EINTR)) continue;
|
||||
if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
|
||||
FILE_SetDosError();
|
||||
break;
|
||||
}
|
||||
close( unix_handle );
|
||||
if (result == -1) return FALSE;
|
||||
|
@ -1648,6 +1654,7 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
LPDWORD bytesWritten, LPOVERLAPPED overlapped )
|
||||
{
|
||||
int unix_handle, result;
|
||||
DWORD type;
|
||||
|
||||
TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
|
||||
bytesWritten, overlapped );
|
||||
|
@ -1659,8 +1666,18 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
if ( overlapped )
|
||||
return WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL);
|
||||
|
||||
unix_handle = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
|
||||
if (unix_handle == -1) return FALSE;
|
||||
unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type );
|
||||
|
||||
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 */
|
||||
while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
|
||||
|
|
|
@ -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_strncasecmp( const char *str1, const char *str2, int len );
|
||||
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 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info );
|
||||
extern HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 );
|
||||
|
|
|
@ -17,6 +17,8 @@ extern "C" {
|
|||
#define ENABLE_ECHO_INPUT 0x04
|
||||
#define ENABLE_WINDOW_INPUT 0x08
|
||||
#define ENABLE_MOUSE_INPUT 0x10
|
||||
/* Wine only code (extension) */
|
||||
#define WINE_ENABLE_LINE_INPUT_EMACS 0x80
|
||||
|
||||
#define ENABLE_PROCESSED_OUTPUT 0x01
|
||||
#define ENABLE_WRAP_AT_EOL_OUTPUT 0x02
|
||||
|
|
|
@ -577,6 +577,7 @@ struct alloc_file_handle_request
|
|||
{
|
||||
struct request_header __header;
|
||||
unsigned int access;
|
||||
int inherit;
|
||||
int fd;
|
||||
handle_t handle;
|
||||
};
|
||||
|
@ -755,8 +756,9 @@ struct alloc_console_request
|
|||
struct request_header __header;
|
||||
unsigned int access;
|
||||
int inherit;
|
||||
void* pid;
|
||||
handle_t handle_in;
|
||||
handle_t handle_out;
|
||||
handle_t event;
|
||||
};
|
||||
|
||||
|
||||
|
@ -767,25 +769,69 @@ struct free_console_request
|
|||
};
|
||||
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
struct open_console_request
|
||||
|
||||
struct get_console_renderer_events_request
|
||||
{
|
||||
struct request_header __header;
|
||||
int output;
|
||||
unsigned int access;
|
||||
int inherit;
|
||||
handle_t handle;
|
||||
/* VARARG(data,bytes); */
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct set_console_fd_request
|
||||
struct open_console_request
|
||||
{
|
||||
struct request_header __header;
|
||||
int from;
|
||||
|
||||
unsigned int access;
|
||||
int inherit;
|
||||
int share;
|
||||
handle_t handle;
|
||||
int fd_in;
|
||||
int fd_out;
|
||||
int pid;
|
||||
};
|
||||
|
||||
|
||||
|
@ -808,31 +854,114 @@ struct set_console_mode_request
|
|||
|
||||
|
||||
|
||||
struct set_console_info_request
|
||||
struct set_console_input_info_request
|
||||
{
|
||||
struct request_header __header;
|
||||
handle_t handle;
|
||||
int mask;
|
||||
int cursor_size;
|
||||
int cursor_visible;
|
||||
/* VARARG(title,string); */
|
||||
handle_t active_sb;
|
||||
int history_mode;
|
||||
int history_size;
|
||||
/* VARARG(title,unicode_str); */
|
||||
};
|
||||
#define SET_CONSOLE_INFO_CURSOR 0x01
|
||||
#define SET_CONSOLE_INFO_TITLE 0x02
|
||||
#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_info_request
|
||||
|
||||
struct get_console_input_info_request
|
||||
{
|
||||
struct request_header __header;
|
||||
handle_t handle;
|
||||
int cursor_size;
|
||||
int cursor_visible;
|
||||
int pid;
|
||||
/* VARARG(title,string); */
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct set_console_output_info_request
|
||||
{
|
||||
struct request_header __header;
|
||||
handle_t handle;
|
||||
int mask;
|
||||
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;
|
||||
};
|
||||
#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 request_header __header;
|
||||
|
@ -842,6 +971,7 @@ struct write_console_input_request
|
|||
};
|
||||
|
||||
|
||||
|
||||
struct read_console_input_request
|
||||
{
|
||||
struct request_header __header;
|
||||
|
@ -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 request_header __header;
|
||||
|
@ -1843,14 +2020,22 @@ enum request
|
|||
REQ_enable_socket_event,
|
||||
REQ_alloc_console,
|
||||
REQ_free_console,
|
||||
REQ_get_console_renderer_events,
|
||||
REQ_open_console,
|
||||
REQ_set_console_fd,
|
||||
REQ_get_console_mode,
|
||||
REQ_set_console_mode,
|
||||
REQ_set_console_info,
|
||||
REQ_get_console_info,
|
||||
REQ_set_console_input_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_read_console_input,
|
||||
REQ_write_console_output,
|
||||
REQ_read_console_output,
|
||||
REQ_move_console_output,
|
||||
REQ_create_change_notification,
|
||||
REQ_create_mapping,
|
||||
REQ_open_mapping,
|
||||
|
@ -1990,14 +2175,22 @@ union generic_request
|
|||
struct enable_socket_event_request enable_socket_event;
|
||||
struct alloc_console_request alloc_console;
|
||||
struct free_console_request free_console;
|
||||
struct get_console_renderer_events_request get_console_renderer_events;
|
||||
struct open_console_request open_console;
|
||||
struct set_console_fd_request set_console_fd;
|
||||
struct get_console_mode_request get_console_mode;
|
||||
struct set_console_mode_request set_console_mode;
|
||||
struct set_console_info_request set_console_info;
|
||||
struct get_console_info_request get_console_info;
|
||||
struct set_console_input_info_request set_console_input_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 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_mapping_request create_mapping;
|
||||
struct open_mapping_request open_mapping;
|
||||
|
@ -2080,6 +2273,6 @@ union generic_request
|
|||
struct get_window_properties_request get_window_properties;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 64
|
||||
#define SERVER_PROTOCOL_VERSION 65
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -1052,10 +1052,6 @@ BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
|
|||
|
||||
/* 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)
|
||||
FIXME("(%s,...): NORMAL_PRIORITY_CLASS ignored\n", name);
|
||||
if (dwCreationFlags & IDLE_PRIORITY_CLASS)
|
||||
|
|
|
@ -17,6 +17,7 @@ SUBDIRS = \
|
|||
uninstaller \
|
||||
view \
|
||||
wcmd \
|
||||
wineconsole \
|
||||
winemine \
|
||||
winetest \
|
||||
winhelp \
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Makefile
|
||||
wineconsole.spec.c
|
||||
wineconsole_res.res
|
|
@ -0,0 +1,19 @@
|
|||
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:
|
|
@ -0,0 +1,515 @@
|
|||
/* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,957 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#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);
|
|
@ -0,0 +1,479 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
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
|
|
@ -0,0 +1,70 @@
|
|||
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
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
|
||||
BEGIN
|
||||
IDS_EDIT, "&Editer"
|
||||
IDS_DEFAULT, "Par &défaut"
|
||||
IDS_PROPERTY, "&Propriétés"
|
||||
IDS_MARK, "&Marquer"
|
||||
IDS_COPY, "&Copier"
|
||||
IDS_PASTE, "C&oller"
|
||||
IDS_SELECTALL, "&Sélectionner tout"
|
||||
IDS_SCROLL, "&Défiler"
|
||||
IDS_SEARCH, "C&hercher"
|
||||
IDS_FNT_DISPLAY, "Chaque caractère 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 mémoire 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 mémoire 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 fenêtre", -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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/* 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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#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 @@
|
|||
#include "file.h"
|
||||
#include "thread.h"
|
||||
#include "winerror.h"
|
||||
#include "wincon.h"
|
||||
#include "wine/server.h"
|
||||
#include "options.h"
|
||||
#include "callback.h"
|
||||
|
@ -216,29 +217,6 @@ void PROCESS_CallUserSignalProc( UINT uCode, HMODULE16 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
|
||||
*
|
||||
|
@ -287,15 +265,28 @@ static BOOL process_init( char *argv[] )
|
|||
SERVER_END_VAR_REQ;
|
||||
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 */
|
||||
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 */
|
||||
PTHREAD_init_done();
|
||||
|
||||
|
@ -305,7 +296,11 @@ static BOOL process_init( char *argv[] )
|
|||
/* Parse command line arguments */
|
||||
OPTIONS_ParseOptions( argv );
|
||||
|
||||
return MAIN_MainInit();
|
||||
ret = MAIN_MainInit();
|
||||
|
||||
if (create_flags & CREATE_NEW_CONSOLE)
|
||||
AllocConsole();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
1224
server/console.c
1224
server/console.c
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 @@
|
|||
#include "process.h"
|
||||
#include "thread.h"
|
||||
#include "request.h"
|
||||
#include "console.h"
|
||||
|
||||
enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED };
|
||||
|
||||
|
@ -411,6 +412,11 @@ static int debugger_attach( struct process *process, struct thread *debugger )
|
|||
for (thread = debugger; thread; thread = thread->process->debugger)
|
||||
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 );
|
||||
|
||||
/* we must have been able to attach all threads */
|
||||
|
|
|
@ -494,7 +494,7 @@ DECL_HANDLER(alloc_file_handle)
|
|||
if ((file = create_file_for_fd( fd, req->access, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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->access & access) != access)
|
||||
{
|
||||
fprintf( stderr, "handle %d access %08x denied (%08x)\n", handle, access, entry->access );
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
return NULL;
|
||||
}
|
||||
|
@ -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->access & access) != access)
|
||||
{
|
||||
fprintf( stderr, "handle %d access %08x denied (%08x)\n", handle, access, entry->access );
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -155,11 +155,6 @@ extern void file_set_error(void);
|
|||
|
||||
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 */
|
||||
|
||||
extern int set_process_debugger( struct process *process, struct thread *debugger );
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "process.h"
|
||||
#include "thread.h"
|
||||
#include "request.h"
|
||||
#include "console.h"
|
||||
|
||||
/* process structure */
|
||||
|
||||
|
@ -101,12 +102,18 @@ static int set_process_console( struct process *process, struct process *parent,
|
|||
{
|
||||
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))
|
||||
{
|
||||
if (parent->console_in) process->console_in = grab_object( parent->console_in );
|
||||
if (parent->console_out) process->console_out = grab_object( parent->console_out );
|
||||
/* FIXME: some better error checking should be done...
|
||||
* 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)
|
||||
{
|
||||
|
@ -129,13 +136,20 @@ static int set_process_console( struct process *process, struct process *parent,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* no parent, use handles to the console for stdio */
|
||||
req->hstdin = alloc_handle( process, process->console_in,
|
||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
||||
req->hstdout = alloc_handle( process, process->console_out,
|
||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
||||
req->hstderr = alloc_handle( process, process->console_out,
|
||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
||||
if (process->console)
|
||||
{
|
||||
req->hstdin = alloc_handle( process, process->console,
|
||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
||||
req->hstdout = alloc_handle( process, process->console->active,
|
||||
GENERIC_READ | GENERIC_WRITE, 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 */
|
||||
if (get_error() == STATUS_INVALID_HANDLE) clear_error();
|
||||
|
@ -152,6 +166,7 @@ struct thread *create_process( int fd )
|
|||
if (!(process = alloc_object( &process_ops, fd ))) return NULL;
|
||||
process->next = NULL;
|
||||
process->prev = NULL;
|
||||
process->parent = NULL;
|
||||
process->thread_list = NULL;
|
||||
process->debugger = NULL;
|
||||
process->handles = NULL;
|
||||
|
@ -161,8 +176,7 @@ struct thread *create_process( int fd )
|
|||
process->affinity = 1;
|
||||
process->suspend = 0;
|
||||
process->create_flags = 0;
|
||||
process->console_in = NULL;
|
||||
process->console_out = NULL;
|
||||
process->console = NULL;
|
||||
process->init_event = NULL;
|
||||
process->idle_event = NULL;
|
||||
process->queue = NULL;
|
||||
|
@ -173,6 +187,7 @@ struct thread *create_process( int fd )
|
|||
process->exe.file = NULL;
|
||||
process->exe.dbg_offset = 0;
|
||||
process->exe.dbg_size = 0;
|
||||
|
||||
gettimeofday( &process->start_time, NULL );
|
||||
if ((process->next = first_process) != NULL) process->next->prev = process;
|
||||
first_process = process;
|
||||
|
@ -222,10 +237,11 @@ static void init_process( int ppid, struct init_process_request *req )
|
|||
fatal_protocol_error( current, "init_process: called twice?\n" );
|
||||
return;
|
||||
}
|
||||
process->parent = (struct process *)grab_object( parent );
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (parent && info->inherit_all)
|
||||
|
@ -288,6 +304,8 @@ static void process_destroy( struct object *obj )
|
|||
|
||||
/* we can't have a thread remaining */
|
||||
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->prev) process->prev->next = process->next;
|
||||
else first_process = process->next;
|
||||
|
@ -304,9 +322,8 @@ static void process_dump( struct object *obj, int verbose )
|
|||
struct process *process = (struct process *)obj;
|
||||
assert( obj->ops == &process_ops );
|
||||
|
||||
fprintf( stderr, "Process next=%p prev=%p console=%p/%p handles=%p\n",
|
||||
process->next, process->prev, process->console_in, process->console_out,
|
||||
process->handles );
|
||||
fprintf( stderr, "Process next=%p prev=%p handles=%p\n",
|
||||
process->next, process->prev, process->handles );
|
||||
}
|
||||
|
||||
static int process_signaled( struct object *obj, struct thread *thread )
|
||||
|
@ -418,6 +435,25 @@ static void process_unload_dll( struct process *process, void *base )
|
|||
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) */
|
||||
static void process_killed( struct process *process )
|
||||
{
|
||||
|
@ -425,7 +461,13 @@ static void process_killed( struct process *process )
|
|||
gettimeofday( &process->end_time, NULL );
|
||||
if (process->handles) release_object( process->handles );
|
||||
process->handles = NULL;
|
||||
|
||||
/* close the console attached to this process, if any */
|
||||
free_console( process );
|
||||
|
||||
/* close the processes using process as renderer, if any */
|
||||
kill_console_processes( process, 0 );
|
||||
|
||||
while (process->exe.next)
|
||||
{
|
||||
struct process_dll *dll = process->exe.next;
|
||||
|
@ -508,6 +550,7 @@ void resume_process( struct process *process )
|
|||
void kill_process( struct process *process, struct thread *skip, int exit_code )
|
||||
{
|
||||
struct thread *thread = process->thread_list;
|
||||
|
||||
while (thread)
|
||||
{
|
||||
struct thread *next = thread->proc_next;
|
||||
|
@ -532,6 +575,7 @@ void kill_debugged_processes( struct thread *debugger, int exit_code )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* get all information about a process */
|
||||
static void get_process_info( struct process *process, struct get_process_info_request *req )
|
||||
{
|
||||
|
|
|
@ -30,6 +30,7 @@ struct process
|
|||
struct object obj; /* object header */
|
||||
struct process *next; /* system-wide process list */
|
||||
struct process *prev;
|
||||
struct process *parent; /* parent process */
|
||||
struct thread *thread_list; /* head of the thread list */
|
||||
struct thread *debugger; /* thread debugging this process */
|
||||
struct object *handles; /* handle entries */
|
||||
|
@ -41,8 +42,7 @@ struct process
|
|||
int affinity; /* process affinity mask */
|
||||
int suspend; /* global process suspend count */
|
||||
int create_flags; /* process creation flags */
|
||||
struct object *console_in; /* console input */
|
||||
struct object *console_out; /* console output */
|
||||
struct console_input*console; /* console input */
|
||||
struct event *init_event; /* event for init done */
|
||||
struct event *idle_event; /* event for input idle */
|
||||
struct msg_queue *queue; /* main message queue */
|
||||
|
@ -55,7 +55,6 @@ struct process
|
|||
struct process_snapshot
|
||||
{
|
||||
struct process *process; /* process ptr */
|
||||
struct process *parent; /* process parent */
|
||||
int count; /* process refcount */
|
||||
int threads; /* number of threads */
|
||||
int priority; /* priority class */
|
||||
|
|
|
@ -533,6 +533,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
|||
/* Allocate a file handle for a Unix fd */
|
||||
@REQ(alloc_file_handle)
|
||||
unsigned int access; /* wanted access rights */
|
||||
int inherit; /* inherit flag */
|
||||
int fd; /* file descriptor on the client side */
|
||||
@REPLY
|
||||
handle_t handle; /* handle to the file */
|
||||
|
@ -685,13 +686,14 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
|||
@END
|
||||
|
||||
|
||||
/* Allocate a console for the current process */
|
||||
/* Allocate a console (only used by a console renderer) */
|
||||
@REQ(alloc_console)
|
||||
unsigned int access; /* wanted access rights */
|
||||
int inherit; /* inherit flag */
|
||||
void* pid; /* pid of process which shall be attached to the console */
|
||||
@REPLY
|
||||
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
|
||||
|
||||
|
||||
|
@ -700,22 +702,67 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
|||
@END
|
||||
|
||||
|
||||
/* Open a handle to the process console */
|
||||
@REQ(open_console)
|
||||
int output; /* input or output? */
|
||||
unsigned int access; /* wanted access rights */
|
||||
int inherit; /* inherit flag */
|
||||
#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
|
||||
handle_t handle; /* handle to the console */
|
||||
VARARG(data,bytes); /* the various console_renderer_events */
|
||||
@END
|
||||
|
||||
|
||||
/* Set a console file descriptor */
|
||||
@REQ(set_console_fd)
|
||||
/* Open a handle to the process console */
|
||||
@REQ(open_console)
|
||||
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 */
|
||||
int inherit; /* inherit flag */
|
||||
int share; /* share mask (only for output handles) */
|
||||
@REPLY
|
||||
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
|
||||
|
||||
|
||||
|
@ -734,28 +781,104 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
|||
@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) */
|
||||
@REQ(set_console_info)
|
||||
@REQ(set_console_output_info)
|
||||
handle_t handle; /* handle to the console */
|
||||
int mask; /* setting mask (see below) */
|
||||
int cursor_size; /* size of cursor (percentage filled) */
|
||||
int cursor_visible;/* cursor visibility flag */
|
||||
VARARG(title,string); /* console title */
|
||||
short int cursor_size; /* size of cursor (percentage filled) */
|
||||
short int cursor_visible;/* cursor visibility flag */
|
||||
short int cursor_x; /* position of cursor (x, y) */
|
||||
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
|
||||
#define SET_CONSOLE_INFO_CURSOR 0x01
|
||||
#define SET_CONSOLE_INFO_TITLE 0x02
|
||||
#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) */
|
||||
@REQ(get_console_info)
|
||||
@REQ(get_console_output_info)
|
||||
handle_t handle; /* handle to the console */
|
||||
@REPLY
|
||||
int cursor_size; /* size of cursor (percentage filled) */
|
||||
int cursor_visible;/* cursor visibility flag */
|
||||
int pid; /* pid of xterm (hack) */
|
||||
VARARG(title,string); /* console title */
|
||||
short int cursor_size; /* size of cursor (percentage filled) */
|
||||
short int cursor_visible;/* cursor visibility flag */
|
||||
short int cursor_x; /* position of cursor (x, y) */
|
||||
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
|
||||
|
||||
|
||||
/* Add input records to a console input queue */
|
||||
@REQ(write_console_input)
|
||||
handle_t handle; /* handle to the console input */
|
||||
|
@ -764,6 +887,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
|||
int written; /* number of records written */
|
||||
@END
|
||||
|
||||
|
||||
/* Fetch input records from a console input queue */
|
||||
@REQ(read_console_input)
|
||||
handle_t handle; /* handle to the console input */
|
||||
|
@ -774,6 +898,49 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
|||
@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 */
|
||||
@REQ(create_change_notification)
|
||||
int subtree; /* watch all the subtree */
|
||||
|
|
|
@ -118,14 +118,22 @@ DECL_HANDLER(get_socket_event);
|
|||
DECL_HANDLER(enable_socket_event);
|
||||
DECL_HANDLER(alloc_console);
|
||||
DECL_HANDLER(free_console);
|
||||
DECL_HANDLER(get_console_renderer_events);
|
||||
DECL_HANDLER(open_console);
|
||||
DECL_HANDLER(set_console_fd);
|
||||
DECL_HANDLER(get_console_mode);
|
||||
DECL_HANDLER(set_console_mode);
|
||||
DECL_HANDLER(set_console_info);
|
||||
DECL_HANDLER(get_console_info);
|
||||
DECL_HANDLER(set_console_input_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(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_mapping);
|
||||
DECL_HANDLER(open_mapping);
|
||||
|
@ -264,14 +272,22 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_enable_socket_event,
|
||||
(req_handler)req_alloc_console,
|
||||
(req_handler)req_free_console,
|
||||
(req_handler)req_get_console_renderer_events,
|
||||
(req_handler)req_open_console,
|
||||
(req_handler)req_set_console_fd,
|
||||
(req_handler)req_get_console_mode,
|
||||
(req_handler)req_set_console_mode,
|
||||
(req_handler)req_set_console_info,
|
||||
(req_handler)req_get_console_info,
|
||||
(req_handler)req_set_console_input_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_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_mapping,
|
||||
(req_handler)req_open_mapping,
|
||||
|
|
203
server/trace.c
203
server/trace.c
|
@ -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 )
|
||||
{
|
||||
fprintf( stderr, " access=%08x,", req->access );
|
||||
fprintf( stderr, " inherit=%d,", req->inherit );
|
||||
fprintf( stderr, " fd=%d", req->fd );
|
||||
}
|
||||
|
||||
|
@ -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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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_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 )
|
||||
{
|
||||
fprintf( stderr, " output=%d,", req->output );
|
||||
fprintf( stderr, " from=%d,", req->from );
|
||||
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 )
|
||||
|
@ -906,14 +920,6 @@ static void dump_open_console_reply( const struct open_console_request *req )
|
|||
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 )
|
||||
{
|
||||
fprintf( stderr, " handle=%d", req->handle );
|
||||
|
@ -930,28 +936,102 @@ static void dump_set_console_mode_request( const struct set_console_mode_request
|
|||
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, " mask=%d,", req->mask );
|
||||
fprintf( stderr, " cursor_size=%d,", req->cursor_size );
|
||||
fprintf( stderr, " cursor_visible=%d,", req->cursor_visible );
|
||||
fprintf( stderr, " title=" );
|
||||
cur_pos += dump_varargs_string( req );
|
||||
fprintf( stderr, " cursor_x=%d,", req->cursor_x );
|
||||
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 );
|
||||
}
|
||||
|
||||
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_visible=%d,", req->cursor_visible );
|
||||
fprintf( stderr, " pid=%d,", req->pid );
|
||||
fprintf( stderr, " title=" );
|
||||
cur_pos += dump_varargs_string( req );
|
||||
fprintf( stderr, " cursor_x=%d,", req->cursor_x );
|
||||
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_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
|
|||
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 )
|
||||
{
|
||||
fprintf( stderr, " subtree=%d,", req->subtree );
|
||||
|
@ -1955,14 +2078,22 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_enable_socket_event_request,
|
||||
(dump_func)dump_alloc_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_set_console_fd_request,
|
||||
(dump_func)dump_get_console_mode_request,
|
||||
(dump_func)dump_set_console_mode_request,
|
||||
(dump_func)dump_set_console_info_request,
|
||||
(dump_func)dump_get_console_info_request,
|
||||
(dump_func)dump_set_console_input_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_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_mapping_request,
|
||||
(dump_func)dump_open_mapping_request,
|
||||
|
@ -2098,14 +2229,22 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)0,
|
||||
(dump_func)dump_alloc_console_reply,
|
||||
(dump_func)0,
|
||||
(dump_func)dump_get_console_renderer_events_reply,
|
||||
(dump_func)dump_open_console_reply,
|
||||
(dump_func)0,
|
||||
(dump_func)dump_get_console_mode_reply,
|
||||
(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_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_mapping_reply,
|
||||
(dump_func)dump_open_mapping_reply,
|
||||
|
@ -2241,14 +2380,22 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"enable_socket_event",
|
||||
"alloc_console",
|
||||
"free_console",
|
||||
"get_console_renderer_events",
|
||||
"open_console",
|
||||
"set_console_fd",
|
||||
"get_console_mode",
|
||||
"set_console_mode",
|
||||
"set_console_info",
|
||||
"get_console_info",
|
||||
"set_console_input_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",
|
||||
"read_console_input",
|
||||
"write_console_output",
|
||||
"read_console_output",
|
||||
"move_console_output",
|
||||
"create_change_notification",
|
||||
"create_mapping",
|
||||
"open_mapping",
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
%formats =
|
||||
(
|
||||
"int" => "%d",
|
||||
"short int" => "%d",
|
||||
"char" => "%c",
|
||||
"unsigned char" => "%02x",
|
||||
"unsigned short"=> "%04x",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DEFS = @DLLFLAGS@ -D__WINE__
|
||||
DEFS = @DLLFLAGS@ -D__WINE__ -DBINDIR="\"$(bindir)\""
|
||||
TOPSRCDIR = @top_srcdir@
|
||||
TOPOBJDIR = ..
|
||||
SRCDIR = @srcdir@
|
||||
|
@ -8,6 +8,7 @@ MODULE = win32
|
|||
C_SRCS = \
|
||||
console.c \
|
||||
device.c \
|
||||
editline.c \
|
||||
except.c \
|
||||
file.c \
|
||||
init.c \
|
||||
|
|
2984
win32/console.c
2984
win32/console.c
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,708 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue