The R Project SVN R

Rev

Rev 24283 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 24283 Rev 24322
1
/*
1
/*
2
 * GraphApp - Cross-Platform Graphics Programming Library.
2
 * GraphApp - Cross-Platform Graphics Programming Library.
3
 *
3
 *
4
 * File: events.c -- winprocs and timers are contained here.
4
 * File: events.c -- winprocs and timers are contained here.
5
 * Platform: Windows  Version: 2.35  Date: 1998/04/04
5
 * Platform: Windows  Version: 2.35  Date: 1998/04/04
6
 *
6
 *
7
 * Version: 1.00  Changes: Original version by Lachlan Patrick.
7
 * Version: 1.00  Changes: Original version by Lachlan Patrick.
8
 * Version: 2.00  Changes: New class system implemented.
8
 * Version: 2.00  Changes: New class system implemented.
9
 * Version: 2.20  Changes: Non-native buttons supported.
9
 * Version: 2.20  Changes: Non-native buttons supported.
10
 * Version: 2.22  Changes: 32-bit fix by Wim Rijnders.
10
 * Version: 2.22  Changes: 32-bit fix by Wim Rijnders.
11
 * Version: 2.35  Changes: New delayed deletion technique.
11
 * Version: 2.35  Changes: New delayed deletion technique.
12
 */
12
 */
13
 
13
 
14
/* Copyright (C) 1993-1998 Lachlan Patrick
14
/* Copyright (C) 1993-1998 Lachlan Patrick
15
 
15
 
16
   This file is part of GraphApp, a cross-platform C graphics library.
16
   This file is part of GraphApp, a cross-platform C graphics library.
17
 
17
 
18
   GraphApp is free software; you can redistribute it and/or modify it
18
   GraphApp is free software; you can redistribute it and/or modify it
19
   under the terms of the GNU Library General Public License.
19
   under the terms of the GNU Library General Public License.
20
   GraphApp is distributed in the hope that it will be useful, but
20
   GraphApp is distributed in the hope that it will be useful, but
21
   WITHOUT ANY WARRANTY.
21
   WITHOUT ANY WARRANTY.
22
 
22
 
23
   See the file COPYLIB.TXT for details.
23
   See the file COPYLIB.TXT for details.
24
*/
24
*/
25
 
25
 
26
#include "internal.h"
26
#include "internal.h"
27
 
27
 
28
/*
28
/*
29
 *  Library variables.
29
 *  Library variables.
30
 */
30
 */
31
	static timerfn do_timer = NULL;
31
	static timerfn do_timer = NULL;
32
	static void *timer_data = NULL;
32
	static void *timer_data = NULL;
33
 
33
 
34
	static MSG    msg;
34
	static MSG    msg;
35
	PROTECTED int keystate = 0; /* state of shift, ctrl and alt keys */
35
	PROTECTED int keystate = 0; /* state of shift, ctrl and alt keys */
36
 
36
 
37
/* a user-timer and a mouse-down timer function can be started */
37
/* a user-timer and a mouse-down timer function can be started */
38
 
38
 
39
	static	UINT	timer_id	= 0;
39
	static	UINT	timer_id	= 0;
40
	static	UINT	mouse_timer_id	= 0;
40
	static	UINT	mouse_timer_id	= 0;
41
 
41
 
42
/* buttons and xy are used to record the state of the mouse */
42
/* buttons and xy are used to record the state of the mouse */
43
 
43
 
44
	static	int 	buttons = 0;
44
	static	int 	buttons = 0;
45
	static	point	xy;
45
	static	point	xy;
46
 
46
 
47
	static	long	mouse_msec = 0;
47
	static	long	mouse_msec = 0;
48
 
48
 
49
	TIMERPROC app_timer_proc;
49
	TIMERPROC app_timer_proc;
50
	WNDPROC   app_control_proc;
50
	WNDPROC   app_control_proc;
51
 
51
 
52
	static object frontwindow = NULL; /* the window receiving events */
52
	static object frontwindow = NULL; /* the window receiving events */
53
 
53
 
54
/*
54
/*
55
 *  Call the relevent mouse handler function.
55
 *  Call the relevent mouse handler function.
56
 */
56
 */
57
static void handle_mouse(object obj, HWND hwnd, UINT message,
57
static void handle_mouse(object obj, HWND hwnd, UINT message,
58
			int param, int x, int y)
58
			int param, int x, int y)
59
{
59
{
60
        menu m;
60
        menu m;
61
        POINT wp;
61
        POINT wp;
62
        HWND hw;
62
        HWND hw;
63
	int dble = 1;
63
	int dble = 1;
64
 
64
 
65
	xy.x = x;
65
	xy.x = x;
66
	xy.y = y;
66
	xy.y = y;
67
	buttons = 0;
67
	buttons = 0;
68
        if (!obj) return;
68
        if (!obj) return;
69
	if (param & MK_LBUTTON)
69
	if (param & MK_LBUTTON)
70
		buttons |= LeftButton;
70
		buttons |= LeftButton;
71
	if (param & MK_MBUTTON)
71
	if (param & MK_MBUTTON)
72
		buttons |= MiddleButton;
72
		buttons |= MiddleButton;
73
	if (param & MK_RBUTTON)
73
	if (param & MK_RBUTTON)
74
		buttons |= RightButton;
74
		buttons |= RightButton;
75
 
75
 
76
	/* dispatch the mouse event to the relevent handler */
76
	/* dispatch the mouse event to the relevent handler */
77
	if (obj && obj->drawstate && obj->drawstate->crsr)
77
	if (obj && obj->drawstate && obj->drawstate->crsr)
78
                 SetCursor((HCURSOR)obj->drawstate->crsr->handle);
78
                 SetCursor((HCURSOR)obj->drawstate->crsr->handle);
79
 
79
 
80
	switch (message)
80
	switch (message)
81
	{
81
	{
82
	case WM_MOUSEMOVE:
82
	case WM_MOUSEMOVE:
83
                if (obj->call) {
83
                if (obj->call) {
84
		  if (buttons) {
84
		  if (buttons) {
85
			if (obj->call->mousedrag)
85
			if (obj->call->mousedrag)
86
				obj->call->mousedrag(obj, buttons, xy);
86
				obj->call->mousedrag(obj, buttons, xy);
87
		  }
87
		  }
88
		  else if (obj->call->mousemove)
88
		  else if (obj->call->mousemove)
89
			obj->call->mousemove(obj, buttons, xy);
89
			obj->call->mousemove(obj, buttons, xy);
90
                }
90
                }
91
		break;
91
		break;
92
	case WM_LBUTTONDOWN:
92
	case WM_LBUTTONDOWN:
93
	case WM_RBUTTONDOWN:
93
	case WM_RBUTTONDOWN:
94
	case WM_MBUTTONDOWN:
94
	case WM_MBUTTONDOWN:
95
	        dble = 0;
95
	        dble = 0;
96
		setmousetimer(mouse_msec); /* restart timer */
96
		setmousetimer(mouse_msec); /* restart timer */
97
		/* fall through to next case */
97
		/* fall through to next case */
98
	case WM_LBUTTONDBLCLK:
98
	case WM_LBUTTONDBLCLK:
99
	case WM_RBUTTONDBLCLK:
99
	case WM_RBUTTONDBLCLK:
100
	case WM_MBUTTONDBLCLK:
100
	case WM_MBUTTONDBLCLK:
101
	        if (dble) buttons |= DblClick;
101
	        if (dble) buttons |= DblClick;
102
		if ((obj->flags & ChildWindow) &&  (obj->kind != LabelObject))
102
		if ((obj->flags & ChildWindow) &&  (obj->kind != LabelObject))
103
			SetFocus(hwnd);
103
			SetFocus(hwnd);
104
		if (obj->flags & TrackMouse)
104
		if (obj->flags & TrackMouse)
105
			SetCapture(hwnd);
105
			SetCapture(hwnd);
106
                if (buttons == RightButton) {
106
                if (buttons == RightButton) {
107
                    m = obj->popup; hw = hwnd;
107
                    m = obj->popup; hw = hwnd;
108
                    if (!m) {
108
                    if (!m) {
109
                        m = obj->parent->popup;
109
                        m = obj->parent->popup;
110
                        hw = (HWND) obj->parent->handle;
110
                        hw = (HWND) obj->parent->handle;
111
                    }
111
                    }
112
                    if (m) {
112
                    if (m) {
113
                      wp.x = x; wp.y = y;
113
                      wp.x = x; wp.y = y;
114
                      ClientToScreen(hw, (LPPOINT) &wp);
114
                      ClientToScreen(hw, (LPPOINT) &wp);
115
                      if (m->action) m->action(m);
115
                      if (m->action) m->action(m);
116
                      TrackPopupMenu(m->handle,
116
                      TrackPopupMenu(m->handle,
117
                         TPM_LEFTALIGN|
117
                         TPM_LEFTALIGN|
118
                         TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
118
                         TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
119
                         wp.x,wp.y,
119
                         wp.x,wp.y,
120
                         0,
120
                         0,
121
                         obj->handle,
121
                         obj->handle,
122
                         NULL);
122
                         NULL);
123
                         break;
123
                         break;
124
                    }
124
                    }
125
                }
125
                }
126
		if (obj->call && obj->call->mousedown)
126
		if (obj->call && obj->call->mousedown)
127
			obj->call->mousedown(obj, buttons, xy);
127
			obj->call->mousedown(obj, buttons, xy);
128
		break;
128
		break;
129
	case WM_LBUTTONUP:
129
	case WM_LBUTTONUP:
130
	case WM_RBUTTONUP:
130
	case WM_RBUTTONUP:
131
	case WM_MBUTTONUP:
131
	case WM_MBUTTONUP:
132
		if ((obj->flags & TrackMouse) && (buttons == 0))
132
		if ((obj->flags & TrackMouse) && (buttons == 0))
133
			ReleaseCapture();
133
			ReleaseCapture();
134
		if (obj->call && obj->call->mouseup)
134
		if (obj->call && obj->call->mouseup)
135
			obj->call->mouseup(obj, buttons, xy);
135
			obj->call->mouseup(obj, buttons, xy);
136
		break;
136
		break;
137
	}
137
	}
138
}
138
}
139
 
