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    This file added by Alan Buckley (alan_baa@hotmail.com) to support RISC OS
26	26 March 2003
27
28	File includes routines for:
29	  Setting up as a WIMP Task
30	  Reading information about the current desktop
31	  Storing information before a switch to full screen
32	  Restoring desktop after switching to full screen
33*/
34
35#include "kernel.h"
36#include "swis.h"
37
38#include "SDL_stdinc.h"
39#include "SDL_riscostask.h"
40
41#if !SDL_THREADS_DISABLED
42#include <pthread.h>
43pthread_t main_thread;
44#endif
45
46/* RISC OS variables */
47
48static int task_handle = 0;
49static int wimp_version = 0;
50
51/* RISC OS variables to help compatability with certain programs */
52int riscos_backbuffer = 0; /* Create a back buffer in system memory for full screen mode */
53int riscos_closeaction = 1; /* Close icon action */
54
55static int stored_mode = -1; /* -1 when in desktop, mode number or pointer when full screen */
56
57extern int mouseInWindow; /* Mouse is in WIMP window */
58
59/* Local function */
60
61static int RISCOS_GetTaskName(char *task_name, size_t maxlen);
62
63/* Uncomment next line to copy mode changes/restores to stderr */
64/* #define DUMP_MODE */
65#ifdef DUMP_MODE
66#include "stdio.h"
67static void dump_mode()
68{
69    fprintf(stderr, "mode %d\n", stored_mode);
70    if (stored_mode < -1 || stored_mode >= 256)
71    {
72        int blockSize = 0;
73		int *storeBlock = (int *)stored_mode;
74
75        while(blockSize < 5 || storeBlock[blockSize] != -1)
76        {
77           fprintf(stderr, "   %d\n", storeBlock[blockSize++]);
78        }
79    }
80}
81#endif
82
83/******************************************************************
84
85 Initialise as RISC OS Wimp task
86
87*******************************************************************/
88
89int RISCOS_InitTask()
90{
91   char task_name[32];
92   _kernel_swi_regs regs;
93   int messages[4];
94
95   if (RISCOS_GetTaskName(task_name, SDL_arraysize(task_name)) == 0) return 0;
96
97   messages[0] = 9;       /* Palette changed */
98   messages[1] = 0x400c1; /* Mode changed */
99   messages[2] = 8;       /* Pre quit */
100   messages[2] = 0;
101
102	regs.r[0] = (unsigned int)360; /* Minimum version 3.6 */
103	regs.r[1] = (unsigned int)0x4b534154;
104	regs.r[2] = (unsigned int)task_name;
105	regs.r[3] = (unsigned int)messages;
106
107   if (_kernel_swi(Wimp_Initialise, &regs, &regs) == 0)
108   {
109	   wimp_version = regs.r[0];
110	   task_handle = regs.r[1];
111	   return 1;
112   }
113
114#if !SDL_THREADS_DISABLED
115   main_thread = pthread_self();
116#endif
117
118   return 0;
119}
120
121/*********************************************************************
122
123  Close down application on exit.
124
125**********************************************************************/
126
127void RISCOS_ExitTask()
128{
129	_kernel_swi_regs regs;
130
131    if (stored_mode == -1)
132    {
133       /* Ensure cursor is put back to standard pointer shape if
134          we have been running in a window */
135       _kernel_osbyte(106,1,0);
136    }
137
138	/* Ensure we end up back in the wimp */
139	RISCOS_RestoreWimpMode();
140
141	/* Neatly exit the task */
142   	regs.r[0] = task_handle;
143   	regs.r[1] = (unsigned int)0x4b534154;
144   	_kernel_swi(Wimp_CloseDown, &regs, &regs);
145	task_handle = 0;
146}
147
148/**************************************************************************
149
150  Get the name of the task for the desktop.
151
152  Param:   task_name - name of task 32 characters.
153
154  Returns: 1 is successful, otherwise 0
155
156  Notes:   Works by getting using OS_GetEnv to get the command line
157		   used to run the program and then parsing a name from it
158		   as follows.
159
160		   1. Use name after final period if not !RunImage
161		   2. If name is !RunImage then process item before the period
162		      in front of !RunImage.
163		   3. If directory name use that
164		   4. if in form <XXX$Dir> use the XXX.
165
166		   Finally once this value has been retrieved use it unless
167		   there is a variable set up in the form SDL$<name>$TaskName
168		   in which case the value of this variable will be used.
169
170		   Now also gets other RISC OS configuration varibles
171                SDL$<name>$BackBuffer - set to 1 to use a system memory backbuffer in fullscreen mode
172						    so updates wait until a call to SDL_UpdateRects. (default 0)
173						    This is required for programmes where they have assumed this is
174						    always the case which is contrary to the documentation.
175               SDL$<name>$CloseAction
176                    0 Don't show close icon
177                    1 Show close icon
178
179***************************************************************************/
180
181int RISCOS_GetTaskName(char *task_name, size_t maxlen)
182{
183	_kernel_swi_regs regs;
184
185   task_name[0] = 0;
186
187   /* Figure out a sensible task name */
188   if (_kernel_swi(OS_GetEnv, &regs, &regs) == 0)
189   {
190	   char *command_line = (char *)regs.r[0];
191	   size_t len = SDL_strlen(command_line)+1;
192	   char *buffer = SDL_stack_alloc(char, len);
193	   char *env_var;
194	   char *p;
195
196	   SDL_strlcpy(buffer, command_line, len);
197	   p = SDL_strchr(buffer, ' ');
198	   if (p) *p = 0;
199	   p = SDL_strrchr(buffer, '.');
200	   if (p == 0) p = buffer;
201	   if (stricmp(p+1,"!RunImage") == 0)
202	   {
203		   *p = 0;
204	   	   p = SDL_strrchr(buffer, '.');
205		   if (p == 0) p = buffer;
206	   }
207	   if (*p == '.') p++;
208	   if (*p == '!') p++; /* Skip "!" at beginning of application directories */
209
210       if (*p == '<')
211       {
212          // Probably in the form <appname$Dir>
213          char *q = SDL_strchr(p, '$');
214          if (q == 0) q = SDL_strchr(p,'>'); /* Use variable name if not */
215          if (q) *q = 0;
216          p++; /* Move over the < */
217       }
218
219	   if (*p)
220	   {
221		   /* Read variables that effect the RISC OS SDL engine for this task */
222		   len = SDL_strlen(p) + 18; /* 18 is larger than the biggest variable name */
223		   env_var = SDL_stack_alloc(char, len);
224		   if (env_var)
225		   {
226			   char *env_val;
227
228			   /* See if a variable of form SDL$<dirname>$TaskName exists */
229
230			   SDL_strlcpy(env_var, "SDL$", len);
231			   SDL_strlcat(env_var, p, len);
232			   SDL_strlcat(env_var, "$TaskName", len);
233
234			   env_val = SDL_getenv(env_var);
235			   if (env_val) SDL_strlcpy(task_name, env_val, maxlen);
236
237			   SDL_strlcpy(env_var, "SDL$", len);
238			   SDL_strlcat(env_var, p, len);
239			   SDL_strlcat(env_var, "$BackBuffer", len);
240
241			   env_val = SDL_getenv(env_var);
242			   if (env_val) riscos_backbuffer = atoi(env_val);
243
244			   SDL_strlcpy(env_var, "SDL$", len);
245			   SDL_strlcat(env_var, p, len);
246			   SDL_strlcat(env_var, "$CloseAction", len);
247
248			   env_val = SDL_getenv(env_var);
249			   if (env_val && SDL_strcmp(env_val,"0") == 0) riscos_closeaction = 0;
250
251			   SDL_stack_free(env_var);
252		   }
253
254		   if (!*task_name) SDL_strlcpy(task_name, p, maxlen);
255	   }
256
257	   SDL_stack_free(buffer);
258   }
259
260   if (task_name[0] == 0) SDL_strlcpy(task_name, "SDL Task", maxlen);
261
262   return 1;
263}
264
265/*****************************************************************
266
267  Store the current desktop screen mode if we are in the desktop.
268
269******************************************************************/
270
271void RISCOS_StoreWimpMode()
272{
273     _kernel_swi_regs regs;
274
275	/* Don't store if in full screen mode */
276	if (stored_mode != -1) return;
277
278    regs.r[0] = 1;
279    _kernel_swi(OS_ScreenMode, &regs, &regs);
280    if (regs.r[1] >= 0 && regs.r[1] < 256) stored_mode = regs.r[1];
281    else
282    {
283        int blockSize = 0;
284        int *retBlock = (int *)regs.r[1];
285		int *storeBlock;
286        int j;
287
288        while(blockSize < 5 || retBlock[blockSize] != -1) blockSize++;
289        blockSize++;
290        storeBlock = (int *)SDL_malloc(blockSize * sizeof(int));
291        retBlock = (int *)regs.r[1];
292        for ( j = 0; j < blockSize; j++)
293           storeBlock[j] = retBlock[j];
294
295		stored_mode = (int)storeBlock;
296     }
297#if DUMP_MODE
298    fprintf(stderr, "Stored "); dump_mode();
299#endif
300}
301
302/*****************************************************************
303
304  Restore desktop screen mode if we are in full screen mode.
305
306*****************************************************************/
307
308void RISCOS_RestoreWimpMode()
309{
310    _kernel_swi_regs regs;
311
312	/* Only need to restore if we are in full screen mode */
313	if (stored_mode == -1) return;
314
315#if DUMP_MODE
316   fprintf(stderr, "Restored"); dump_mode();
317#endif
318
319    regs.r[0] = stored_mode;
320    _kernel_swi(Wimp_SetMode, &regs, &regs);
321    if (stored_mode < 0 || stored_mode > 256)
322    {
323       SDL_free((int *)stored_mode);
324    }
325    stored_mode = -1;
326
327    /* Flush keyboard buffer to dump the keystrokes we've already polled */
328    regs.r[0] = 21;
329    regs.r[1] = 0; /* Keyboard buffer number */
330    _kernel_swi(OS_Byte, &regs, &regs);
331
332    mouseInWindow = 0;
333
334}
335
336/*********************************************************************
337
338  Get version of Wimp running when task was initialised.
339
340*********************************************************************/
341
342int RISCOS_GetWimpVersion()
343{
344	return wimp_version;
345}
346
347int RISCOS_GetTaskHandle()
348{
349	return task_handle;
350}
351