qe_register_binding takes ModeDef* and returns status cosmetic changes in QEDisplay API added int dpy_init(QEditScreen *s, QEDisplay *dpy, int w, int h); copies *dpy (or dummy_dpy if NULL) to QEditScreen and calls method simplified dpy_init methods and calls inlined 5 more methods moved dummy_dpy to display.c and simplified simplified to_hex simplified qe_colors array handling
529 lines
13 KiB
C
529 lines
13 KiB
C
/*
|
|
* MS Windows driver for QEmacs
|
|
*
|
|
* Copyright (c) 2002 Fabrice Bellard.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "qe.h"
|
|
|
|
#include <windows.h>
|
|
|
|
extern int main1(int argc, char **argv);
|
|
LRESULT CALLBACK qe_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
static HINSTANCE _hPrev, _hInstance;
|
|
static int font_xsize;
|
|
|
|
/* state of a single window */
|
|
typedef struct WinWindow {
|
|
HWND w;
|
|
HDC hdc;
|
|
HFONT font;
|
|
} WinWindow;
|
|
|
|
typedef struct QEEventQ {
|
|
QEEvent ev;
|
|
struct QEEventQ *next;
|
|
} QEEventQ;
|
|
|
|
QEEventQ *first_event, *last_event;
|
|
WinWindow win_ctx;
|
|
|
|
#define PROG_NAME "qemacs"
|
|
|
|
/* the main is there. We simulate a unix command line by parsing the
|
|
windows command line */
|
|
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,
|
|
LPSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
char **argv;
|
|
int argc, count;
|
|
char *command_line, *p;
|
|
|
|
command_line = qe_malloc_array(char, sizeof(PROG_NAME) +
|
|
strlen(lpszCmdLine) + 1);
|
|
if (!command_line)
|
|
return 0;
|
|
strcpy(command_line, PROG_NAME " ");
|
|
strcat(command_line, lpszCmdLine);
|
|
_hPrev = hPrevInst;
|
|
_hInstance = hInstance;
|
|
|
|
/* simplistic command line parser */
|
|
p = command_line;
|
|
count = 0;
|
|
for (;;) {
|
|
skip_spaces((const char **)&p);
|
|
if (*p == '\0')
|
|
break;
|
|
while (*p != '\0' && !qe_isspace(*p))
|
|
p++;
|
|
count++;
|
|
}
|
|
|
|
argv = qe_malloc_array(char *, count + 1);
|
|
if (!argv)
|
|
return 0;
|
|
|
|
argc = 0;
|
|
p = command_line;
|
|
for (;;) {
|
|
skip_spaces((const char **)&p);
|
|
if (*p == '\0')
|
|
break;
|
|
argv[argc++] = p;
|
|
while (*p != '\0' && !qe_isspace(*p))
|
|
p++;
|
|
*p = '\0';
|
|
p++;
|
|
}
|
|
|
|
argv[argc] = NULL;
|
|
|
|
#if 0
|
|
{
|
|
int i;
|
|
for (i = 0; i < argc; i++) {
|
|
printf("%d: '%s'\n", i, argv[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return main1(argc, argv);
|
|
}
|
|
|
|
static int win_probe(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static void init_application(void)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = qe_wnd_proc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = _hInstance;
|
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = "qemacs";
|
|
|
|
RegisterClass(&wc);
|
|
}
|
|
|
|
static int win_init(QEditScreen *s, int w, int h)
|
|
{
|
|
int xsize, ysize, font_ysize;
|
|
TEXTMETRIC tm;
|
|
HDC hdc;
|
|
HWND desktop_hwnd;
|
|
|
|
if (!_hPrev)
|
|
init_application();
|
|
|
|
s->private = NULL;
|
|
s->media = CSS_MEDIA_SCREEN;
|
|
|
|
win_ctx.font = CreateFont(-12, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0,
|
|
FIXED_PITCH, "fixed");
|
|
|
|
/* get font metric for window size */
|
|
desktop_hwnd = GetDesktopWindow();
|
|
hdc = GetDC(desktop_hwnd);
|
|
SelectObject(hdc, win_ctx.font);
|
|
GetTextMetrics(hdc, &tm);
|
|
ReleaseDC(desktop_hwnd, hdc);
|
|
|
|
font_xsize = tm.tmAveCharWidth;
|
|
font_ysize = tm.tmHeight;
|
|
|
|
xsize = 80 * font_xsize;
|
|
ysize = 25 * font_ysize;
|
|
|
|
s->width = xsize;
|
|
s->height = ysize;
|
|
s->charset = &charset_utf8;
|
|
|
|
s->clip_x1 = 0;
|
|
s->clip_y1 = 0;
|
|
s->clip_x2 = s->width;
|
|
s->clip_y2 = s->height;
|
|
|
|
win_ctx.w = CreateWindow("qemacs", "qemacs", WS_OVERLAPPEDWINDOW,
|
|
0, 0, xsize, ysize, NULL, NULL, _hInstance, NULL);
|
|
|
|
win_ctx.hdc = GetDC(win_ctx.w);
|
|
SelectObject(win_ctx.hdc, win_ctx.font);
|
|
|
|
// SetWindowPos (win_ctx.w, NULL, 0, 0, xsize, ysize, SWP_NOMOVE);
|
|
|
|
ShowWindow(win_ctx.w, SW_SHOW);
|
|
UpdateWindow(win_ctx.w);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void win_close(QEditScreen *s)
|
|
{
|
|
ReleaseDC(win_ctx.w, win_ctx.hdc);
|
|
DestroyWindow(win_ctx.w);
|
|
DeleteObject(win_ctx.font);
|
|
}
|
|
|
|
static void win_flush(QEditScreen *s)
|
|
{
|
|
}
|
|
|
|
static int win_is_user_input_pending(QEditScreen *s)
|
|
{
|
|
/* XXX: do it */
|
|
return 0;
|
|
}
|
|
|
|
static void push_event(QEEvent *ev)
|
|
{
|
|
QEEventQ *e;
|
|
|
|
e = qe_malloc(QEEventQ);
|
|
if (!e)
|
|
return;
|
|
e->ev = *ev;
|
|
e->next = NULL;
|
|
if (!last_event)
|
|
first_event = e;
|
|
else
|
|
last_event->next = e;
|
|
last_event = e;
|
|
}
|
|
|
|
static void push_key(int key)
|
|
{
|
|
QEEvent ev;
|
|
ev.type = QE_KEY_EVENT;
|
|
ev.key_event.key = key;
|
|
push_event(&ev);
|
|
}
|
|
|
|
static int ignore_wchar_msg = 0;
|
|
|
|
LRESULT CALLBACK qe_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// printf("msg=%d\n", msg);
|
|
switch (msg) {
|
|
case WM_CREATE:
|
|
/* NOTE: must store them here to avoid problems in main */
|
|
win_ctx.w = hWnd;
|
|
return 0;
|
|
|
|
/* key handling */
|
|
case WM_CHAR:
|
|
if (!ignore_wchar_msg) {
|
|
push_key(wParam);
|
|
} else {
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
}
|
|
break;
|
|
case WM_SYSCHAR:
|
|
if (!ignore_wchar_msg) {
|
|
int key;
|
|
key = wParam;
|
|
if (key >= ' ' && key <= '~') {
|
|
key = KEY_META(' ') + key - ' ';
|
|
push_key(key);
|
|
break;
|
|
}
|
|
}
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
case WM_SYSKEYDOWN:
|
|
case WM_KEYDOWN:
|
|
{
|
|
unsigned int scan;
|
|
int ctrl, shift, alt, key;
|
|
|
|
ctrl = (GetKeyState(VK_CONTROL) & 0x8000);
|
|
shift = (GetKeyState(VK_SHIFT) & 0x8000);
|
|
alt = (GetKeyState(VK_MENU) & 0x8000);
|
|
|
|
ignore_wchar_msg = 0;
|
|
|
|
scan = (unsigned int)((lParam >> 16) & 0x1FF);
|
|
switch (scan) {
|
|
case 0x00E:
|
|
ignore_wchar_msg = 1;
|
|
push_key(KEY_DEL);
|
|
break;
|
|
case 0x039: /* space */
|
|
ignore_wchar_msg = 1;
|
|
if (!ctrl)
|
|
push_key(KEY_SPC);
|
|
else
|
|
push_key(KEY_CTRL('@'));
|
|
break;
|
|
case 0x147: /* HOME */
|
|
push_key(KEY_HOME);
|
|
break;
|
|
case 0x148: /* UP */
|
|
push_key(KEY_UP);
|
|
break;
|
|
case 0x149: /* PGUP */
|
|
push_key(KEY_PAGEUP);
|
|
break;
|
|
case 0x14B: /* LEFT */
|
|
push_key(KEY_LEFT);
|
|
break;
|
|
case 0x14D: /* RIGHT */
|
|
push_key(KEY_RIGHT);
|
|
break;
|
|
case 0x14F: /* END */
|
|
push_key(KEY_END);
|
|
break;
|
|
case 0x150: /* DOWN */
|
|
push_key(KEY_DOWN);
|
|
break;
|
|
case 0x151: /* PGDN */
|
|
push_key(KEY_PAGEDOWN);
|
|
break;
|
|
case 0x153: /* DEL */
|
|
push_key(KEY_DELETE);
|
|
break;
|
|
case 0x152: /* INSERT */
|
|
push_key(KEY_INSERT);
|
|
break;
|
|
case 0x3b: /* F1 */
|
|
push_key(KEY_F1);
|
|
break;
|
|
case 0x3c: /* F2 */
|
|
push_key(KEY_F2);
|
|
break;
|
|
case 0x3d: /* F3 */
|
|
push_key(KEY_F3);
|
|
break;
|
|
case 0x3e: /* F4 */
|
|
/* we leave Alt-F4 to close the window */
|
|
if (alt)
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
push_key(KEY_F4);
|
|
break;
|
|
case 0x3f: /* F5 */
|
|
push_key(KEY_F5);
|
|
break;
|
|
case 0x40: /* F6 */
|
|
push_key(KEY_F6);
|
|
break;
|
|
case 0x41: /* F7 */
|
|
push_key(KEY_F7);
|
|
break;
|
|
case 0x42: /* F8 */
|
|
push_key(KEY_F8);
|
|
break;
|
|
case 0x43: /* F9 */
|
|
push_key(KEY_F9);
|
|
break;
|
|
case 0x44: /* F10 */
|
|
push_key(KEY_F10);
|
|
break;
|
|
case 0x57: /* F11 */
|
|
push_key(KEY_F11);
|
|
break;
|
|
case 0x58: /* F12 */
|
|
push_key(KEY_F12);
|
|
break;
|
|
default:
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_KEYUP:
|
|
ignore_wchar_msg = 0;
|
|
break;
|
|
|
|
case WM_SYSKEYUP:
|
|
ignore_wchar_msg = 0;
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
|
|
case WM_SIZE:
|
|
if (wParam != SIZE_MINIMIZED) {
|
|
QEmacsState *qs = &qe_state;
|
|
QEEvent ev;
|
|
|
|
qs->screen->width = LOWORD(lParam);
|
|
qs->screen->height = HIWORD(lParam);
|
|
ev.expose_event.type = QE_EXPOSE_EVENT;
|
|
push_event(&ev);
|
|
}
|
|
break;
|
|
case WM_PAINT:
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC saved_hdc;
|
|
BeginPaint(win_ctx.w, &ps);
|
|
saved_hdc = win_ctx.hdc;
|
|
win_ctx.hdc = ps.hdc;
|
|
SelectObject(win_ctx.hdc, win_ctx.font);
|
|
do_refresh(NULL);
|
|
|
|
EndPaint(win_ctx.w, &ps);
|
|
win_ctx.hdc = saved_hdc;
|
|
}
|
|
break;
|
|
|
|
case WM_SETFOCUS:
|
|
case WM_KILLFOCUS:
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int get_unicode_key(QEditScreen *s, QEPollData *pd, QEEvent *ev)
|
|
{
|
|
MSG msg;
|
|
QEEventQ *e;
|
|
|
|
for (;;) {
|
|
/* check if events queued */
|
|
if (first_event != NULL) {
|
|
e = first_event;
|
|
*ev = e->ev;
|
|
first_event = e->next;
|
|
if (!first_event)
|
|
last_event = NULL;
|
|
qe_free(&e);
|
|
break;
|
|
}
|
|
|
|
/* check if message queued */
|
|
if (GetMessage(&msg, NULL, 0, 0)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void win_fill_rectangle(QEditScreen *s,
|
|
int x1, int y1, int w, int h, QEColor color)
|
|
{
|
|
RECT rc;
|
|
HBRUSH hbr;
|
|
COLORREF col;
|
|
|
|
/* XXX: suppress XOR mode */
|
|
if (color == QECOLOR_XOR)
|
|
color = QERGB(0xff, 0xff, 0xff);
|
|
|
|
SetRect(&rc, x1, y1, x1 + w, y1 + h);
|
|
col = RGB((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
|
|
hbr = CreateSolidBrush(col);
|
|
FillRect(win_ctx.hdc, &rc, hbr);
|
|
DeleteObject(hbr);
|
|
}
|
|
|
|
static QEFont *win_open_font(QEditScreen *s, int style, int size)
|
|
{
|
|
QEFont *font;
|
|
TEXTMETRIC tm;
|
|
|
|
font = qe_malloc(QEFont);
|
|
if (!font)
|
|
return NULL;
|
|
GetTextMetrics(win_ctx.hdc, &tm);
|
|
font->ascent = tm.tmAscent;
|
|
font->descent = tm.tmDescent;
|
|
font->private = NULL;
|
|
return font;
|
|
}
|
|
|
|
static void win_close_font(QEditScreen *s, QEFont *font)
|
|
{
|
|
qe_free(&font);
|
|
}
|
|
|
|
static void win_text_metrics(QEditScreen *s, QEFont *font,
|
|
QECharMetrics *metrics,
|
|
const unsigned int *str, int len)
|
|
{
|
|
int i, x;
|
|
metrics->font_ascent = font->ascent;
|
|
metrics->font_descent = font->descent;
|
|
x = 0;
|
|
for (i = 0; i < len; i++)
|
|
x += font_xsize;
|
|
metrics->width = x;
|
|
}
|
|
|
|
static void win_draw_text(QEditScreen *s, QEFont *font,
|
|
int x1, int y, const unsigned int *str, int len,
|
|
QEColor color)
|
|
{
|
|
int i;
|
|
WORD buf[len];
|
|
COLORREF col;
|
|
|
|
for (i = 0; i < len; i++)
|
|
buf[i] = str[i];
|
|
col = RGB((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
|
|
SetTextColor(win_ctx.hdc, col);
|
|
SetBkMode(win_ctx.hdc, TRANSPARENT);
|
|
TextOutW(win_ctx.hdc, x1, y - font->ascent, buf, len);
|
|
}
|
|
|
|
static void win_set_clip(QEditScreen *s,
|
|
int x, int y, int w, int h)
|
|
{
|
|
/* nothing to do */
|
|
}
|
|
|
|
static QEDisplay win32_dpy = {
|
|
"win32",
|
|
win_probe,
|
|
win_init,
|
|
win_close,
|
|
win_flush,
|
|
win_is_user_input_pending,
|
|
win_fill_rectangle,
|
|
win_open_font,
|
|
win_close_font,
|
|
win_text_metrics,
|
|
win_draw_text,
|
|
win_set_clip,
|
|
NULL, /* dpy_selection_activate */
|
|
NULL, /* dpy_selection_request */
|
|
NULL, /* dpy_invalidate */
|
|
NULL, /* dpy_cursor_at */
|
|
NULL, /* dpy_bmp_alloc */
|
|
NULL, /* dpy_bmp_free */
|
|
NULL, /* dpy_bmp_draw */
|
|
NULL, /* dpy_bmp_lock */
|
|
NULL, /* dpy_bmp_unlock */
|
|
NULL, /* dpy_full_screen */
|
|
NULL, /* next */
|
|
};
|
|
|
|
int win32_init(void)
|
|
{
|
|
return qe_register_display(&win32_dpy);
|
|
}
|
|
|
|
qe_module_init(win32_init);
|