139
 
140
/*
140
/*
141
 *  Some WM_KEYDOWN VK_* messages call the keyaction associated
141
 *  Some WM_KEYDOWN VK_* messages call the keyaction associated
142
 *  with a window.
142
 *  with a window.
143
 */
143
 */
144
static void handle_virtual_keydown(object obj, int param)
144
static void handle_virtual_keydown(object obj, int param)
145
{
145
{
146
	if ((! obj->call) || (! obj->call->keyaction))
146
	if ((! obj->call) || (! obj->call->keyaction))
147
		return;
147
		return;
148
 
148
 
149
	/* translate arrow key combinations into Unicode arrow symbols */
149
	/* translate arrow key combinations into Unicode arrow symbols */
150
	if ((param >= VK_LEFT) && (param <= VK_DOWN)) {
150
	if ((param >= VK_LEFT) && (param <= VK_DOWN)) {
151
		param += (LEFT - VK_LEFT);
151
		param += (LEFT - VK_LEFT);
152
	}
152
	}
153
 
153
 
154
	/* translate functions keys into Unicode circled numbers */
154
	/* translate functions keys into Unicode circled numbers */
155
	else if ((param >= VK_F1) && (param <= VK_F10)) {
155
	else if ((param >= VK_F1) && (param <= VK_F10)) {
156
		param += (F1 - VK_F1);
156
		param += (F1 - VK_F1);
157
	}
157
	}
158
 
158
 
159
	/* translate other keyboard keys into Unicode 'equivalents' */
159
	/* translate other keyboard keys into Unicode 'equivalents' */
160
	else switch (param) {
160
	else switch (param) {
161
		case VK_PRIOR:	param = PGUP; break;
161
		case VK_PRIOR:	param = PGUP; break;
162
		case VK_NEXT:	param = PGDN; break;
162
		case VK_NEXT:	param = PGDN; break;
163
		case VK_END:	param = END;  break;
163
		case VK_END:	param = END;  break;
164
		case VK_HOME:	param = HOME; break;
164
		case VK_HOME:	param = HOME; break;
165
		case VK_INSERT:	param = INS;  break;
165
		case VK_INSERT:	param = INS;  break;
166
		case VK_DELETE:	param = DEL;  break;
166
		case VK_DELETE:	param = DEL;  break;
167
		default:	return; /* do nothing */
167
		default:	return; /* do nothing */
168
	}
168
	}
169
 
169
 
170
	drawto(obj);
170
	drawto(obj);
171
	obj->call->keyaction(obj, param);
171
	obj->call->keyaction(obj, param);
172
}
172
}
173
 
173
 
174
static void handle_keydown(int param)
174
static void handle_keydown(int param)
175
{
175
{
176
        if (param == VK_SHIFT)
176
        if (param == VK_SHIFT)
177
		keystate |= ShiftKey;
177
		keystate |= ShiftKey;
178
	else if (param == VK_CONTROL)
178
	else if (param == VK_CONTROL)
179
		keystate |= CtrlKey;
179
		keystate |= CtrlKey;
180
	else if (param == VK_MENU)
180
	else if (param == VK_MENU)
181
		keystate |= AltKey;
181
		keystate |= AltKey;
182
}
182
}
183
 
183
 
184
static void handle_keyup(int param)
184
static void handle_keyup(int param)
185
{
185
{
186
        if (param == VK_SHIFT)
186
        if (param == VK_SHIFT)
187
		keystate &= ~ShiftKey;
187
		keystate &= ~ShiftKey;
188
	else if (param == VK_CONTROL)
188
	else if (param == VK_CONTROL)
189
		keystate &= ~CtrlKey;
189
		keystate &= ~CtrlKey;
190
	else if (param == VK_MENU)
190
	else if (param == VK_MENU)
191
		keystate &= ~AltKey;
191
		keystate &= ~AltKey;
192
}
192
}
193
 
193
 
194
/*
194
/*
195
 *  Handle char messages.
195
 *  Handle char messages.
196
 */
196
 */
197
static void handle_char(object obj, int ch)
197
static void handle_char(object obj, int ch)
198
{
198
{
199
	if (obj->call && obj->call->keydown) {
199
	if (obj->call && obj->call->keydown) {
200
		if (ch == '\r') /* carriage return becomes newline */
200
		if (ch == '\r') /* carriage return becomes newline */
201
			ch = '\n';
201
			ch = '\n';
202
		drawto(obj);
202
		drawto(obj);
203
		obj->call->keydown(obj, ch);
203
		obj->call->keydown(obj, ch);
204
	}
204
	}
205
}
205
}
206
 
206
 
207
static void handle_mdiframesize() {
207
static void handle_mdiframesize() {
208
     HWND tool=NULL ,status=NULL;
208
     HWND tool=NULL ,status=NULL;
209
     RECT rFrame,rToolbar;
209
     RECT rFrame,rToolbar;
210
     int  fw, fh, th=0, sh=0;
210
     int  fw, fh, th=0, sh=0;
211
     GetClientRect(hwndFrame,&rFrame);
211
     GetClientRect(hwndFrame,&rFrame);
212
     fw = rFrame.right-rFrame.left;
212
     fw = rFrame.right-rFrame.left;
213
     fh = rFrame.bottom-rFrame.top;
213
     fh = rFrame.bottom-rFrame.top;
214
     if (MDIToolbar) {
214
     if (MDIToolbar) {
215
        tool = (HWND)MDIToolbar->handle;
215
        tool = (HWND)MDIToolbar->handle;
216
        GetWindowRect(tool,&rToolbar);
216
        GetWindowRect(tool,&rToolbar);
217
        th = rToolbar.bottom-rToolbar.top;
217
        th = rToolbar.bottom-rToolbar.top;
218
     }
218
     }
219
     if (MDIStatus) {
219
     if (MDIStatus) {
220
        status = (HWND)MDIStatus;
220
        status = (HWND)MDIStatus;
221
        GetWindowRect(status,&rToolbar);
221
        GetWindowRect(status,&rToolbar);
222
        sh = rToolbar.bottom-rToolbar.top;
222
        sh = rToolbar.bottom-rToolbar.top;
223
     }
223
     }
224
     MoveWindow(hwndClient,0,th+1,fw,fh-sh-th-1,TRUE);
224
     MoveWindow(hwndClient,0,th+1,fw,fh-sh-th-1,TRUE);
225
     if (tool) {
225
     if (tool) {
226
        MoveWindow(tool,1,0,fw-2,th,TRUE);
226
        MoveWindow(tool,1,0,fw-2,th,TRUE);
227
        show(MDIToolbar);
227
        show(MDIToolbar);
228
     }
228
     }
229
     if (status) {
229
     if (status) {
230
        MoveWindow(status,1,fh-sh,fw-2,sh,TRUE);
230
        MoveWindow(status,1,fh-sh,fw-2,sh,TRUE);
231
     }
231
     }
232
     SetFocus((HWND)SendMessage(hwndClient,
232
     SetFocus((HWND)SendMessage(hwndClient,
233
                WM_MDIGETACTIVE,(WPARAM)0,(LPARAM) 0));
233
                WM_MDIGETACTIVE,(WPARAM)0,(LPARAM) 0));
234
}
234
}
235
 
