Contiki 3.x
program-handler.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003, Adam Dunkels.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following
12  * disclaimer in the documentation and/or other materials provided
13  * with the distribution.
14  * 3. The name of the author may not be used to endorse or promote
15  * products derived from this software without specific prior
16  * written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * This file is part of the Contiki desktop OS
31  *
32  *
33  */
34 
35 /**
36  * \file
37  * The program handler, used for loading programs and starting the
38  * screensaver.
39  * \author Adam Dunkels <adam@dunkels.com>
40  *
41  * The Contiki program handler is responsible for the Contiki menu and
42  * the desktop icons, as well as for loading programs and displaying a
43  * dialog with a message telling which program that is loading.
44  *
45  * The program handler also is responsible for starting the
46  * screensaver when the CTK detects that it should be started.
47  */
48 
49 #include <string.h>
50 #include <stdlib.h>
51 
52 #include "contiki.h"
53 #include "ctk/ctk.h"
54 #include "ctk/ctk-draw.h"
55 #include "sys/log.h"
56 
57 #include "program-handler.h"
58 
59 
60 /* Menus */
61 static struct ctk_menu contikimenu = {NULL, "Contiki", 7, 0, 0};
62 
63 #ifndef PROGRAM_HANDLER_CONF_MAX_NUMDSCS
64 #define MAX_NUMDSCS 10
65 #else /* PROGRAM_HANDLER_CONF_MAX_NUMDSCS */
66 #define MAX_NUMDSCS PROGRAM_HANDLER_CONF_MAX_NUMDSCS
67 #endif /* PROGRAM_HANDLER_CONF_MAX_NUMDSCS */
68 
69 static struct dsc *contikidsc[MAX_NUMDSCS];
70 static unsigned char contikidsclast = 0;
71 
72 #ifndef PROGRAM_HANDLER_CONF_QUIT_MENU
73 #define QUIT_MENU 0
74 #else /* PROGRAM_HANDLER_CONF_QUIT_MENU */
75 #define QUIT_MENU PROGRAM_HANDLER_CONF_QUIT_MENU
76 #endif /* PROGRAM_HANDLER_CONF_QUIT_MENU */
77 
78 #if QUIT_MENU
79 
80 static unsigned char quitmenuitem;
81 
82 /* "Quit" dialog */
83 static struct ctk_window quitdialog;
84 static struct ctk_label quitdialoglabel =
85  {CTK_LABEL(2, 1, 20, 1, "Really quit Contiki?")};
86 static struct ctk_button quityesbutton =
87  {CTK_BUTTON(4, 3, 3, "Yes")};
88 static struct ctk_button quitnobutton =
89  {CTK_BUTTON(16, 3, 2, "No")};
90 
91 #endif /* QUIT_MENU */
92 
93 #if WITH_LOADER_ARCH
94 
95 /* "Run..." window */
96 static struct ctk_window runwindow;
97 static unsigned char runmenuitem;
98 static struct ctk_label namelabel =
99  {CTK_LABEL(0, 0, 13, 1, "Program name:")};
100 static char name[31];
101 static struct ctk_textentry nameentry =
102  {CTK_TEXTENTRY(0, 1, 14, 1, name, 30)};
103 static struct ctk_button loadbutton =
104  {CTK_BUTTON(10, 2, 4, "Load")};
105 
106 static struct ctk_window loadingdialog;
107 static struct ctk_label loadingmsg =
108  {CTK_LABEL(0, 0, 8, 1, "Starting")};
109 static struct ctk_label loadingname =
110  {CTK_LABEL(9, 0, 16, 1, name)};
111 
112 static struct ctk_window errordialog;
113 static struct ctk_label errormsg =
114  {CTK_LABEL(0, 1, 22, 1, "Error loading program:")};
115 static char errorfilename[22];
116 static struct ctk_label errorfilelabel =
117  {CTK_LABEL(0, 3, 22, 1, errorfilename)};
118 static struct ctk_label errortype =
119  {CTK_LABEL(4, 5, 16, 1, "")};
120 static struct ctk_button errorokbutton =
121  {CTK_BUTTON(9, 7, 2, "Ok")};
122 
123 static const char * const errormsgs[] = {
124  "Ok",
125  "Read error",
126  "Header error",
127  "OS error",
128  "Data format error",
129  "Out of memory",
130  "File not found",
131  "No loader"
132 };
133 
134 #endif /* WITH_LOADER_ARCH */
135 
136 #define LOADER_EVENT_LOAD 1
137 #define LOADER_EVENT_DISPLAY_NAME 2
138 
139 PROCESS(program_handler_process, "Program handler");
140 
141 AUTOSTART_PROCESSES(&program_handler_process);
142 
143 static char *displayname;
144 
145 #if CTK_CONF_SCREENSAVER
146 char program_handler_screensaver[20];
147 #endif /* CTK_CONF_SCREENSAVER */
148 
149 /*-----------------------------------------------------------------------------------*/
150 /**
151  * Add a program to the program handler.
152  *
153  * \param dsc The DSC description structure for the program to be added.
154  *
155  * \param menuname The name that the program should have in the
156  * Contiki menu.
157  *
158  * \param desktop Flag which specifies if the program should show up
159  * as an icon on the desktop or not.
160  */
161 /*-----------------------------------------------------------------------------------*/
162 void
163 program_handler_add(struct dsc *dsc, char *menuname,
164  unsigned char desktop)
165 {
166  contikidsc[contikidsclast++] = dsc;
167  ctk_menuitem_add(&contikimenu, menuname);
168  if(desktop) {
169 #if CTK_CONF_ICONS
170  CTK_ICON_ADD(dsc->icon, &program_handler_process);
171 #endif /* CTK_CONF_ICONS */
172  }
173 }
174 /*-----------------------------------------------------------------------------------*/
175 /**
176  * Initializes the program handler.
177  *
178  * Is called by the initialization before any programs have been added
179  * with program_handler_add().
180  *
181  */
182 /*-----------------------------------------------------------------------------------*/
183 #ifdef WITH_LOADER_ARCH
184 #define NUM_PNARGS 6
185 #define NAMELEN 32
186 struct pnarg {
187  char name[NAMELEN];
188  char *arg;
189 };
190 static struct pnarg pnargs[NUM_PNARGS];
191 static struct pnarg *
192 pnarg_copy(char *name, char *arg)
193 {
194  char i;
195  struct pnarg *pnargsptr;
196 
197  pnargsptr = pnargs;
198  /* Allocate a place in the loadernames table. */
199  for(i = 0; i < NUM_PNARGS; ++i) {
200  if(*(pnargsptr->name) == 0) {
201  strncpy(pnargsptr->name, name, NAMELEN);
202  pnargsptr->arg = arg;
203  return pnargsptr;
204  }
205  ++pnargsptr;
206  }
207  return NULL;
208 }
209 
210 static void
211 pnarg_free(struct pnarg *pn)
212 {
213  *(pn->name) = 0;
214 }
215 #endif /* WITH_LOADER_ARCH */
216 /*-----------------------------------------------------------------------------------*/
217 /**
218  * Loads a program and displays a dialog telling the user about it.
219  *
220  * \param name The name of the program to be loaded.
221  *
222  * \param arg An argument which is passed to the new process when it
223  * is loaded.
224  */
225 /*-----------------------------------------------------------------------------------*/
226 void
227 program_handler_load(char *name, char *arg)
228 {
229 #ifdef WITH_LOADER_ARCH
230  struct pnarg *pnarg;
231 
232  pnarg = pnarg_copy(name, arg);
233  if(pnarg != NULL) {
234  process_post(&program_handler_process, LOADER_EVENT_DISPLAY_NAME, pnarg);
235  } else {
236  ctk_label_set_text(&errortype, "Out of memory");
237  ctk_dialog_open(&errordialog);
238  }
239  /* ctk_redraw(); */
240  /* ctk_window_redraw(&loadingdialog);*/
241 #endif /* WITH_LOADER_ARCH */
242 }
243 
244 #ifdef WITH_LOADER_ARCH
245 #define RUN(prg, name, arg) program_handler_load(prg, arg)
246 #else /* WITH_LOADER_ARCH */
247 #define RUN(prg, process, arg) process_start(process, arg)
248 #endif /* WITH_LOADER_ARCH */
249 /*-----------------------------------------------------------------------------------*/
250 /**
251  * Configures the name of the screensaver to be loaded when
252  * appropriate.
253  *
254  * \param name The name of the screensaver or NULL if no screensaver
255  * should be used.
256  */
257 /*-----------------------------------------------------------------------------------*/
258 #if CTK_CONF_SCREENSAVER
259 void
260 program_handler_setscreensaver(char *name)
261 {
262  if(name == NULL) {
263  program_handler_screensaver[0] = 0;
264  } else {
265  strncpy(program_handler_screensaver, name, sizeof(program_handler_screensaver));
266  }
267 }
268 #endif /* CTK_CONF_SCREENSAVER */
269 /*-----------------------------------------------------------------------------------*/
270 #ifdef WITH_LOADER_ARCH
271 static void
272 make_windows(void)
273 {
274  ctk_window_new(&runwindow, 16, 3, "Run");
275 
276  CTK_WIDGET_ADD(&runwindow, &namelabel);
277  CTK_WIDGET_ADD(&runwindow, &nameentry);
278  CTK_WIDGET_ADD(&runwindow, &loadbutton);
279 
280  CTK_WIDGET_FOCUS(&runwindow, &nameentry);
281 
282  ctk_dialog_new(&loadingdialog, 25, 1);
283  CTK_WIDGET_ADD(&loadingdialog, &loadingmsg);
284  CTK_WIDGET_ADD(&loadingdialog, &loadingname);
285 
286  ctk_dialog_new(&errordialog, 22, 8);
287  CTK_WIDGET_ADD(&errordialog, &errormsg);
288  CTK_WIDGET_ADD(&errordialog, &errorfilelabel);
289  CTK_WIDGET_ADD(&errordialog, &errortype);
290  CTK_WIDGET_ADD(&errordialog, &errorokbutton);
291  CTK_WIDGET_FOCUS(&errordialog, &errorokbutton);
292 }
293 #endif /* WITH_LOADER_ARCH */
294 /*-----------------------------------------------------------------------------------*/
295 PROCESS_THREAD(program_handler_process, ev, data)
296 {
297 #ifdef WITH_LOADER_ARCH
298  unsigned char err;
299  struct dsc *dsc;
300 #endif /* WITH_LOADER_ARCH */
301  unsigned char i;
302  struct dsc **dscp;
303 
304  PROCESS_BEGIN();
305 
306  /* Create the menus */
307  ctk_menu_add(&contikimenu);
308 #if WITH_LOADER_ARCH
309  runmenuitem = ctk_menuitem_add(&contikimenu, "Run program...");
310 
311  make_windows();
312 #endif /* WITH_LOADER_ARCH */
313 #if QUIT_MENU
314  quitmenuitem = ctk_menuitem_add(&contikimenu, "Quit");
315 #endif /* QUIT_MENU */
316 
317  displayname = NULL;
318 
319 #if CTK_CONF_SCREENSAVER
320  program_handler_screensaver[0] = 0;
321 #endif /* CTK_CONF_SCREENSAVER */
322 
323  while(1) {
325  if(ev == ctk_signal_button_activate) {
326 #ifdef WITH_LOADER_ARCH
327  if(data == (process_data_t)&loadbutton) {
328  ctk_window_close(&runwindow);
329  program_handler_load(name, NULL);
330  } else if(data == (process_data_t)&errorokbutton) {
331  ctk_dialog_close();
332  }
333 #endif /* WITH_LOADER_ARCH */
334 #if QUIT_MENU
335  if(data == (process_data_t)&quityesbutton) {
336  ctk_draw_init();
337  exit(EXIT_SUCCESS);
338  } else if(data == (process_data_t)&quitnobutton) {
339  ctk_dialog_close();
340  }
341 #endif /* QUIT_MENU */
342  dscp = &contikidsc[0];
343  for(i = 0; i < CTK_MAXMENUITEMS; ++i) {
344  if(*dscp != NULL
345 #if CTK_CONF_ICONS
346  && data == (process_data_t)(*dscp)->icon
347 #endif /* CTK_CONF_ICONS */
348  ) {
349  RUN((*dscp)->prgname, (*dscp)->process, NULL);
350  break;
351  }
352  ++dscp;
353  }
354  } else if(ev == ctk_signal_menu_activate) {
355  if((struct ctk_menu *)data == &contikimenu) {
356 #if WITH_LOADER_ARCH
357  dsc = contikidsc[contikimenu.active];
358  if(dsc != NULL) {
359  RUN(dsc->prgname, dsc->process, NULL);
360  } else if(contikimenu.active == runmenuitem) {
361  make_windows();
362  ctk_window_close(&runwindow);
363  ctk_window_open(&runwindow);
364  CTK_WIDGET_FOCUS(&runwindow, &nameentry);
365  }
366 #else /* WITH_LOADER_ARCH */
367  if(contikidsc[contikimenu.active] != NULL) {
368  RUN(contikidsc[contikimenu.active]->prgname,
369  contikidsc[contikimenu.active]->process,
370  NULL);
371  }
372 #endif /* WITH_LOADER_ARCH */
373 #if QUIT_MENU
374  if(contikimenu.active == quitmenuitem) {
375  ctk_dialog_new(&quitdialog, 24, 5);
376  CTK_WIDGET_ADD(&quitdialog, &quitdialoglabel);
377  CTK_WIDGET_ADD(&quitdialog, &quityesbutton);
378  CTK_WIDGET_ADD(&quitdialog, &quitnobutton);
379  CTK_WIDGET_FOCUS(&quitdialog, &quitnobutton);
380  ctk_dialog_open(&quitdialog);
381  }
382 #endif /* QUIT_MENU */
383  }
384 #if CTK_CONF_SCREENSAVER
385  } else if(ev == ctk_signal_screensaver_start) {
386 #if WITH_LOADER_ARCH
387  if(program_handler_screensaver[0] != 0) {
388  program_handler_load(program_handler_screensaver, NULL);
389  }
390 #endif /* WITH_LOADER_ARCH */
391 #endif /* CTK_CONF_SCREENSAVER */
392  } else if(ev == LOADER_EVENT_DISPLAY_NAME) {
393 #if WITH_LOADER_ARCH
394  if(displayname == NULL) {
395  make_windows();
396 
397  ctk_label_set_text(&loadingname, ((struct pnarg *)data)->name);
398  ctk_dialog_open(&loadingdialog);
399  process_post(&program_handler_process, LOADER_EVENT_LOAD, data);
400  displayname = data;
401  } else {
402  /* Try again. */
403  process_post(&program_handler_process, LOADER_EVENT_DISPLAY_NAME, data);
404  }
405 #endif /* WITH_LOADER_ARCH */
406  } else if(ev == LOADER_EVENT_LOAD) {
407 #if WITH_LOADER_ARCH
408  if(displayname == data) {
409  ctk_dialog_close();
410  displayname = NULL;
411  log_message("Loading ", ((struct pnarg *)data)->name);
412  err = LOADER_LOAD(((struct pnarg *)data)->name,
413  ((struct pnarg *)data)->arg);
414  if(err != LOADER_OK) {
415  make_windows();
416  errorfilename[0] = '"';
417  strncpy(errorfilename + 1, ((struct pnarg *)data)->name,
418  sizeof(errorfilename) - 2);
419  errorfilename[1 + strlen(((struct pnarg *)data)->name)] = '"';
420  ctk_label_set_text(&errortype, (char *)errormsgs[err]);
421  ctk_dialog_open(&errordialog);
422  log_message((char *)errormsgs[err], errorfilename);
423  }
424  pnarg_free(data);
425  } else {
426  /* Try again. */
427  process_post(&program_handler_process, LOADER_EVENT_DISPLAY_NAME, data);
428  }
429 #endif /* WITH_LOADEER_ARCH */
430  }
431  }
432  PROCESS_END();
433 }
434 /*-----------------------------------------------------------------------------------*/
#define CTK_WIDGET_ADD(win, widg)
Add a widget to a window.
Definition: ctk.h:752
process_event_t ctk_signal_button_activate
Same as ctk_signal_widget_activate.
Definition: ctk.c:126
unsigned char ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu, char *name)
Adds a menu item to a menu.
Definition: ctk.c:800
void ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
Open a window, or bring window to front if already open.
Definition: ctk.c:347
#define NUM_PNARGS
Initializes the program handler.
#define CTK_WIDGET_FOCUS(win, widg)
Set focus to a widget.
Definition: ctk.h:763
void ctk_window_close(struct ctk_window *w)
Close a window if it is open.
Definition: ctk.c:400
unsigned char active
The currently active menu item.
Definition: ctk.h:601
#define LOADER_OK
No error.
Definition: loader.h:60
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
void ctk_menu_add(struct ctk_menu *menu)
Add a menu to the menu bar.
Definition: ctk.c:504
#define CTK_TEXTENTRY(x, y, w, h, text, len)
Instantiating macro for the ctk_textentry widget.
Definition: ctk.h:275
#define ctk_label_set_text(l, t)
Set the text of a label.
Definition: ctk.h:849
#define NULL
The null pointer.
process_event_t ctk_signal_menu_activate
Emitted when a menu item is activated.
Definition: ctk.c:151
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
#define CTK_LABEL(x, y, w, h, text)
Instantiating macro for the ctk_label widget.
Definition: ctk.h:171
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
The DSC program description structure.
Definition: dsc.h:75
void program_handler_add(struct dsc *dsc, char *menuname, unsigned char desktop)
Add a program to the program handler.
void ctk_window_new(struct ctk_window *window, unsigned char w, unsigned char h, char *title)
Create a new window.
Definition: ctk.c:732
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
CTK screen drawing module interface, ctk-draw.
Representation of an individual menu.
Definition: ctk.h:586
#define CTK_BUTTON(x, y, w, text)
Instantiating macro for the ctk_button widget.
Definition: ctk.h:140
void ctk_draw_init(void)
The initialization function.
Definition: ctk-conio.c:74
Representation of a CTK window.
Definition: ctk.h:506
char * prgname
The name of the program on disk.
Definition: dsc.h:80
#define LOADER_LOAD(name, arg)
Load and execute a program.
Definition: loader.h:92
void program_handler_load(char *name, char *arg)
Loads a program and displays a dialog telling the user about it.
CTK header file.
#define CTK_ICON_ADD(icon, p)
Add an icon to the desktop.
Definition: ctk.h:741