1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with this library; if not, write to the Free
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/*
25     File added by Alan Buckley (alan_baa@hotmail.com) for RISC OS compatability
26	 27 March 2003
27
28     Implements Pumping of events and WIMP polling
29*/
30
31#include "SDL.h"
32#include "SDL_syswm.h"
33#include "../../events/SDL_sysevents.h"
34#include "../../events/SDL_events_c.h"
35#include "SDL_riscosvideo.h"
36#include "SDL_riscosevents_c.h"
37#include "SDL_riscosmouse_c.h"
38#include "../../timer/SDL_timer_c.h"
39
40#include "memory.h"
41#include "stdlib.h"
42#include "ctype.h"
43
44#include "kernel.h"
45#include "swis.h"
46#include "unixlib/os.h"
47
48#if !SDL_THREADS_DISABLED
49#include <pthread.h>
50#endif
51
52/* Local functions */
53void WIMP_Poll(_THIS, int waitTime);
54void WIMP_SetFocus(int win);
55
56/* SDL_riscossprite functions */
57void WIMP_PlotSprite(_THIS, int x, int y);
58void WIMP_ModeChanged(_THIS);
59void WIMP_PaletteChanged(_THIS);
60
61
62extern void WIMP_PollMouse(_THIS);
63extern void RISCOS_PollKeyboard();
64
65#if SDL_THREADS_DISABLED
66/* Timer running function */
67extern void RISCOS_CheckTimer();
68#else
69extern int riscos_using_threads;
70#endif
71
72/* Mouse cursor handling */
73extern void WIMP_ReshowCursor(_THIS);
74extern void WIMP_RestoreWimpCursor();
75
76int hasFocus = 0;
77int mouseInWindow = 0;
78
79/* Flag to ensure window is correct size after a mode change */
80static int resizeOnOpen = 0;
81
82void WIMP_PumpEvents(_THIS)
83{
84	WIMP_Poll(this, 0);
85	if (hasFocus) RISCOS_PollKeyboard();
86	if (mouseInWindow) WIMP_PollMouse(this);
87#if SDL_THREADS_DISABLED
88	if (SDL_timer_running) RISCOS_CheckTimer();
89#endif
90}
91
92
93void WIMP_Poll(_THIS, int waitTime)
94{
95	_kernel_swi_regs regs;
96	int message[64];
97	unsigned int code;
98	int pollMask = 0;
99	int doPoll = 1;
100	int sysEvent;
101	int sdlWindow = this->hidden->window_handle;
102
103    if (this->PumpEvents != WIMP_PumpEvents) return;
104
105    if (waitTime > 0)
106    {
107		_kernel_swi(OS_ReadMonotonicTime, &regs, &regs);
108		waitTime += regs.r[0];
109    }
110
111    while (doPoll)
112    {
113#if !SDL_THREADS_DISABLED
114       /* Stop thread callbacks while program is paged out */
115       if (riscos_using_threads) __pthread_stop_ticker();
116#endif
117
118        if (waitTime <= 0)
119        {
120        	regs.r[0] = pollMask; /* Poll Mask */
121        	/* For no wait time mask out null event so we wait until something happens */
122        	if (waitTime < 0) regs.r[0] |= 1;
123        	regs.r[1] = (int)message;
124        	_kernel_swi(Wimp_Poll, &regs, &regs);
125        } else
126        {
127        	regs.r[0] = pollMask;
128        	regs.r[1] = (int)message;
129        	regs.r[2] = waitTime;
130        	_kernel_swi(Wimp_PollIdle, &regs, &regs);
131        }
132
133		/* Flag to specify if we post a SDL_SysWMEvent */
134	sysEvent = 0;
135
136        code = (unsigned int)regs.r[0];
137
138	switch(code)
139	{
140        case 0:  /* Null Event - drop out for standard processing*/
141	   doPoll = 0;
142	   break;
143
144	case 1:     /* Redraw window */
145           _kernel_swi(Wimp_RedrawWindow, &regs,&regs);
146	   if (message[0] == sdlWindow)
147	   {
148                 while (regs.r[0])
149                 {
150           	    WIMP_PlotSprite(this, message[1], message[2]);
151           	    _kernel_swi(Wimp_GetRectangle, &regs, &regs);
152                 }
153	   } else
154	  {
155	/* TODO: Currently we just eat them - we may need to pass them on */
156        	while (regs.r[0])
157        	{
158                        _kernel_swi(Wimp_GetRectangle, &regs, &regs);
159        	}
160	  }
161          break;
162
163		case 2:		/* Open window */
164		   if ( resizeOnOpen && message[0] == sdlWindow)
165		   {
166		      /* Ensure window is correct size */
167		      resizeOnOpen = 0;
168		      message[3] = message[1] + (this->screen->w << this->hidden->xeig);
169		      message[4] = message[2] + (this->screen->h << this->hidden->yeig);
170		   }
171        	_kernel_swi(Wimp_OpenWindow, &regs, &regs);
172       	    break;
173
174		case 3:		/* Close window */
175			if (message[0] == sdlWindow)
176			{
177				/* Documentation makes it looks as if the following line is correct:
178				**    if (SDL_PrivateQuit() == 1) _kernel_swi(Wimp_CloseWindow, &regs, &regs);
179				** However some programs don't process this message and so sit there invisibly
180				** in the background so I just post the quit message and hope the application
181				** does the correct thing.
182				*/
183				SDL_PrivateQuit();
184			} else
185				sysEvent = 1;
186        	doPoll = 0;
187        	break;
188
189		case 4: /* Pointer_Leaving_Window */
190			if (message[0] == sdlWindow)
191			{
192				mouseInWindow = 0;
193				//TODO: Lose buttons / dragging
194				 /* Reset to default pointer */
195				 WIMP_RestoreWimpCursor();
196				 SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
197			} else
198				sysEvent = 1;
199			break;
200
201		case 5: /* Pointer_Entering_Window */
202			if (message[0] == sdlWindow)
203			{
204				mouseInWindow = 1;
205				WIMP_ReshowCursor(this);
206				SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
207			} else sysEvent = 1;
208			break;
209
210		case 6:		/* Mouse_Click */
211			if (hasFocus == 0)
212			{
213			   /* First click gives focus if it's not a menu */
214			   /* we only count non-menu clicks on a window that has the focus */
215			   WIMP_SetFocus(message[3]);
216			} else
217				doPoll = 0; // So PollMouse gets a chance to pick it up
218		   break;
219
220		case 7: /* User_Drag_Box - Used for mouse release */
221			//TODO: May need to implement this in the future
222			sysEvent = 1;
223			break;
224
225		case 8: /* Keypressed */
226			doPoll = 0; /* PollKeyboard should pick it up */
227			if (message[0] != sdlWindow) sysEvent = 1;
228			/*TODO: May want to always pass F12 etc to the wimp
229			{
230				regs.r[0] = message[6];
231				_kernel_swi(Wimp_ProcessKey, &regs, &regs);
232			}
233			*/
234			break;
235
236		case 11: /* Lose Caret */
237			 hasFocus = 0;
238			 if (message[0] == sdlWindow) SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
239			 else sysEvent = 1;
240			 break;
241
242		case 12: /* Gain Caret */
243			 hasFocus = 1;
244			 if (message[0] == sdlWindow) SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
245			 else sysEvent = 1;
246			 break;
247
248		case 17:
249		case 18:
250			sysEvent = 1; /* All messages are passed on */
251
252			switch(message[4])
253			{
254			case 0: /* Quit Event */
255				/* No choice - have to quit */
256			   SDL_Quit();
257        	   exit(0);
258			   break;
259
260			case 8: /* Pre Quit */
261				SDL_PrivateQuit();
262				break;
263
264			case 0x400c1: /* Mode change */
265				WIMP_ModeChanged(this);
266				resizeOnOpen = 1;
267				break;
268
269			case 9:      /* Palette changed */
270				WIMP_PaletteChanged(this);
271				break;
272			}
273			break;
274
275		default:
276			/* Pass unknown events on */
277			sysEvent = 1;
278			break;
279		}
280
281		if (sysEvent)
282		{
283	        SDL_SysWMmsg wmmsg;
284
285			SDL_VERSION(&wmmsg.version);
286			wmmsg.eventCode = code;
287			SDL_memcpy(wmmsg.pollBlock, message, 64 * sizeof(int));
288
289			/* Fall out of polling loop if message is successfully posted */
290			if (SDL_PrivateSysWMEvent(&wmmsg)) doPoll = 0;
291		}
292#if !SDL_THREADS_DISABLED
293		if (riscos_using_threads)
294		{
295                   /* Restart ticker here so other thread can not interfere
296                      with the Redraw processing */
297		   if (riscos_using_threads) __pthread_start_ticker();
298                   /* Give other threads a better chance of running */
299		   pthread_yield();
300		}
301#endif
302    }
303}
304
305/* Set focus to specified window */
306void WIMP_SetFocus(int win)
307{
308	_kernel_swi_regs regs;
309
310	regs.r[0] = win;
311	regs.r[1] = -1; /* Icon handle */
312	regs.r[2] = 0;  /* X-offset we just put it at position 0 */
313	regs.r[3] = 0;  /* Y-offset as above */
314	regs.r[4] = 1 << 25; /* Caret is invisible */
315	regs.r[5] = 0;  /* index into string */
316
317	_kernel_swi(Wimp_SetCaretPosition, &regs, &regs);
318}
319
320/** Run background task while in a sleep command */
321void RISCOS_BackgroundTasks(void)
322{
323	if (current_video && current_video->hidden->window_handle)
324	{
325		WIMP_Poll(current_video, 0);
326	}
327#if SDL_THREADS_DISABLED
328	if (SDL_timer_running) RISCOS_CheckTimer();
329#endif
330}
331