235
 
236
/*
236
/*
237
 *  The window is being resized for some reason.
237
 *  The window is being resized for some reason.
238
 */
238
 */
239
static void handle_resize(object obj)
239
static void handle_resize(object obj)
240
{
240
{
241
	if (obj->call && obj->call->resize) {
241
	if (obj->call && obj->call->resize) {
242
		drawto(obj);
242
		drawto(obj);
243
		obj->call->resize(obj,
243
		obj->call->resize(obj,
244
			rect(0,0,obj->rect.width,obj->rect.height));
244
			rect(0,0,obj->rect.width,obj->rect.height));
245
	}
245
	}
-
 
246
	deletion_traversal();  /* We may be called again before 
-
 
247
				  returning to doevent */
246
}
248
}
247
 
249
 
248
/*
250
/*
249
 *  The window is being redrawn for some reason.
251
 *  The window is being redrawn for some reason.
250
 */
252
 */
251
static void handle_redraw(object obj, HWND hwnd)
253
static void handle_redraw(object obj, HWND hwnd)
252
{
254
{
253
	PAINTSTRUCT ps;
255
	PAINTSTRUCT ps;
254
        if (obj==MDIFrame)
256
        if (obj==MDIFrame)
255
                handle_mdiframesize();
257
                handle_mdiframesize();
256
	del_context(obj);
258
	del_context(obj);
257
	add_context(obj, BeginPaint(hwnd, &ps), NULL);
259
	add_context(obj, BeginPaint(hwnd, &ps), NULL);
258
	if (ps.fErase)
260
	if (ps.fErase)
259
		clear(obj);
261
		clear(obj);
260
	draw(obj);
262
	draw(obj);
261
	EndPaint(hwnd, &ps);
263
	EndPaint(hwnd, &ps);
262
	remove_context(obj);
264
	remove_context(obj);
263
	dc = 0;
265
	dc = 0;
264
}
266
}
265
 
267
 
266
/*
268
/*
267
 *  Hide an application window, or call close() function if possible.
269
 *  Hide an application window, or call close() function if possible.
268
 */
270
 */
269
static void handle_close(object obj)
271
static void handle_close(object obj)
270
{
272
{
271
	if (obj->call && obj->call->close) {
273
	if (obj->call && obj->call->close) {
272
		drawto(obj);
274
		drawto(obj);
273
		obj->call->close(obj);
275
		obj->call->close(obj);
274
	} else {
276
	} else {
275
		hide(obj);
277
		hide(obj);
276
	}
278
	}
277
}
279
}
278
 
280
 
279
static void handle_destroy(object obj)
281
static void handle_destroy(object obj)
280
{
282
{
281
	/*
283
	/*
282
	drawto(obj);
284
	drawto(obj);
283
	del_object(obj);
285
	del_object(obj);
284
	*/
286
	*/
285
}
287
}
286
 
288
 
287
static void handle_focus(object obj, int gained_focus)
289
static void handle_focus(object obj, int gained_focus)
288
{
290
{
289
	if (gained_focus)
291
	if (gained_focus)
290
		obj->state |= Focus;
292
		obj->state |= Focus;
291
	else
293
	else
292
		obj->state &= ~Focus;
294
		obj->state &= ~Focus;
293
	if ((! USE_NATIVE_BUTTONS) && (obj->kind == ButtonObject))
295
	if ((! USE_NATIVE_BUTTONS) && (obj->kind == ButtonObject))
294
		InvalidateRect(obj->handle, NULL, 0);
296
		InvalidateRect(obj->handle, NULL, 0);
295
}
297
}
296
 
298
 
297
/*
299
/*
298
 *  Handle scrollbars. Designed to also work with normal window
300
 *  Handle scrollbars. Designed to also work with normal window
299
 *  scrollbars.
301
 *  scrollbars.
300
 */
302
 */
301
static void handle_scroll(object obj, HWND hwnd, UINT message,
303
static void handle_scroll(object obj, HWND hwnd, UINT message,
302
				WPARAM wParam, LPARAM lParam)
304
				WPARAM wParam, LPARAM lParam)
303
{
305
{
304
	int size_shown = 10;
306
	int size_shown = 10;
305
	int max_value = 100;
307
	int max_value = 100;
306
	int where = 0;
308
	int where = 0;
307
	int prev = 0;
309
	int prev = 0;
308
	/* we need to look at the recorded values */
310
	/* we need to look at the recorded values */
309
	max_value = obj->max;
311
	max_value = obj->max;
310
	size_shown = obj->size;
312
	size_shown = obj->size;
311
	if (obj->kind != WindowObject) {
313
	if (obj->kind != WindowObject) {
312
		prev = where = GetScrollPos(hwnd, SB_CTL);
314
		prev = where = GetScrollPos(hwnd, SB_CTL);
313
	}
315
	}
314
	else if (message == WM_VSCROLL) {
316
	else if (message == WM_VSCROLL) {
315
		prev = where = GetScrollPos(hwnd, SB_VERT);
317
		prev = where = GetScrollPos(hwnd, SB_VERT);
316
	} else if (message == WM_HSCROLL) {
318
	} else if (message == WM_HSCROLL) {
317
	    prev = where = GetScrollPos(hwnd, SB_HORZ);
319
	    prev = where = GetScrollPos(hwnd, SB_HORZ);
318
	    max_value = obj->xmax;
320
	    max_value = obj->xmax;
319
	    size_shown = obj->xsize;
321
	    size_shown = obj->xsize;
320
	}
322
	}
321
 
323
 
322
	/* next we look at wParam to see what happened */
324
	/* next we look at wParam to see what happened */
323
	switch(LOWORD(wParam))
325
	switch(LOWORD(wParam))
324
	{
326
	{
325
	case SB_PAGEDOWN:	where += (size_shown-1);
327
	case SB_PAGEDOWN:	where += (size_shown-1);
326
				/* fall through to next case */
328
				/* fall through to next case */
327
	case SB_LINEDOWN:	where = min(max_value, where+1);
329
	case SB_LINEDOWN:	where = min(max_value, where+1);
328
				break;
330
				break;
329
	case SB_PAGEUP:		where -= (size_shown-1);
331
	case SB_PAGEUP:		where -= (size_shown-1);
330
				/* fall through to next case */
332
				/* fall through to next case */
331
	case SB_LINEUP:		where = max(0, where-1);
333
	case SB_LINEUP:		where = max(0, where-1);
332
				break;
334
				break;
333
	case SB_TOP:		where = 0;
335
	case SB_TOP:		where = 0;
334
				break;
336
				break;
335
	case SB_BOTTOM:		where = max_value;
337
	case SB_BOTTOM:		where = max_value;
336
				break;
338
				break;
337
	case SB_THUMBPOSITION:
339
	case SB_THUMBPOSITION:
338
	case SB_THUMBTRACK:
340
	case SB_THUMBTRACK:
339
		#ifdef WIN32
341
		#ifdef WIN32
340
				where = HIWORD(wParam);
342
				where = HIWORD(wParam);
341
		#else
343
		#else
342
				where = LOWORD(lParam);
344
				where = LOWORD(lParam);
343
		#endif
345
		#endif
344
				break;
346
				break;
345
	default:		break;
347
	default:		break;
346
	}
348
	}
347
	/* check if something happened */
349
	/* check if something happened */
348
	if (prev == where)
350
	if (prev == where)
349
		return;
351
		return;
350
	/* now we reset the scrollbar's values */
352
	/* now we reset the scrollbar's values */
351
	if (obj->kind != WindowObject) {
353
	if (obj->kind != WindowObject) {
352
		SetScrollPos(hwnd, SB_CTL, where, 1);
354
		SetScrollPos(hwnd, SB_CTL, where, 1);
353
	}
355
	}
354
	else if (message == WM_VSCROLL) {
356
	else if (message == WM_VSCROLL) {
355
	       SetScrollPos(hwnd, SB_VERT, where, 1);
357
	       SetScrollPos(hwnd, SB_VERT, where, 1);
356
        }
358
        }
357
	else if (message == WM_HSCROLL) {
359
	else if (message == WM_HSCROLL) {
358
	       SetScrollPos(hwnd, SB_HORZ, where, 1);
360
	       SetScrollPos(hwnd, SB_HORZ, where, 1);
359
               where = -(where+1);
361
               where = -(where+1);
360
        }
362
        }
361
        setvalue(obj, where);
363
        setvalue(obj, where);
362
        activatecontrol(obj);
364
        activatecontrol(obj);
363
}
365
}
364
 
366
 
365
/*
367
/*
366
 *  Perform some brush manipulation to handle background colours
368
 *  Perform some brush manipulation to handle background colours
367
 *  in native checkboxes and radio buttons.
369
 *  in native checkboxes and radio buttons.
368
 */
370
 */
369
#if USE_NATIVE_TOGGLES
371
#if USE_NATIVE_TOGGLES
370
  #ifdef WM_CTLCOLOR
372
  #ifdef WM_CTLCOLOR
371
static void handle_colour(HDC dc, object obj)
373
static void handle_colour(HDC dc, object obj)
372
{
374
{
373
	rgb fg, bg;
375
	rgb fg, bg;
374
	COLORREF wincolour;
376
	COLORREF wincolour;
375
 
377
 
376
	if (obj->drawstate)
378
	if (obj->drawstate)
377
		fg = obj->drawstate->hue;
379
		fg = obj->drawstate->hue;
378
	else
380
	else
379
		fg = obj->fg;
381
		fg = obj->fg;
380
	wincolour = RGB((fg&Red)>>16,(fg&Green)>>8,(fg&Blue));
382
	wincolour = RGB((fg&Red)>>16,(fg&Green)>>8,(fg&Blue));
381
	SetTextColor(dc, wincolour);
383
	SetTextColor(dc, wincolour);
382
 
384
 
383
	bg = obj->bg;
385
	bg = obj->bg;
384
	wincolour = RGB((bg&Red)>>16,(bg&Green)>>8,(bg&Blue));
386
	wincolour = RGB((bg&Red)>>16,(bg&Green)>>8,(bg&Blue));
385
	SetBkColor(dc, wincolour);
387
	SetBkColor(dc, wincolour);
386
 
388
 
387
	fix_brush(dc, obj, obj->bgbrush);
389
	fix_brush(dc, obj, obj->bgbrush);
388
}
390
}
389
   #endif
391
   #endif
390
#endif
392
#endif
391
 
393
 
392
static char dfilename[MAX_PATH + 1];
394
static char dfilename[MAX_PATH + 1];
393
static void handle_drop(object obj, HANDLE dropstruct)
395
static void handle_drop(object obj, HANDLE dropstruct)
394
{
396
{
395
    if (obj->call && obj->call->drop) {
397
    if (obj->call && obj->call->drop) {
396
	int len = DragQueryFile(dropstruct, 0, NULL, 0);
398
	int len = DragQueryFile(dropstruct, 0, NULL, 0);
397
	if (len > MAX_PATH) {
399
	if (len > MAX_PATH) {
398
	    DragFinish(dropstruct);
400
	    DragFinish(dropstruct);
399
	    return;
401
	    return;
400
	}
402
	}
401
	DragQueryFile(dropstruct, 0, dfilename, MAX_PATH);
403
	DragQueryFile(dropstruct, 0, dfilename, MAX_PATH);
402
	DragFinish(dropstruct);
404
	DragFinish(dropstruct);
403
	obj->call->drop(obj, dfilename);
405
	obj->call->drop(obj, dfilename);
404
    }
406
    }
405
}
407
}
406
 
408
 
407
/*
409
/*
408
 *  Shared window procedure code. The pass variable is initially zero.
410
 *  Shared window procedure code. The pass variable is initially zero.
409
 *  It can be set to non-zero in this procedure if we wish to pass
411
 *  It can be set to non-zero in this procedure if we wish to pass
410
 *  the event to the default Windows winprocs.
412
 *  the event to the default Windows winprocs.
411
 */
413
 */
412
static long handle_message(HWND hwnd, UINT message,
414
static long handle_message(HWND hwnd, UINT message,
413
			WPARAM wParam, LONG lParam, int *pass)
415
			WPARAM wParam, LONG lParam, int *pass)
414
{
416
{
415
	object obj;
417
	object obj;
416
 
418
 
417
	/* Find the library object associated with the hwnd. */
419
	/* Find the library object associated with the hwnd. */
418
	obj = find_by_handle(hwnd);
420
	obj = find_by_handle(hwnd);
419
 
421
 
420
	if (! obj) { /* Not a library object ... */
422
	if (! obj) { /* Not a library object ... */
421
		*pass = 1; /* ... so pass the event. */
423
		*pass = 1; /* ... so pass the event. */
422
		return 0;
424
		return 0;
423
	}
425
	}
424
 
426
 
425
	frontwindow = obj; /* Needed for auto-mousedowns. */
427
	frontwindow = obj; /* Needed for auto-mousedowns. */
426
 
428
 
427
	/* Handle mouse messages. */
429
	/* Handle mouse messages. */
428
	if ((message >= WM_MOUSEMOVE) && (message <= WM_MBUTTONDBLCLK))
430
	if ((message >= WM_MOUSEMOVE) && (message <= WM_MBUTTONDBLCLK))
429
	{
431
	{
430
		handle_mouse(obj, hwnd, message, LOWORD(wParam),
432
		handle_mouse(obj, hwnd, message, LOWORD(wParam),
431
				LOWORD(lParam), HIWORD(lParam));
433
				LOWORD(lParam), HIWORD(lParam));
432
		return 0;
434
		return 0;
433
	}
435
	}
434
 
436
 
435
	/* Handle other messages. */
437
	/* Handle other messages. */
436
	switch (message)
438
	switch (message)
437
	{
439
	{
438
	case WM_KEYDOWN: /* record state of shift and control keys */
440
	case WM_KEYDOWN: /* record state of shift and control keys */
439
		handle_keydown(LOWORD(wParam));
441
		handle_keydown(LOWORD(wParam));
440
		handle_virtual_keydown(obj, LOWORD(wParam));
442
		handle_virtual_keydown(obj, LOWORD(wParam));
441
		break;
443
		break;
442
 
444
 
443
	case WM_KEYUP: /* record state of shift and control keys */
445
	case WM_KEYUP: /* record state of shift and control keys */
444
		handle_keyup(LOWORD(wParam));
446
		handle_keyup(LOWORD(wParam));
445
		break;
447
		break;
446
 
448
 
447
	case WM_CHAR:
449
	case WM_CHAR:
448
		handle_char(obj, LOWORD(wParam));
450
		handle_char(obj, LOWORD(wParam));
449
		return 0;
451
		return 0;
450
 
452
 
451
	case WM_SETFOCUS:
453
	case WM_SETFOCUS:
452
		handle_focus(obj, 1);
454
		handle_focus(obj, 1);
453
		break;
455
		break;
454
 
456
 
455
	case WM_KILLFOCUS:
457
	case WM_KILLFOCUS:
456
		handle_focus(obj, 0);
458
		handle_focus(obj, 0);
457
		break;
459
		break;
458
 
460
 
459
	case WM_PAINT:
461
	case WM_PAINT:
460
		handle_redraw(obj, hwnd);
462
		handle_redraw(obj, hwnd);
461
		return 0;
463
		return 0;
462
 
464
 
463
	case WM_INITMENUPOPUP:
465
	case WM_INITMENUPOPUP:
464
		if (HIWORD(lParam)) /* true if system menu */
466
		if (HIWORD(lParam)) /* true if system menu */
465
			return 0; /* else fall through */
467
			return 0; /* else fall through */
466
	case WM_INITMENU:
468
	case WM_INITMENU:
467
		adjust_menu(wParam);
469
		adjust_menu(wParam);
468
		break;
470
		break;
469
 
471
 
470
	case WM_MOVE:
472
	case WM_MOVE:
471
		obj->rect.x = LOWORD(lParam);
473
		obj->rect.x = LOWORD(lParam);
472
		obj->rect.y = HIWORD(lParam);
474
		obj->rect.y = HIWORD(lParam);
473
		break;
475
		break;
474
 
476
 
475
	case WM_SIZE:
477
	case WM_SIZE:
476
		obj->rect.width = LOWORD(lParam);
478
		obj->rect.width = LOWORD(lParam);
477
		obj->rect.height = HIWORD(lParam);
479
		obj->rect.height = HIWORD(lParam);
478
		handle_resize(obj);
480
		handle_resize(obj);
479
		break;
481
		break;
480
 
482
 
481
	case WM_ACTIVATE:
483
	case WM_ACTIVATE:
482
		/* Keep track of which window is in front. */
484
		/* Keep track of which window is in front. */
483
		if (LOWORD(wParam) != WA_INACTIVE)
485
		if (LOWORD(wParam) != WA_INACTIVE)
484
			move_to_front(obj);
486
			move_to_front(obj);
485
		break;
487
		break;
486
 
488
 
487
	case WM_QUERYENDSESSION:
489
	case WM_QUERYENDSESSION:
488
		handle_close(obj);
490
		handle_close(obj);
489
		return 1L; /* ensure Windows can terminate */
491
		return 1L; /* ensure Windows can terminate */
490
 
492
 
491
	case WM_CLOSE:
493
	case WM_CLOSE:
492
		handle_close(obj);
494
		handle_close(obj);
493
		return 0;
495
		return 0;
494
 
496
 
495
	case WM_DESTROY:
497
	case WM_DESTROY:
496
		handle_destroy(obj);
498
		handle_destroy(obj);
497
		break;
499
		break;
498
 
500
 
499
	/*case WM_SYSCOMMAND:*/
501
	/*case WM_SYSCOMMAND:*/
500
	case WM_COMMAND:
502
	case WM_COMMAND:
501
		if (LOWORD(wParam) >= MinDocID)
503
		if (LOWORD(wParam) >= MinDocID)
502
			break; /* MDI Client window will handle it */
504
			break; /* MDI Client window will handle it */
503
		else if (LOWORD(wParam) >= MinChildID) {
505
		else if (LOWORD(wParam) >= MinChildID) {
504
		#ifdef WIN32
506
		#ifdef WIN32
505
			handle_control((HWND) lParam, HIWORD(wParam));
507
			handle_control((HWND) lParam, HIWORD(wParam));
506
		#else
508
		#else
507
			handle_control((HWND) LOWORD(lParam), HIWORD(lParam));
509
			handle_control((HWND) LOWORD(lParam), HIWORD(lParam));
508
		#endif /* WIN32 */
510
		#endif /* WIN32 */
509
		}
511
		}
510
		else if ((LOWORD(wParam) >= MinMenuID) && menus_active)
512
		else if ((LOWORD(wParam) >= MinMenuID) && menus_active)
511
			handle_menu_id(LOWORD(wParam));
513
			handle_menu_id(LOWORD(wParam));
512
		break;
514
		break;
513
 
515
 
514
	case WM_VSCROLL:
516
	case WM_VSCROLL:
515
	case WM_HSCROLL:
517
	case WM_HSCROLL:
516
		#ifdef WIN32
518
		#ifdef WIN32
517
		if ( lParam != 0) { /* scrollbar object */
519
		if ( lParam != 0) { /* scrollbar object */
518
			hwnd = (HWND) lParam;
520
			hwnd = (HWND) lParam;
519
		#else
521
		#else
520
		if (HIWORD(lParam) != 0) { /* scrollbar object */
522
		if (HIWORD(lParam) != 0) { /* scrollbar object */
521
			hwnd = (HWND) HIWORD(lParam);
523
			hwnd = (HWND) HIWORD(lParam);
522
		#endif /* WIN32 */
524
		#endif /* WIN32 */
523
			obj = find_by_handle(hwnd);
525
			obj = find_by_handle(hwnd);
524
			if (! obj)
526
			if (! obj)
525
				return 0;
527
				return 0;
526
		}
528
		}
527
		handle_scroll(obj, hwnd, message, wParam, lParam);
529
		handle_scroll(obj, hwnd, message, wParam, lParam);
528
		return 0;
530
		return 0;
529
 
531
 
530
#if USE_NATIVE_TOGGLES
532
#if USE_NATIVE_TOGGLES
531
  #ifdef WM_CTLCOLOR
533
  #ifdef WM_CTLCOLOR
532
	case WM_CTLCOLOR:
534
	case WM_CTLCOLOR:
533
		#ifdef WIN32
535
		#ifdef WIN32
534
		hwnd = (HWND) lParam;
536
		hwnd = (HWND) lParam;
535
		#else
537
		#else
536
		hwnd = (HWND) LOWORD(lParam);
538
		hwnd = (HWND) LOWORD(lParam);
537
		#endif  /* WIN32 */
539
		#endif  /* WIN32 */
538
 
540
 
539
		obj = find_by_handle(hwnd);
541
		obj = find_by_handle(hwnd);
540
		if (! obj)
542
		if (! obj)
541
			break;
543
			break;
542
		if ((obj->kind != CheckboxObject) && (obj->kind != RadioObject))
544
		if ((obj->kind != CheckboxObject) && (obj->kind != RadioObject))
543
			break;
545
			break;
544
		handle_colour((HDC) wParam, obj);
546
		handle_colour((HDC) wParam, obj);
545
		return (LRESULT) obj->bgbrush;
547
		return (LRESULT) obj->bgbrush;
546
  #endif
548
  #endif
547
#endif
549
#endif
548
        case WM_DROPFILES:
550
        case WM_DROPFILES:
549
		handle_drop(obj, (HANDLE) wParam);
551
		handle_drop(obj, (HANDLE) wParam);
550
	}
552
	}
551
 
553
 
552
	/* If we got this far the event must be passed along
554
	/* If we got this far the event must be passed along
553
	 * to the default Windows event handling procedures. */
555
	 * to the default Windows event handling procedures. */
554
	*pass = 1;
556
	*pass = 1;
555
	return 0;
557
	return 0;
556
}
558
}
557
 
559
 
558
/*
560
/*
559
 *  Window procedures call a generic window handling routine.
561
 *  Window procedures call a generic window handling routine.
560
 *  We need three window procedures since the different calls
562
 *  We need three window procedures since the different calls
561
 *  tell us which default window procedure to pass the messages
563
 *  tell us which default window procedure to pass the messages
562
 *  to if we don't wish to handle a message.
564
 *  to if we don't wish to handle a message.
563
 *  If we were to use only one window procedure, we would have to
565
 *  If we were to use only one window procedure, we would have to
564
 *  have a way of determining which is the default window proc
566
 *  have a way of determining which is the default window proc
565
 *  for a window from just knowing the hwnd (which may or may not
567
 *  for a window from just knowing the hwnd (which may or may not
566
 *  belong to us).
568
 *  belong to us).
567
 */
569
 */
568
long FAR PASCAL _export
570
long FAR PASCAL _export
569
app_win_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
571
app_win_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
570
{
572
{
571
	long result;
573
	long result;
572
	int pass = 0;
574
	int pass = 0;
573
 
575
 
574
	result = handle_message(hwnd, message, wParam, lParam, &pass);
576
	result = handle_message(hwnd, message, wParam, lParam, &pass);
575
	if (pass)
577
	if (pass)
576
		result = DefWindowProc(hwnd, message, wParam, lParam);
578
		result = DefWindowProc(hwnd, message, wParam, lParam);
577
	return result;
579
	return result;
578
}
580
}
579
 
581
 
580
long FAR PASCAL _export
582
long FAR PASCAL _export
581
app_doc_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
583
app_doc_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
582
{
584
{
583
	long result;
585
	long result;
584
	int pass = 0;
586
	int pass = 0;
585
	object obj;
587
	object obj;
586
        if ((message==WM_MDIACTIVATE) && ((HWND)lParam==hwnd)) {
588
        if ((message==WM_MDIACTIVATE) && ((HWND)lParam==hwnd)) {
587
            if (MDIToolbar) hide(MDIToolbar);
589
            if (MDIToolbar) hide(MDIToolbar);
588
            obj = find_by_handle(hwnd);
590
            obj = find_by_handle(hwnd);
589
            MDIToolbar = (obj) ? obj->toolbar : NULL;
591
            MDIToolbar = (obj) ? obj->toolbar : NULL;
590
            handle_mdiframesize();
592
            handle_mdiframesize();
591
            if (obj && obj->menubar) {
593
            if (obj && obj->menubar) {
592
                menu mdi = (obj->menubar)->menubar;
594
                menu mdi = (obj->menubar)->menubar;
593
	        SendMessage(hwndClient, WM_MDISETMENU,
595
	        SendMessage(hwndClient, WM_MDISETMENU,
594
                        (WPARAM)obj->menubar->handle,
596
                        (WPARAM)obj->menubar->handle,
595
			(LPARAM)(mdi?(mdi->handle):0));
597
			(LPARAM)(mdi?(mdi->handle):0));
596
                DrawMenuBar(hwndFrame);
598
                DrawMenuBar(hwndFrame);
597
            }
599
            }
598
            updatestatus(obj->status);
600
            updatestatus(obj->status);
599
            RedrawWindow(hwndFrame,NULL,NULL,
601
            RedrawWindow(hwndFrame,NULL,NULL,
600
                         RDW_UPDATENOW|RDW_ALLCHILDREN);
602
                         RDW_UPDATENOW|RDW_ALLCHILDREN);
601
            SetFocus(hwnd);
603
            SetFocus(hwnd);
602
            return 1;
604
            return 1;
603
	}
605
	}
604
	result = handle_message(hwnd, message, wParam, lParam, &pass);
606
	result = handle_message(hwnd, message, wParam, lParam, &pass);
605
	if (pass)
607
	if (pass)
606
		result = DefMDIChildProc(hwnd, message, wParam, lParam);
608
		result = DefMDIChildProc(hwnd, message, wParam, lParam);
607
	return result;
609
	return result;
608
}
610
}
609
 
611
 
610
long FAR PASCAL _export
612
long FAR PASCAL _export
611
app_work_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
613
app_work_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
612
{
614
{
613
	long result;
615
	long result;
614
	int pass = 0;
616
	int pass = 0;
615
	result = handle_message(hwnd, message, wParam, lParam, &pass);
617
	result = handle_message(hwnd, message, wParam, lParam, &pass);
616
	if (pass)
618
	if (pass)
617
		result = DefFrameProc(hwnd, hwndClient, message, wParam, lParam);
619
		result = DefFrameProc(hwnd, hwndClient, message, wParam, lParam);
618
	return result;
620
	return result;
619
}
621
}
620
 
622
 
621
/*
623
/*
622
 *  To handle controls correctly, we replace each control's event
624
 *  To handle controls correctly, we replace each control's event
623
 *  handling procedure with our own when we create it. We handle
625
 *  handling procedure with our own when we create it. We handle
624
 *  certain events ourselves, and pass the rest to the default
626
 *  certain events ourselves, and pass the rest to the default
625
 *  routines.
627
 *  routines.
626
 *  Things we do here include: allowing the TAB key to change
628
 *  Things we do here include: allowing the TAB key to change
627
 *  input focus to the next control; for one-line text fields
629
 *  input focus to the next control; for one-line text fields
628
 *  pressing return causes the event to be sent to the parent window.
630
 *  pressing return causes the event to be sent to the parent window.
629
 */
631
 */
630
 
632
 
631
/* Send a char to an object, or its parent if it has no handler. */
633
/* Send a char to an object, or its parent if it has no handler. */
632
static void send_char(object obj, int ch)
634
static void send_char(object obj, int ch)
633
{
635
{
634
	while (obj) {
636
	while (obj) {
635
	    if ((obj->call) && (obj->call->keydown))
637
	    if ((obj->call) && (obj->call->keydown))
636
		break;
638
		break;
637
	    obj = obj->parent;
639
	    obj = obj->parent;
638
	}
640
	}
639
	if (! obj)
641
	if (! obj)
640
		return;
642
		return;
641
	if (ch == '\r')
643
	if (ch == '\r')
642
		ch = '\n';
644
		ch = '\n';
643
	drawto(obj);
645
	drawto(obj);
644
	obj->call->keydown(obj, ch);
646
	obj->call->keydown(obj, ch);
645
        keystate = 0;
647
        keystate = 0;
646
}
648
}
647
 
649
 
648
long FAR PASCAL _export
650
long FAR PASCAL _export
649
app_control_procedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
651
app_control_procedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
650
{
652
{
651
	int prevent_activation = 0;
653
	int prevent_activation = 0;
652
	int key;
654
	int key;
653
	long result;
655
	long result;
654
	object obj, next;
656
	object obj, next;
655
 
657
 
656
	/* Find the library object associated with the hwnd. */
658
	/* Find the library object associated with the hwnd. */
657
	obj = find_by_handle(hwnd);
659
	obj = find_by_handle(hwnd);
658
	key = LOWORD(wParam);
660
	key = LOWORD(wParam);
659
 
661
 
660
	if (! obj) /* Not a library object ... */
662
	if (! obj) /* Not a library object ... */
661
		return 0; /* ... so do nothing. */
663
		return 0; /* ... so do nothing. */
662
	if (! obj->winproc)
664
	if (! obj->winproc)
663
		return 0; /* Nowhere to send events! */
665
		return 0; /* Nowhere to send events! */
664
 
666
 
665
	next = find_valid_sibling(obj->next);
667
	next = find_valid_sibling(obj->next);
666
 
668
 
667
	if (message == WM_KEYDOWN)
669
	if (message == WM_KEYDOWN)
668
		handle_keydown(key);
670
		handle_keydown(key);
669
	else if (message == WM_KEYUP)
671
	else if (message == WM_KEYUP)
670
		handle_keyup(key);
672
		handle_keyup(key);
671
 
673
 
672
	switch (message)
674
	switch (message)
673
	{
675
	{
674
	  case WM_KEYDOWN:
676
	  case WM_KEYDOWN:
675
	    if (obj->kind == TextboxObject) {
677
	    if (obj->kind == TextboxObject) {
676
		if ((key == VK_TAB) && (keystate & CtrlKey)) {
678
		if ((key == VK_TAB) && (keystate & CtrlKey)) {
677
			SetFocus(next->handle);
679
			SetFocus(next->handle);
678
			return 0;
680
			return 0;
679
		  }
681
		  }
680
	    	break;
682
	    	break;
681
	    }
683
	    }
682
	    if (key == VK_TAB) {
684
	    if (key == VK_TAB) {
683
		SetFocus(next->handle);
685
		SetFocus(next->handle);
684
		return 0;
686
		return 0;
685
	    }
687
	    }
686
	    else if ((key == VK_RETURN) || (key == VK_ESCAPE)) {
688
	    else if ((key == VK_RETURN) || (key == VK_ESCAPE)) {
687
		send_char(obj, key);
689
		send_char(obj, key);
688
		return 0;
690
		return 0;
689
	    }
691
	    }
690
	    break;
692
	    break;
691
 
693
 
692
	  case WM_CHAR:
694
	  case WM_CHAR:
693
	    switch (obj->kind) {
695
	    switch (obj->kind) {
694
		case TextboxObject:
696
		case TextboxObject:
695
			break;
697
			break;
696
		case LabelObject:
698
		case LabelObject:
697
		case ButtonObject:   case CheckboxObject:
699
		case ButtonObject:   case CheckboxObject:
698
		case RadioObject:    case ScrollbarObject:
700
		case RadioObject:    case ScrollbarObject:
699
		case ListboxObject:  case MultilistObject:
701
		case ListboxObject:  case MultilistObject:
700
		case DroplistObject: case DropfieldObject:
702
		case DroplistObject: case DropfieldObject:
701
			if (key != ' ') {
703
			if (key != ' ') {
702
				send_char(obj, key);
704
				send_char(obj, key);
703
				return 0;
705
				return 0;
704
			}
706
			}
705
		case FieldObject:
707
		case FieldObject:
706
			if (key == '\t')
708
			if (key == '\t')
707
				return 0;
709
				return 0;
708
			if ((key == '\n') || (key == ESC))
710
			if ((key == '\n') || (key == ESC))
709
				return 0;
711
				return 0;
710
		break;
712
		break;
711
	    }
713
	    }
712
	    break;
714
	    break;
713
 
715
 
714
	  case WM_SETFOCUS:
716
	  case WM_SETFOCUS:
715
	    if (obj->kind == RadioObject) {
717
	    if (obj->kind == RadioObject) {
716
		/* Temporarily disable the control manually.
718
		/* Temporarily disable the control manually.
717
		 * We do this to work around the way Windows
719
		 * We do this to work around the way Windows
718
		 * sends WM_COMMAND messages to radio buttons
720
		 * sends WM_COMMAND messages to radio buttons
719
		 * when we use TAB to set focus to them. */
721
		 * when we use TAB to set focus to them. */
720
#if USE_NATIVE_TOGGLES
722
#if USE_NATIVE_TOGGLES
721
		if (isenabled(obj)) {
723
		if (isenabled(obj)) {
722
			obj->state &= ~Enabled;
724
			obj->state &= ~Enabled;
723
			prevent_activation = 1;
725
			prevent_activation = 1;
724
		}
726
		}
725
#endif
727
#endif
726
	    }
728
	    }
727
	    else if (obj->kind == FieldObject) {
729
	    else if (obj->kind == FieldObject) {
728
		#ifdef WIN32
730
		#ifdef WIN32
729
		sendmessage(hwnd, EM_SETSEL, 32767, 32767);
731
		sendmessage(hwnd, EM_SETSEL, 32767, 32767);
730
		#else
732
		#else
731
		sendmessage(hwnd, EM_SETSEL, 0, MAKELONG(32767,32767));
733
		sendmessage(hwnd, EM_SETSEL, 0, MAKELONG(32767,32767));
732
		#endif /* WIN32 */
734
		#endif /* WIN32 */
733
	    }
735
	    }
734
	    break;
736
	    break;
735
	}
737
	}
736
 
738
 
737
	result = CallWindowProc((obj->winproc), hwnd, message, wParam, lParam);
739
	result = CallWindowProc((obj->winproc), hwnd, message, wParam, lParam);
738
 
740
 
739
	/* Re-activate the control if necessary. */
741
	/* Re-activate the control if necessary. */
740
	if (prevent_activation)
742
	if (prevent_activation)
741
		obj->state |= Enabled;
743
		obj->state |= Enabled;
742
	return result;
744
	return result;
743
}
745
}
744
 
746
 
745
/*
747
/*
746
 *  Timer functions use a timer procedure not associated with a window.
748
 *  Timer functions use a timer procedure not associated with a window.
747
 *  We use this one procedure to handle both timer events and mouse-down
749
 *  We use this one procedure to handle both timer events and mouse-down
748
 *  timer events. The mouse-down timer happens when the user has held
750
 *  timer events. The mouse-down timer happens when the user has held
749
 *  a mouse button down for longer than mouse_msec milliseconds, and
751
 *  a mouse button down for longer than mouse_msec milliseconds, and
750
 *  it causes the last mouse event to repeat.
752
 *  it causes the last mouse event to repeat.
751
 */
753
 */
752
UINT FAR PASCAL _export
754
UINT FAR PASCAL _export
753
app_timer_procedure(HWND hwnd, UINT message, UINT tid, DWORD time)
755
app_timer_procedure(HWND hwnd, UINT message, UINT tid, DWORD time)
754
{
756
{
755
	object obj;
757
	object obj;
756
	UINT id = LOWORD(tid);
758
	UINT id = LOWORD(tid);
757
 
759
 
758
	if ((id == 0) || (message != WM_TIMER))
760
	if ((id == 0) || (message != WM_TIMER))
759
		return 0;
761
		return 0;
760
 
762
 
761
	if (id == mouse_timer_id) {
763
	if (id == mouse_timer_id) {
762
		obj = frontwindow;
764
		obj = frontwindow;
763
		if ((buttons == 0) || (! obj) || (! obj->call)
765
		if ((buttons == 0) || (! obj) || (! obj->call)
764
			|| (! obj->call->mouserepeat))
766
			|| (! obj->call->mouserepeat))
765
				setmousetimer(0);
767
				setmousetimer(0);
766
		else
768
		else
767
			obj->call->mouserepeat(obj, buttons, xy);
769
			obj->call->mouserepeat(obj, buttons, xy);
768
	}
770
	}
769
	else if (id == timer_id) {
771
	else if (id == timer_id) {
770
		if (do_timer)
772
		if (do_timer)
771
			do_timer(timer_data);
773
			do_timer(timer_data);
772
	}
774
	}
773
 
775
 
774
	return 0;
776
	return 0;
775
}
777
}
776
 
778
 
777
/*
779
/*
778
 *  Set the timer function.
780
 *  Set the timer function.
779
 */
781
 */
780
void settimerfn(timerfn timeout, void *data)
782
void settimerfn(timerfn timeout, void *data)
781
{
783
{
782
	do_timer = timeout;
784
	do_timer = timeout;
783
	timer_data = data;
785
	timer_data = data;
784
}
786
}
785
 
787
 
786
/*
788
/*
787
 * Start the timer with a period of msec milliseconds.
789
 * Start the timer with a period of msec milliseconds.
788
 */
790
 */
789
int settimer(unsigned msec)
791
int settimer(unsigned msec)
790
{
792
{
791
	if (timer_id != 0) {
793
	if (timer_id != 0) {
792
		KillTimer(0, timer_id);
794
		KillTimer(0, timer_id);
793
		timer_id = 0;
795
		timer_id = 0;
794
	}
796
	}
795
	if (msec == 0)
797
	if (msec == 0)
796
		timer_id = 0;
798
		timer_id = 0;
797
	else {
799
	else {
798
		timer_id = SetTimer(0, 0, (UINT) msec, app_timer_proc);
800
		timer_id = SetTimer(0, 0, (UINT) msec, app_timer_proc);
799
		if (timer_id == 0)
801
		if (timer_id == 0)
800
			return 0;
802
			return 0;
801
	}
803
	}
802
	return 1;
804
	return 1;
803
}
805
}
804
 
806
 
805
/*
807
/*
806
 * Start the mouse-down timer with a period of msec milliseconds.
808
 * Start the mouse-down timer with a period of msec milliseconds.
807
 *
809
 *
808
 * Notes: setmousetimer() starts the mouse-down auto-repeat timer.
810
 * Notes: setmousetimer() starts the mouse-down auto-repeat timer.
809
 *  The timer will not do anything unless the user holds down a
811
 *  The timer will not do anything unless the user holds down a
810
 *  mouse button for longer than msec milliseconds, in which case
812
 *  mouse button for longer than msec milliseconds, in which case
811
 *  it will call the mouserepeat function associated with which ever
813
 *  it will call the mouserepeat function associated with which ever
812
 *  window is currently active.
814
 *  window is currently active.
813
 *  Also, an interval of zero should stop the timer without
815
 *  Also, an interval of zero should stop the timer without
814
 *  destroying the previous interval recorded in mouse_msec.
816
 *  destroying the previous interval recorded in mouse_msec.
815
 */
817
 */
816
int setmousetimer(unsigned msec)
818
int setmousetimer(unsigned msec)
817
{
819
{
818
	if (mouse_timer_id != 0) {
820
	if (mouse_timer_id != 0) {
819
		KillTimer(0, mouse_timer_id);
821
		KillTimer(0, mouse_timer_id);
820
		mouse_timer_id = 0;
822
		mouse_timer_id = 0;
821
	}
823
	}
822
	if (msec == 0) {
824
	if (msec == 0) {
823
		mouse_timer_id = 0;
825
		mouse_timer_id = 0;
824
		return 1;
826
		return 1;
825
	}
827
	}
826
	else {
828
	else {
827
		mouse_timer_id = SetTimer(0, 0, (UINT) msec, app_timer_proc);
829
		mouse_timer_id = SetTimer(0, 0, (UINT) msec, app_timer_proc);
828
		if (mouse_timer_id == 0)
830
		if (mouse_timer_id == 0)
829
			return 0;
831
			return 0;
830
	}
832
	}
831
	mouse_msec = msec;
833
	mouse_msec = msec;
832
	return 1;
834
	return 1;
833
}
835
}
834
 
836
 
835
/*
837
/*
836
 *  Delay execution for a given number of milliseconds.
838
 *  Delay execution for a given number of milliseconds.
837
 *  This is a blocking function which should be used sparingly.
839
 *  This is a blocking function which should be used sparingly.
838
 */
840
 */
839
void delay(unsigned msec)
841
void delay(unsigned msec)
840
{
842
{
841
	unsigned long now;
843
	unsigned long now;
842
	unsigned long stop;
844
	unsigned long stop;
843
 
845
 
844
	stop = msec;
846
	stop = msec;
845
	now = GetTickCount();
847
	now = GetTickCount();
846
	stop += now;
848
	stop += now;
847
	while(now < stop)
849
	while(now < stop)
848
		now = GetTickCount();
850
		now = GetTickCount();
849
}
851
}
850
 
852
 
851
/*
853
/*
852
 *  Report current time in milliseconds since initialisation of
854
 *  Report current time in milliseconds since initialisation of
853
 *  the graphics interface. Not reliable for timing events.
855
 *  the graphics interface. Not reliable for timing events.
854
 */
856
 */
855
long currenttime(void)
857
long currenttime(void)
856
{
858
{
857
	return GetTickCount();
859
	return GetTickCount();
858
}
860
}
859
 
861
 
860
/*
862
/*
861
 *  Intercept menu keys, since we don't always have accelerator tables.
863
 *  Intercept menu keys, since we don't always have accelerator tables.
862
 *  Return 1 if doing something which should not go to the winproc, else 0.
864
 *  Return 1 if doing something which should not go to the winproc, else 0.
863
 */
865
 */
864
static int TranslateMenuKeys(MSG *msg)
866
static int TranslateMenuKeys(MSG *msg)
865
{
867
{
866
	int key = LOWORD(msg->wParam);
868
	int key = LOWORD(msg->wParam);
867
 
869
 
868
	/* Translate F10 from syskey to normal keydown message. */
870
	/* Translate F10 from syskey to normal keydown message. */
869
	if ((key == VK_F10) && (msg->message == WM_SYSKEYDOWN))
871
	if ((key == VK_F10) && (msg->message == WM_SYSKEYDOWN))
870
		msg->message = WM_KEYDOWN;
872
		msg->message = WM_KEYDOWN;
871
 
873
 
872
	/* Check for menu control keys. */
874
	/* Check for menu control keys. */
873
/* disabled : Alt-Gr bug*/
875
/* disabled : Alt-Gr bug*/
874
        return 0;
876
        return 0;
875
	if ((keystate & CtrlKey) && (msg->message == WM_KEYDOWN))
877
	if ((keystate & CtrlKey) && (msg->message == WM_KEYDOWN))
876
	{
878
	{
877
		/* ctrl-letter or ctrl-number is a menu key */
879
		/* ctrl-letter or ctrl-number is a menu key */
878
		if (((key >= 'A') && (key <= 'Z')) ||
880
		if (((key >= 'A') && (key <= 'Z')) ||
879
			((key >= '0') && (key <= '9')))
881
			((key >= '0') && (key <= '9')))
880
		{
882
		{
881
			if (menus_active)
883
			if (menus_active)
882
				handle_menu_key(key);
884
				handle_menu_key(key);
883
			return 1;
885
			return 1;
884
		}
886
		}
885
	}
887
	}
886
 
888
 
887
	return 0; /* 0 = pass to TranslateMessage and DispatchMessage */
889
	return 0; /* 0 = pass to TranslateMessage and DispatchMessage */
888
}
890
}
889
 
891
 
890
/*
892
/*
891
 *  Return zero if there are no messages, non-zero otherwise.
893
 *  Return zero if there are no messages, non-zero otherwise.
892
 */
894
 */
893
int peekevent(void)
895
int peekevent(void)
894
{
896
{
895
	return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
897
	return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
896
}
898
}
897
 
899
 
898
/*
900
/*
899
 *  Handle one event.
901
 *  Handle one event.
900
 */
902
 */
901
int doevent(void)
903
int doevent(void)
902
{
904
{
903
	int result = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
905
	int result = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
904
 
906
 
905
	if (result)
907
	if (result)
906
	{
908
	{
907
	  /*		del_all_contexts();*/
909
	  /*		del_all_contexts();*/
908
		if (TranslateMenuKeys(&msg))
910
		if (TranslateMenuKeys(&msg))
909
			return result;
911
			return result;
910
		if ((hwndClient) &&
912
		if ((hwndClient) &&
911
			TranslateMDISysAccel(hwndClient, &msg))
913
			TranslateMDISysAccel(hwndClient, &msg))
912
			return result;
914
			return result;
913
		if ((hwndFrame) && (hAccel) &&
915
		if ((hwndFrame) && (hAccel) &&
914
			TranslateAccelerator(hwndFrame, hAccel, &msg))
916
			TranslateAccelerator(hwndFrame, hAccel, &msg))
915
			return result;
917
			return result;
916
		TranslateMessage(&msg);
918
		TranslateMessage(&msg);
917
		DispatchMessage(&msg);
919
		DispatchMessage(&msg);
918
	}
920
	}
919
	deletion_traversal();
921
	deletion_traversal();
920
	if ((active_windows <= 0) || (msg.message == WM_QUIT))
922
	if ((active_windows <= 0) || (msg.message == WM_QUIT))
921
		return 0;
923
		return 0;
922
	else
924
	else
923
		return 1;
925
		return 1;
924
}
926
}
925
 
927
 
926
/*
928
/*
927
 *  Handle events until the program has finished receiving events,
929
 *  Handle events until the program has finished receiving events,
928
 *  or until there are no windows open to receive events.
930
 *  or until there are no windows open to receive events.
929
 */
931
 */
930
void gamainloop(void)
932
void gamainloop(void)
931
{
933
{
932
	while (doevent())
934
	while (doevent())
933
		continue;
935
		continue;
934
}
936
}
935
 
937
 
936
/*
938
/*
937
 *  Finish all pending graphics requests.
939
 *  Finish all pending graphics requests.
938
 */
940
 */
939
void drawall(void)
941
void drawall(void)
940
{
942
{
941
	/* Do nothing here. */
943
	/* Do nothing here. */
942
}
944
}
943
 
945
 
944
/*
946
/*
945
 *  Initialise the timer and make some instance 'thunks' for
947
 *  Initialise the timer and make some instance 'thunks' for
946
 *  the event callbacks.
948
 *  the event callbacks.
947
 */
949
 */
948
PROTECTED
950
PROTECTED
949
void init_events(void)
951
void init_events(void)
950
{
952
{
951
	app_timer_proc = (TIMERPROC) MakeProcInstance((FARPROC) app_timer_procedure,
953
	app_timer_proc = (TIMERPROC) MakeProcInstance((FARPROC) app_timer_procedure,
952
				this_instance);
954
				this_instance);
953
	setmousetimer(100); /* start 1/10 second mouse-down auto-repeat */
955
	setmousetimer(100); /* start 1/10 second mouse-down auto-repeat */
954
 
956
 
955
	app_control_proc = (WNDPROC) MakeProcInstance((FARPROC) app_control_procedure,
957
	app_control_proc = (WNDPROC) MakeProcInstance((FARPROC) app_control_procedure,
956
				this_instance);
958
				this_instance);
957
}
959
}
958
 
960
 
959
/*
961
/*
960
 *  Stop all timers and release the memory requirements of
962
 *  Stop all timers and release the memory requirements of
961
 *  the proc instance 'thunks'.
963
 *  the proc instance 'thunks'.
962
 */
964
 */
963
PROTECTED
965
PROTECTED
964
void finish_events(void)
966
void finish_events(void)
965
{
967
{
966
	settimer(0);
968
	settimer(0);
967
	setmousetimer(0);
969
	setmousetimer(0);
968
}
970
}